Skip to content

Commit 4f1a615

Browse files
committed
Rely on standard async socket operations
Don't use a while loop and Task.Delay to receive from multiple sockets concurrently. With a small restructure we can use standard async operations.
1 parent 1674ed2 commit 4f1a615

File tree

3 files changed

+28
-30
lines changed

3 files changed

+28
-30
lines changed

Mono.Nat/Mono.Nat.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
<Target Name="SetAssemblyVersion" BeforeTargets="GetAssemblyVersion" Condition="'$(RestoreSuccess)' == 'true' And '$(Configuration)' == 'Release' " DependsOnTargets="GitVersion">
4747
<PropertyGroup>
48-
<MonoNatFileVersion>3.0.2</MonoNatFileVersion>
48+
<MonoNatFileVersion>3.0.3</MonoNatFileVersion>
4949
<MonoNatInformationalVersion>$(MonoNatFileVersion)-$(GitBranch)+$(GitCommit)</MonoNatInformationalVersion>
5050

5151
<AssemblyVersion Condition="'$(AssemblyVersion)' == ''">$(MonoNatABIVersion)</AssemblyVersion>

Mono.Nat/Searcher.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ abstract class Searcher : ISearcher
5252
protected SocketGroup Clients { get; }
5353

5454
protected CancellationTokenSource Cancellation { get; }
55+
SemaphoreSlim Locker = new SemaphoreSlim (1, 1);
56+
5557
protected Searcher (SocketGroup clients)
5658
{
5759
Clients = clients;
@@ -75,18 +77,35 @@ public void Dispose ()
7577
}
7678

7779
async void ListenAsync (CancellationToken token)
80+
{
81+
try {
82+
var listens = new List<Task> ();
83+
foreach (var udpClient in Clients.Clients)
84+
listens.Add (ListenOneAsync (udpClient, token));
85+
await Task.WhenAll (listens);
86+
token.ThrowIfCancellationRequested ();
87+
} catch (OperationCanceledException) {
88+
Listening = false;
89+
return;
90+
} catch(Exception ex) {
91+
Log.ExceptionFormated (ex, "Unhandled exception listening for clients in {0}", GetType().Name);
92+
}
93+
}
94+
95+
async Task ListenOneAsync (System.Net.Sockets.UdpClient udpClient, CancellationToken token)
7896
{
7997
while (!token.IsCancellationRequested) {
8098
try {
81-
(var localAddress, var data) = await Clients.ReceiveAsync (token).ConfigureAwait (false);
82-
99+
var data = await udpClient.ReceiveAsync ();
100+
var localEndPoint = (IPEndPoint) udpClient.Client.LocalEndPoint;
83101
token.ThrowIfCancellationRequested ();
84-
await HandleMessageReceived (localAddress, data.Buffer, data.RemoteEndPoint, false, token).ConfigureAwait (false);
102+
103+
using (await Locker.EnterAsync (token))
104+
await HandleMessageReceived (localEndPoint.Address, data.Buffer, data.RemoteEndPoint, false, token).ConfigureAwait (false);
85105
} catch (OperationCanceledException) {
86-
Listening = false;
87106
return;
88-
} catch(Exception ex) {
89-
Log.ExceptionFormated (ex, "Unhandled exception listening for clients in {0}", GetType().Name);
107+
} catch (Exception) {
108+
// Ignore any errors
90109
}
91110
}
92111
}

Mono.Nat/SocketGroup.cs

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace Mono.Nat
99
{
1010
class SocketGroup : IDisposable
1111
{
12+
public ICollection<UdpClient> Clients => Sockets.Keys;
13+
1214
Dictionary<UdpClient, List<IPAddress>> Sockets { get; }
1315
SemaphoreSlim SocketSendLocker { get; }
1416

@@ -27,29 +29,6 @@ public void Dispose ()
2729
s.Key.Dispose ();
2830
}
2931

30-
public async Task<(IPAddress, UdpReceiveResult)> ReceiveAsync (CancellationToken token)
31-
{
32-
while (true) {
33-
foreach (var keypair in Sockets) {
34-
token.ThrowIfCancellationRequested ();
35-
36-
try {
37-
if (keypair.Key.Available > 0) {
38-
var localAddress = ((IPEndPoint) keypair.Key.Client.LocalEndPoint).Address;
39-
var data = await keypair.Key.ReceiveAsync ();
40-
return (localAddress, data);
41-
}
42-
} catch (OperationCanceledException) {
43-
throw;
44-
} catch (Exception) {
45-
// Ignore any errors
46-
}
47-
}
48-
49-
await Task.Delay (10, token);
50-
}
51-
}
52-
5332
public async Task SendAsync (byte[] buffer, IPAddress gatewayAddress, CancellationToken token)
5433
{
5534
using (await SocketSendLocker.EnterAsync (token)) {

0 commit comments

Comments
 (0)