Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
HakanL committed Dec 12, 2024
1 parent f3a6f85 commit 0bd15d2
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 83 deletions.
6 changes: 1 addition & 5 deletions example/Haukcode.sACN.ConsoleExample.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -7,10 +7,6 @@
<AssemblyName>ConsoleExample</AssemblyName>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Haukcode.Network" Version="1.0.10" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\Haukcode.sACN\Haukcode.sACN.csproj" />
</ItemGroup>
Expand Down
7 changes: 5 additions & 2 deletions example/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Net;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Channels;

namespace Haukcode.sACN.ConsoleExample
{
Expand All @@ -28,7 +29,7 @@ static void Listen()
var sendClient = new SACNClient(
senderId: acnSourceId,
senderName: acnSourceName,
localAddress: Haukcode.Network.Helper.GetFirstBindAddress().IPAddress);
localAddress: Haukcode.Network.Utils.GetFirstBindAddress().IPAddress);

recvClient.OnError.Subscribe(e =>
{
Expand All @@ -47,7 +48,9 @@ static void Listen()
last = d.TimestampMS;
});

recvClient.StartReceive();
var channel = Channel.CreateUnbounded<SACNPacket>();

recvClient.StartRecordPipeline(channel, x => x.Packet);
recvClient.JoinDMXUniverse(1);
recvClient.JoinDMXUniverse(2);

Expand Down
2 changes: 1 addition & 1 deletion src/Haukcode.sACN/Haukcode.sACN.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Haukcode.Network" Version="1.0.12" />
<PackageReference Include="Haukcode.Network" Version="1.0.16" />
<PackageReference Include="HdrHistogram" Version="2.5.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
Expand Down
97 changes: 38 additions & 59 deletions src/Haukcode.sACN/SACNClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,33 @@ public class SendData : HighPerfComm.SendData
{
public ushort UniverseId { get; set; }

public IPEndPoint? Destination { get; set; }
public IPEndPoint Destination { get; set; }

public SendData(ushort universeId, IPEndPoint destination)
{
UniverseId = universeId;
Destination = destination;
}
}

public const int DefaultPort = 5568;
public const int ReceiveBufferSize = 680 * 20 * 200;
private const int SendBufferSize = 680 * 20 * 200;
private static readonly IPEndPoint _blankEndpoint = new(IPAddress.Any, 0);

private Socket? listenSocket;
private readonly Socket sendSocket;
private readonly IPEndPoint localEndPoint;
private readonly ISubject<ReceiveDataPacket> packetSubject;
private readonly Dictionary<ushort, byte> sequenceIds = [];
private readonly Dictionary<ushort, byte> sequenceIdsSync = [];
private readonly object lockObject = new();
private readonly Lock lockObject = new();
private readonly HashSet<ushort> dmxUniverses = [];
private readonly Dictionary<IPAddress, (IPEndPoint EndPoint, bool Multicast)> endPointCache = [];
private readonly IPEndPoint localEndPoint;
private readonly Dictionary<ushort, IPEndPoint> universeMulticastEndpoints = [];

public SACNClient(Guid senderId, string senderName, IPAddress localAddress, int port = 5568)
: base(() => new SendData(), SACNPacket.MAX_PACKET_SIZE)
public SACNClient(Guid senderId, string senderName, IPAddress localAddress, int port = DefaultPort)
: base(SACNPacket.MAX_PACKET_SIZE)

Check failure on line 52 in src/Haukcode.sACN/SACNClient.cs

View workflow job for this annotation

GitHub Actions / build

There is no argument given that corresponds to the required parameter 'packetSize' of 'Client<SACNClient.SendData, ReceiveDataPacket>.Client(Func<SACNClient.SendData>, int)'

Check failure on line 52 in src/Haukcode.sACN/SACNClient.cs

View workflow job for this annotation

GitHub Actions / build

