Skip to content

Commit 3e670b3

Browse files
committed
Fixed multicast based discoverer.
1 parent c4dfca9 commit 3e670b3

File tree

2 files changed

+42
-61
lines changed

2 files changed

+42
-61
lines changed

SharpSnmpLib/Messaging/Discoverer.cs

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ namespace Lextm.SharpSnmpLib.Messaging
3333
public sealed partial class Discoverer
3434
{
3535
private int _active;
36-
private int _bufferSize;
3736
private int _requestId;
3837
private static readonly UserRegistry Empty = new();
3938
private readonly IList<Variable> _defaultVariables = new List<Variable> { new(new ObjectIdentifier(new uint[] { 1, 3, 6, 1, 2, 1, 1, 1, 0 })) };
@@ -88,7 +87,7 @@ public void Discover(VersionCode version, IPEndPoint broadcastAddress, OctetStri
8887
using var udp = new UdpClient(addressFamily);
8988
if (addressFamily == AddressFamily.InterNetworkV6)
9089
{
91-
udp.JoinMulticastGroup(broadcastAddress.Address);
90+
udp.MulticastLoopback = false;
9291
}
9392
else if (addressFamily == AddressFamily.InterNetwork)
9493
{
@@ -108,12 +107,12 @@ public void Discover(VersionCode version, IPEndPoint broadcastAddress, OctetStri
108107
return;
109108
}
110109

111-
_bufferSize = udp.Client.ReceiveBufferSize = Messenger.MaxMessageSize;
110+
udp.Client.ReceiveBufferSize = Messenger.MaxMessageSize;
112111

113112
#if ASYNC
114-
Task.Factory.StartNew(() => AsyncBeginReceive(udp.Client));
113+
Task.Factory.StartNew(() => AsyncBeginReceive(udp));
115114
#else
116-
Task.Factory.StartNew(() => AsyncReceive(udp.Client));
115+
Task.Factory.StartNew(() => AsyncReceive(udp));
117116
#endif
118117

119118
Thread.Sleep(interval);
@@ -198,7 +197,7 @@ private void AsyncEndReceive(IAsyncResult iar)
198197
}
199198
#else
200199

201-
private void AsyncReceive(Socket socket)
200+
private void AsyncReceive(UdpClient client)
202201
{
203202
while (true)
204203
{
@@ -210,10 +209,9 @@ private void AsyncReceive(Socket socket)
210209

211210
try
212211
{
213-
var buffer = new byte[_bufferSize];
214-
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
215-
var count = socket.ReceiveFrom(buffer, ref remote);
216-
Task.Factory.StartNew(() => HandleMessage(buffer, count, (IPEndPoint)remote));
212+
var remote = new IPEndPoint(IPAddress.Any, 0);
213+
var buffer = client.Receive(ref remote);
214+
Task.Factory.StartNew(() => HandleMessage(buffer, buffer.Length, remote));
217215
}
218216
catch (SocketException ex)
219217
{
@@ -298,11 +296,6 @@ public async Task DiscoverAsync(VersionCode version, IPEndPoint broadcastAddress
298296
}
299297

300298
var addressFamily = broadcastAddress.AddressFamily;
301-
if (addressFamily == AddressFamily.InterNetworkV6)
302-
{
303-
throw new ArgumentException("IP v6 is not yet supported.", nameof(broadcastAddress));
304-
}
305-
306299
byte[] bytes;
307300
_requestId = Messenger.NextRequestId;
308301
if (version == VersionCode.V3)
@@ -316,25 +309,32 @@ public async Task DiscoverAsync(VersionCode version, IPEndPoint broadcastAddress
316309
bytes = message.ToBytes();
317310
}
318311

319-
using var udp = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp);
320-
udp.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
321-
var buffer = new ArraySegment<byte>(bytes);
322-
await udp.SendToAsync(buffer, SocketFlags.None, broadcastAddress);
312+
using var udp = new UdpClient(addressFamily);
313+
if (addressFamily == AddressFamily.InterNetworkV6)
314+
{
315+
udp.MulticastLoopback = false;
316+
}
317+
else if (addressFamily == AddressFamily.InterNetwork)
318+
{
319+
#if (!CF)
320+
udp.EnableBroadcast = true;
321+
#endif
322+
}
323323

324+
await udp.SendAsync(bytes, bytes.Length, broadcastAddress);
324325
var activeBefore = Interlocked.CompareExchange(ref _active, Active, Inactive);
325326
if (activeBefore == Active)
326327
{
327328
// If already started, we've nothing to do.
328329
return;
329330
}
330331

331-
_bufferSize = udp.ReceiveBufferSize;
332332
#if NET6_0_OR_GREATER
333333
var source = new CancellationTokenSource();
334334
source.CancelAfter(interval);
335335
try
336336
{
337-
await ReceiveAsync(udp, source.Token);
337+
await ReceiveAsync(udp.Client, source.Token);
338338
}
339339
catch (OperationCanceledException)
340340
{
@@ -346,18 +346,10 @@ await Task.WhenAny(
346346
Task.Delay(interval));
347347
#endif
348348
Interlocked.CompareExchange(ref _active, Inactive, Active);
349-
try
350-
{
351-
udp.Shutdown(SocketShutdown.Both);
352-
}
353-
catch (SocketException)
354-
{
355-
// This exception is thrown in .NET Core <=2.1.4 on non-Windows systems.
356-
// However, the shutdown call is necessary to release the socket binding.
357-
}
349+
udp.Close();
358350
}
359351
#if !NET6_0_OR_GREATER
360-
private async Task ReceiveAsync(Socket socket)
352+
private async Task ReceiveAsync(UdpClient client)
361353
{
362354
while (true)
363355
{
@@ -369,11 +361,8 @@ private async Task ReceiveAsync(Socket socket)
369361

370362
try
371363
{
372-
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
373-
374-
var buffer = new byte[_bufferSize];
375-
var result = await socket.ReceiveMessageFromAsync(new ArraySegment<byte>(buffer), SocketFlags.None, remote);
376-
await Task.Factory.StartNew(() => HandleMessage(buffer, result.ReceivedBytes, (IPEndPoint) result.RemoteEndPoint))
364+
var result = await client.ReceiveAsync();
365+
await Task.Factory.StartNew(() => HandleMessage(result.Buffer, result.Buffer.Length, result.RemoteEndPoint))
377366
.ConfigureAwait(false);
378367
}
379368
catch (SocketException ex)

SharpSnmpLib/Messaging/Net6Discoverer.cs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ public void Discover(VersionCode version, IPEndPoint broadcastAddress, OctetStri
8181
return;
8282
}
8383

84-
_bufferSize = udp.Client.ReceiveBufferSize = Messenger.MaxMessageSize;
84+
udp.Client.ReceiveBufferSize = Messenger.MaxMessageSize;
8585

8686
#if ASYNC
8787
Task.Factory.StartNew(() => AsyncBeginReceive(udp.Client, token));
8888
#else
89-
Task.Factory.StartNew(() => AsyncReceive(udp.Client), token);
89+
Task.Factory.StartNew(() => AsyncReceive(udp), token);
9090
#endif
9191
token.WaitHandle.WaitOne();
9292
Interlocked.CompareExchange(ref _active, Inactive, Active);
@@ -154,11 +154,6 @@ public async Task DiscoverAsync(VersionCode version, IPEndPoint broadcastAddress
154154
}
155155

156156
var addressFamily = broadcastAddress.AddressFamily;
157-
if (addressFamily == AddressFamily.InterNetworkV6)
158-
{
159-
throw new ArgumentException("IP v6 is not yet supported.", nameof(broadcastAddress));
160-
}
161-
162157
byte[] bytes;
163158
_requestId = Messenger.NextRequestId;
164159
if (version == VersionCode.V3)
@@ -172,31 +167,28 @@ public async Task DiscoverAsync(VersionCode version, IPEndPoint broadcastAddress
172167
bytes = message.ToBytes();
173168
}
174169

175-
using var udp = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp);
176-
udp.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
177-
var buffer = new ArraySegment<byte>(bytes);
178-
await udp.SendToAsync(buffer, SocketFlags.None, broadcastAddress, token);
170+
using var udp = new UdpClient(addressFamily);
171+
if (addressFamily == AddressFamily.InterNetworkV6)
172+
{
173+
udp.MulticastLoopback = false;
174+
}
175+
else if (addressFamily == AddressFamily.InterNetwork)
176+
{
177+
udp.EnableBroadcast = true;
178+
}
179179

180+
await udp.Client.SendToAsync(bytes, SocketFlags.None, broadcastAddress, token);
180181
var activeBefore = Interlocked.CompareExchange(ref _active, Active, Inactive);
181182
if (activeBefore == Active)
182183
{
183184
// If already started, we've nothing to do.
184185
return;
185186
}
186187

187-
_bufferSize = udp.ReceiveBufferSize;
188-
await ReceiveAsync(udp, token);
188+
await ReceiveAsync(udp.Client, token);
189189

190190
Interlocked.CompareExchange(ref _active, Inactive, Active);
191-
try
192-
{
193-
udp.Shutdown(SocketShutdown.Both);
194-
}
195-
catch (SocketException)
196-
{
197-
// This exception is thrown in .NET Core <=2.1.4 on non-Windows systems.
198-
// However, the shutdown call is necessary to release the socket binding.
199-
}
191+
udp.Close();
200192
}
201193

202194
private async Task ReceiveAsync(Socket socket, CancellationToken token)
@@ -216,10 +208,10 @@ private async Task ReceiveAsync(Socket socket, CancellationToken token)
216208

217209
try
218210
{
219-
EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
211+
EndPoint remote = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);
220212

221-
var buffer = new byte[_bufferSize];
222-
var result = await socket.ReceiveMessageFromAsync(new ArraySegment<byte>(buffer), SocketFlags.None, remote, token);
213+
var buffer = new byte[socket.ReceiveBufferSize];
214+
var result = await socket.ReceiveFromAsync(new ArraySegment<byte>(buffer), SocketFlags.None, remote, token);
223215
await Task.Factory.StartNew(() => HandleMessage(buffer, result.ReceivedBytes, (IPEndPoint)result.RemoteEndPoint), token)
224216
.ConfigureAwait(false);
225217
}

0 commit comments

Comments
 (0)