private async Task HandleIncoming() { while (!_cts.IsCancellationRequested) { try { UdpReceiveResult data; try { data = await _socket.ReceiveAsync(); _logger.LogDebug("Received DTLS Packet from {EndPoint}", data.RemoteEndPoint); } catch (ObjectDisposedException) { // Happens when the Connection is being closed continue; } catch (SocketException sockEx) { // Some clients send an ICMP Port Unreachable when they receive data after they stopped listening. // If we knew from which client it came we could get rid of the connection, but we can't, so we just ignore the exception. if (sockEx.SocketErrorCode == SocketError.ConnectionReset) { _logger.LogInformation("Connection Closed by remote host"); continue; } _logger.LogError("SocketException with SocketErrorCode {SocketErrorCode}", sockEx.SocketErrorCode); throw; } // if there is an existing session, we pass the datagram to the session. if (_sessions.TryGetValue(data.RemoteEndPoint, out CoapDtlsServerClientEndPoint session)) { session.EnqueueDatagram(data.Buffer); continue; } // if there isn't an existing session for this remote endpoint, we start a new one and pass the first datagram to the session var transport = new QueueDatagramTransport(NetworkMtu, bytes => _sendQueue.Add(new UdpSendPacket(bytes, data.RemoteEndPoint))); session = new CoapDtlsServerClientEndPoint(data.RemoteEndPoint, transport, DateTime.UtcNow); session.EnqueueDatagram(data.Buffer); _sessions.TryAdd(data.RemoteEndPoint, session); try { _logger.LogInformation("New connection from {EndPoint}; Active Sessions: {ActiveSessions}", data.RemoteEndPoint, _sessions.Count); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Factory.StartNew(() => HandleSession(session), TaskCreationOptions.LongRunning); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } catch (Exception ex) { _logger.LogError(ex, "Exception while starting session handler!"); _sessions.TryRemove(session.EndPoint, out _); } } catch (Exception ex) { _logger.LogError(ex, "Error while handling incoming datagrams"); } } }
private async Task HandleSession(CoapDtlsServerClientEndPoint session) { var state = new Dictionary <string, object> { { "RemoteEndPoint", session?.EndPoint } }; using (_logger.BeginScope(state)) { try { _logger.LogDebug("Trying to accept TLS connection from {EndPoint}", session.EndPoint); var server = _tlsServerFactory.Create(); session.Accept(_serverProtocol, server); if (session.ConnectionInfo != null) { _logger.LogInformation("New TLS connection from {EndPoint}, Server Info: {ServerInfo}", session.EndPoint, session.ConnectionInfo); } else { _logger.LogInformation("New TLS connection from {EndPoint}", session.EndPoint); } 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); } } catch (OperationCanceledException) { } catch (DtlsConnectionClosedException) { } catch (TlsFatalAlert tlsAlert) { if (!(tlsAlert.InnerException is DtlsConnectionClosedException) && tlsAlert.AlertDescription != AlertDescription.user_canceled) { _logger.LogWarning(tlsAlert, "TLS Error"); } } catch (Exception ex) { _logger.LogError(ex, "Error while handling session"); } finally { _logger.LogInformation("Connection from {EndPoint} closed", session.EndPoint); _sessions.TryRemove(session.EndPoint, out _); } } }