There is no argument given that corresponds to the required parameter 'packetSize' of 'Client<SACNClient.SendData, ReceiveDataPacket>.Client(Func<SACNClient.SendData>, int)'
{
if (senderId == Guid.Empty)
throw new ArgumentException("Invalid sender Id", nameof(senderId));
Expand All @@ -60,40 +67,11 @@ public SACNClient(Guid senderId, string senderName, IPAddress localAddress, int
ConfigureSendSocket(this.sendSocket);
}

private void SetSocketOptions(Socket socket)
{
// Set the SIO_UDP_CONNRESET ioctl to true for this UDP socket. If this UDP socket
// ever sends a UDP packet to a remote destination that exists but there is
// no socket to receive the packet, an ICMP port unreachable message is returned
// to the sender. By default, when this is received the next operation on the
// UDP socket that send the packet will receive a SocketException. The native
// (Winsock) error that is received is WSAECONNRESET (10054). Since we don't want
// to wrap each UDP socket operation in a try/except, we'll disable this error
// for the socket with this ioctl call.
try
{
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;

byte[] optionInValue = { Convert.ToByte(false) };
byte[] optionOutValue = new byte[4];
socket.IOControl((int)SIO_UDP_CONNRESET, optionInValue, optionOutValue);
}
catch
{
Debug.WriteLine("Unable to set SIO_UDP_CONNRESET, maybe not supported.");
}

socket.ExclusiveAddressUse = false;
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}

private void ConfigureSendSocket(Socket socket)
{
socket.SendBufferSize = SendBufferSize;

SetSocketOptions(socket);
Haukcode.Network.Utils.SetSocketOptions(socket);

// Multicast socket settings
socket.DontFragment = true;
Expand Down Expand Up @@ -129,7 +107,7 @@ public void JoinDMXUniverse(ushort universeId)
throw new InvalidOperationException($"You have already joined the DMX Universe {universeId}");

// Join group
var option = new MulticastOption(SACNCommon.GetMulticastAddress(universeId), this.localEndPoint.Address);
var option = new MulticastOption(Haukcode.Network.Utils.GetMulticastAddress(universeId), this.localEndPoint.Address);
this.listenSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, option);

// Add to the list of universes we have joined
Expand All @@ -145,7 +123,7 @@ public void DropDMXUniverse(ushort universeId)
throw new InvalidOperationException($"You are trying to drop the DMX Universe {universeId} but you are not a member");

// Drop group
var option = new MulticastOption(SACNCommon.GetMulticastAddress(universeId), this.localEndPoint.Address);
var option = new MulticastOption(Haukcode.Network.Utils.GetMulticastAddress(universeId), this.localEndPoint.Address);
this.listenSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, option);

// Remove from the list of universes we have joined
Expand Down Expand Up @@ -227,23 +205,35 @@ public Task SendSync(IPAddress? address, ushort syncAddress)
/// <param name="important">Important</param>
private async Task QueuePacket(ushort universeId, IPAddress? destination, SACNPacket packet, bool important)
{
await base.QueuePacket(packet.Length, important, (newSendData, memory) =>
await base.QueuePacket(packet.Length, important, () =>

Check failure on line 208 in src/Haukcode.sACN/SACNClient.cs

View workflow job for this annotation

GitHub Actions / build

No overload for method 'QueuePacket' takes 4 arguments

Check failure on line 208 in src/Haukcode.sACN/SACNClient.cs

View workflow job for this annotation

GitHub Actions / build

No overload for method 'QueuePacket' takes 4 arguments
{
IPEndPoint? sendDataDestination = null;

if (destination != null)
{
if (!this.endPointCache.TryGetValue(destination, out var ipEndPoint))
// Specified destination (but could be multicast, so check for that)
if (!this.endPointCache.TryGetValue(destination, out var ipEndPointDetails))
{
ipEndPoint = (new IPEndPoint(destination, this.localEndPoint.Port), destination.GetAddressBytes()[0] == 239);
this.endPointCache.Add(destination, ipEndPoint);
ipEndPointDetails = (new IPEndPoint(destination, this.localEndPoint.Port), Haukcode.Network.Utils.IsMulticast(destination));
this.endPointCache.Add(destination, ipEndPointDetails);
}

newSendData.Destination = ipEndPoint.Multicast ? null : ipEndPoint.EndPoint;
sendDataDestination = ipEndPointDetails.Multicast ? null : ipEndPointDetails.EndPoint;
}

newSendData.UniverseId = universeId;
if (sendDataDestination == null)
{
// Set the destination to the multicast address
if (!universeMulticastEndpoints.TryGetValue(universeId, out sendDataDestination))
{
sendDataDestination = new IPEndPoint(Haukcode.Network.Utils.GetMulticastAddress(universeId), this.localEndPoint.Port);
universeMulticastEndpoints.Add(universeId, sendDataDestination);
}
}

return packet.WriteToBuffer(memory);
});
return new SendData(universeId, sendDataDestination);
},
packet.WriteToBuffer);
}

