Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 9 additions & 15 deletions samples/DtlsClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
using System.Threading.Tasks;
using CoAPNet;
using CoAPNet.Dtls.Client;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Tls;
using Org.BouncyCastle.Tls.Crypto;
using Org.BouncyCastle.Tls.Crypto.Impl.BC;

namespace CoAPDevices
{
Expand All @@ -16,7 +19,6 @@ static async Task Main(string[] args)
var port = Coap.PortDTLS;
var identity = new BasicTlsPskIdentity("user", Encoding.UTF8.GetBytes("password"));


// Create a new client using a DTLS endpoint with the remote host and Identity
var client = new CoapClient(new CoapDtlsClientEndPoint(host, port, new ExamplePskDtlsClient(identity)));
// Create a cancelation token that cancels after 1 minute
Expand Down Expand Up @@ -69,26 +71,18 @@ static async Task Main(string[] args)
public class ExamplePskDtlsClient : PskTlsClient
{
public ExamplePskDtlsClient(TlsPskIdentity pskIdentity)
: base(pskIdentity)
: base(new BcTlsCrypto(new SecureRandom()), pskIdentity)
{
}

public ExamplePskDtlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity)
: base(cipherFactory, pskIdentity)
{
}

public ExamplePskDtlsClient(TlsCipherFactory cipherFactory, TlsDHVerifier dhVerifier, TlsPskIdentity pskIdentity)
: base(cipherFactory, dhVerifier, pskIdentity)
public override int GetHandshakeTimeoutMillis()
{
return 30000;
}

public override ProtocolVersion MinimumVersion => ProtocolVersion.DTLSv10;
public override ProtocolVersion ClientVersion => ProtocolVersion.DTLSv12;

public override int GetHandshakeTimeoutMillis()
public override ProtocolVersion[] GetProtocolVersions()
{
return 30000;
return ProtocolVersion.DTLSv12.DownTo(ProtocolVersion.DTLSv10);
}
}
}
Expand Down
14 changes: 8 additions & 6 deletions samples/DtlsServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
using CoAPNet.Server;
using System.Threading.Tasks;
using CoAPNet.Dtls.Server;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;
using Org.BouncyCastle.Tls.Crypto.Impl.BC;
using Org.BouncyCastle.Security;

namespace CoAPDevices
{
Expand Down Expand Up @@ -82,7 +82,7 @@ public class ExamplePskDtlsServer : PskTlsServer
private readonly ExamplePskIdentityManager pskIdentityManager;

public ExamplePskDtlsServer(ExamplePskIdentityManager pskIdentityManager)
: base(pskIdentityManager)
: base(new BcTlsCrypto(new SecureRandom()), pskIdentityManager)
{
this.pskIdentityManager = pskIdentityManager;
}
Expand All @@ -97,8 +97,10 @@ public string GetIdentity()
return this.pskIdentityManager.GetIdentity();
}

protected override ProtocolVersion MinimumVersion => ProtocolVersion.DTLSv10;
protected override ProtocolVersion MaximumVersion => ProtocolVersion.DTLSv12;
public override ProtocolVersion[] GetProtocolVersions()
{
return ProtocolVersion.DTLSv12.DownTo(ProtocolVersion.DTLSv10);
}
}

public class ExamplePskIdentityManager : TlsPskIdentityManager
Expand Down
4 changes: 2 additions & 2 deletions src/CoAPNet.Dtls/Client/CoapDtlsClientEndPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;
using Org.BouncyCastle.Security;

namespace CoAPNet.Dtls.Client
Expand Down Expand Up @@ -82,7 +82,7 @@ private void EnsureConnected()

var udpClient = new UdpClient(Server, Port);

var dtlsClientProtocol = new DtlsClientProtocol(new SecureRandom());
var dtlsClientProtocol = new DtlsClientProtocol();
_datagramTransport = dtlsClientProtocol.Connect(_tlsClient, new UdpDatagramTransport(udpClient, NetworkMtu));
_isConnected = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/CoAPNet.Dtls/Client/UdpDatagramTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Linq;
using System.Net;
using System.Net.Sockets;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;

namespace CoAPNet.Dtls.Client
{
Expand Down
2 changes: 1 addition & 1 deletion src/CoAPNet.Dtls/CoAPNet.Dtls.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.8" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/CoAPNet.Dtls/Server/CoapDtlsConnectionInformation.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;

namespace CoAPNet.Dtls.Server
{
Expand Down
8 changes: 4 additions & 4 deletions src/CoAPNet.Dtls/Server/CoapDtlsServerClientEndPoint.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;

namespace CoAPNet.Dtls.Server
{
Expand All @@ -29,7 +30,7 @@ public CoapDtlsServerClientEndPoint(IPEndPoint endPoint, QueueDatagramTransport

public IPEndPoint EndPoint { get; }
public Uri BaseUri { get; }
public string ConnectionInfo { get; private set; }
public IReadOnlyDictionary<string, object> ConnectionInfo { get; private set; }

public bool IsSecure => true;

Expand Down Expand Up @@ -102,8 +103,7 @@ public void Accept(DtlsServerProtocol serverProtocol, TlsServer server)

public void EnqueueDatagram(byte[] datagram)
{
if (!IsClosed)
_udpTransport.ReceiveQueue.Add(datagram);
_udpTransport.EnqueueReceived(datagram);
LastReceivedTime = DateTime.UtcNow;
}
}
Expand Down
57 changes: 28 additions & 29 deletions src/CoAPNet.Dtls/Server/CoapDtlsServerTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
using System.Threading.Tasks;
using CoAPNet.Dtls.Server.Statistics;
using Microsoft.Extensions.Logging;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Tls;

namespace CoAPNet.Dtls.Server
{
Expand All @@ -35,9 +34,7 @@ public CoapDtlsServerTransport(CoapDtlsServerEndPoint endPoint, ICoapHandler coa
_tlsServerFactory = tlsServerFactory ?? throw new ArgumentNullException(nameof(tlsServerFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));

SecureRandom random = new SecureRandom();

_serverProtocol = new DtlsServerProtocol(random);
_serverProtocol = new DtlsServerProtocol();

_sessions = new ConcurrentDictionary<IPEndPoint, CoapDtlsServerClientEndPoint>();
}
Expand Down Expand Up @@ -176,42 +173,37 @@ private async Task HandleSession(CoapDtlsServerClientEndPoint session)

session.Accept(_serverProtocol, server);

if (session.ConnectionInfo != null)
{
_logger.LogInformation("New TLS connection from {EndPoint}, Server Info: {ServerInfo}", session.EndPoint, session.ConnectionInfo);
}
else
using (session.ConnectionInfo != null ? _logger.BeginScope(session.ConnectionInfo) : null)
{
_logger.LogInformation("New TLS connection from {EndPoint}", session.EndPoint);
}

var connectionInfo = new CoapDtlsConnectionInformation
{
LocalEndpoint = _endPoint,
RemoteEndpoint = session,
TlsServer = server
};
var connectionInfo = new CoapDtlsConnectionInformation
{
LocalEndpoint = _endPoint,
RemoteEndpoint = session,
TlsServer = server
};

while (!session.IsClosed && !_cts.IsCancellationRequested)
{
var packet = await session.ReceiveAsync(_cts.Token);
_logger.LogDebug("Handling CoAP Packet from {EndPoint}", session.EndPoint);
await _coapHandler.ProcessRequestAsync(connectionInfo, packet.Payload);
_logger.LogDebug("CoAP request from {EndPoint} handled!", session.EndPoint);
while (!session.IsClosed && !_cts.IsCancellationRequested)
{
var packet = await session.ReceiveAsync(_cts.Token);
_logger.LogDebug("Handling CoAP Packet from {EndPoint}", session.EndPoint);
await _coapHandler.ProcessRequestAsync(connectionInfo, packet.Payload);
_logger.LogDebug("CoAP request from {EndPoint} handled!", session.EndPoint);
}
}
}
catch (OperationCanceledException)
catch (Exception ex) when (IsCanceledException(ex))
{
_logger.LogDebug(ex, "Session was canceled");
}
catch (DtlsConnectionClosedException)
catch (TlsTimeoutException timeoutEx)
{
_logger.LogWarning(timeoutEx, "Timeout while handling session");
}
catch (TlsFatalAlert tlsAlert)
{
if (!(tlsAlert.InnerException is DtlsConnectionClosedException) && tlsAlert.AlertDescription != AlertDescription.user_canceled)
{
_logger.LogWarning(tlsAlert, "TLS Error");
}
_logger.LogWarning(tlsAlert, "TLS Error");
}
catch (Exception ex)
{
Expand All @@ -225,6 +217,13 @@ private async Task HandleSession(CoapDtlsServerClientEndPoint session)
}
}

private bool IsCanceledException(Exception ex)
{
return ex is OperationCanceledException ||
ex is DtlsConnectionClosedException ||
(ex is TlsFatalAlert tlsAlert && (tlsAlert.InnerException is DtlsConnectionClosedException || tlsAlert.AlertDescription == AlertDescription.user_canceled));
}

private async Task HandleCleanup()
{
while (!_cts.IsCancellationRequested)
Expand Down
2 changes: 1 addition & 1 deletion src/CoAPNet.Dtls/Server/IDtlsServerFactory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;

namespace CoAPNet.Dtls.Server
{
Expand Down
5 changes: 3 additions & 2 deletions src/CoAPNet.Dtls/Server/IDtlsServerWithConnectionInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;
using System.Collections.Generic;

namespace CoAPNet.Dtls.Server
{
Expand All @@ -12,6 +13,6 @@ public interface IDtlsServerWithConnectionInfo : TlsServer
/// Get the connection information for the connection handled by this TLS server.
/// </summary>
/// <returns>Information about this connection that should be logged once the connection is established.</returns>
string GetConnectionInfo();
IReadOnlyDictionary<string, object> GetConnectionInfo();
}
}
25 changes: 21 additions & 4 deletions src/CoAPNet.Dtls/Server/QueueDatagramTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Tls;

namespace CoAPNet.Dtls.Server
{
Expand All @@ -16,6 +16,7 @@ internal class QueueDatagramTransport : DatagramTransport
private readonly int _sendLimit;
private readonly Action<byte[]> _sendCallback;
private readonly CancellationTokenSource _cts;
private BlockingCollection<byte[]> _receiveQueue;

private const int MIN_IP_OVERHEAD = 20;
private const int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64;
Expand All @@ -27,20 +28,21 @@ public QueueDatagramTransport(int mtu, Action<byte[]> sendCallback)
_sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD;
_sendCallback = sendCallback ?? throw new ArgumentNullException(nameof(sendCallback));
_cts = new CancellationTokenSource();
_receiveQueue = new BlockingCollection<byte[]>();
}

public BlockingCollection<byte[]> ReceiveQueue { get; internal set; } = new BlockingCollection<byte[]>();
public bool IsClosed { get; private set; }
public ReaderWriterLockSlim CloseLock { get; } = new ReaderWriterLockSlim();

public void Close()
{
// Cancel this before locking so the lock gets released ASAP
_cts.Cancel();

CloseLock.EnterWriteLock();
IsClosed = true;
_receiveQueue.Dispose();
CloseLock.ExitWriteLock();
ReceiveQueue.Dispose();
}

public int GetReceiveLimit()
Expand All @@ -53,6 +55,21 @@ public int GetSendLimit()
return _sendLimit;
}

public void EnqueueReceived(byte[] datagram)
{
try
{
CloseLock.EnterReadLock();
if (IsClosed)
return;
_receiveQueue.Add(datagram);
}
finally
{
CloseLock.ExitReadLock();
}
}

public int Receive(byte[] buf, int off, int len, int waitMillis)
{
try
Expand All @@ -61,7 +78,7 @@ public int Receive(byte[] buf, int off, int len, int waitMillis)
if (IsClosed)
throw new DtlsConnectionClosedException();

var success = ReceiveQueue.TryTake(out var data, waitMillis, _cts.Token);
var success = _receiveQueue.TryTake(out var data, waitMillis, _cts.Token);
if (!success)
return -1; // DO NOT return 0. This will disable the wait timeout effectively for the caller and any abort logic will by bypassed!
var readLen = Math.Min(len, data.Length);
Expand Down
3 changes: 2 additions & 1 deletion src/CoAPNet.Dtls/Server/Statistics/DtlsSessionStatistics.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;

namespace CoAPNet.Dtls.Server.Statistics
{
public class DtlsSessionStatistics
{
public string EndPoint { get; set; }
public string ConnectionInfo { get; set; }
public IReadOnlyDictionary<string, object> ConnectionInfo { get; set; }
public DateTime SessionStartTime { get; internal set; }
public DateTime LastReceivedTime { get; internal set; }
}
Expand Down