public void WarmUpSockets(IEnumerable<ushort> universeIds)
Expand Down Expand Up @@ -298,18 +288,7 @@ protected override void Dispose(bool disposing)

protected override ValueTask<int> SendPacketAsync(SendData sendData, ReadOnlyMemory<byte> payload)
{
var destination = sendData.Destination;

if (destination == null)
{
if (!universeMulticastEndpoints.TryGetValue(sendData.UniverseId, out destination))
{
destination = new IPEndPoint(SACNCommon.GetMulticastAddress(sendData.UniverseId), this.localEndPoint.Port);
universeMulticastEndpoints.Add(sendData.UniverseId, destination);
}
}

return this.sendSocket.SendToAsync(payload, SocketFlags.None, destination);
return this.sendSocket.SendToAsync(payload, SocketFlags.None, sendData.Destination!);
}

protected async override ValueTask<(int ReceivedBytes, SocketReceiveMessageFromResult Result)> ReceiveData(Memory<byte> memory, CancellationToken cancelToken)
Expand All @@ -335,7 +314,7 @@ protected override ValueTask<int> SendPacketAsync(SendData sendData, ReadOnlyMem

if (!this.endPointCache.TryGetValue(destinationIP, out var ipEndPoint))
{
ipEndPoint = (new IPEndPoint(destinationIP, this.localEndPoint.Port), destinationIP.GetAddressBytes()[0] == 239);
ipEndPoint = (new IPEndPoint(destinationIP, this.localEndPoint.Port), Haukcode.Network.Utils.IsMulticast(destinationIP));
this.endPointCache.Add(destinationIP, ipEndPoint);
}

Expand Down Expand Up @@ -364,7 +343,7 @@ protected override void InitializeReceiveSocket()
this.listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
this.listenSocket.ReceiveBufferSize = ReceiveBufferSize;

SetSocketOptions(this.listenSocket);
Haukcode.Network.Utils.SetSocketOptions(this.listenSocket);

// Linux wants IPAddress.Any to get all types of packets (unicast/multicast/broadcast)
this.listenSocket.Bind(new IPEndPoint(IPAddress.Any, this.localEndPoint.Port));
Expand Down
16 changes: 0 additions & 16 deletions src/Haukcode.sACN/SACNCommon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,6 @@ namespace Haukcode.sACN
{
public static class SACNCommon
{
static byte MULTICAST_BYTE_1 = (byte)239;
static byte MULTICAST_BYTE_2 = (byte)255;
public static int SACN_PORT = 5568;

/// <summary>
/// Get Multicast address from universe id
/// </summary>
/// <param name="universeId">Universe Id</param>
/// <returns></returns>
public static IPAddress GetMulticastAddress(ushort universeId)
{
byte highUniverseId = (byte)(universeId >> 8);
byte lowUniverseId = (byte)(universeId & 0xFF);
var multicastAddress = new IPAddress(new byte[] { MULTICAST_BYTE_1, MULTICAST_BYTE_2, highUniverseId, lowUniverseId });

return multicastAddress;
}
}
}

0 comments on commit 0bd15d2

Please sign in to comment.