private async Task <bool> StartTls(ClientMetadata client) { try { await client.SslStream.AuthenticateAsServerAsync( _sslCertificate, _settings.MutuallyAuthenticate, SslProtocols.Tls12, !_settings.AcceptInvalidCertificates).ConfigureAwait(false); if (!client.SslStream.IsEncrypted) { Logger?.Invoke($"{_header}client {client.IpPort} not encrypted, disconnecting"); client.Dispose(); return(false); } if (!client.SslStream.IsAuthenticated) { Logger?.Invoke($"{_header}client {client.IpPort} not SSL/TLS authenticated, disconnecting"); client.Dispose(); return(false); } if (_settings.MutuallyAuthenticate && !client.SslStream.IsMutuallyAuthenticated) { Logger?.Invoke($"{_header}client {client.IpPort} failed mutual authentication, disconnecting"); client.Dispose(); return(false); } } catch (Exception e) { Logger?.Invoke($"{_header}client {client.IpPort} SSL/TLS exception: {Environment.NewLine}{e}"); client.Dispose(); return(false); } return(true); }
private async Task DataReceiver(ClientMetadata client) { string ipPort = client.IpPort; Logger?.Invoke($"{_header}data receiver started for client {ipPort}"); CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_token, client.Token); while (true) { try { if (!IsClientConnected(client.Client)) { Logger?.Invoke($"{_header}client {ipPort} disconnected"); break; } if (client.Token.IsCancellationRequested) { Logger?.Invoke($"{_header}cancellation requested (data receiver for client {ipPort})"); break; } byte[] data = await DataReadAsync(client, linkedCts.Token).ConfigureAwait(false); if (data == null) { await Task.Delay(10, linkedCts.Token).ConfigureAwait(false); continue; } _ = Task.Run(() => _events.HandleDataReceived(this, new DataReceivedEventArgs(ipPort, data)), linkedCts.Token); _statistics.ReceivedBytes += data.Length; UpdateClientLastSeen(client.IpPort); } catch (IOException) { Logger?.Invoke($"{_header}data receiver canceled, peer disconnected [{ipPort}]"); break; } catch (SocketException) { Logger?.Invoke($"{_header}data receiver canceled, peer disconnected [{ipPort}]"); break; } catch (TaskCanceledException) { Logger?.Invoke($"{_header}data receiver task canceled [{ipPort}]"); break; } catch (ObjectDisposedException) { Logger?.Invoke($"{_header}data receiver canceled due to disposal [{ipPort}]"); break; } catch (Exception e) { Logger?.Invoke($"{_header}data receiver exception [{ipPort}]:{ Environment.NewLine}{e}{Environment.NewLine}"); break; } } Logger?.Invoke($"{_header}data receiver terminated for client {ipPort}"); if (_clientsKicked.ContainsKey(ipPort)) { _events.HandleClientDisconnected(this, new ConnectionEventArgs(ipPort, DisconnectReason.Kicked)); } else if (_clientsTimedout.ContainsKey(client.IpPort)) { _events.HandleClientDisconnected(this, new ConnectionEventArgs(ipPort, DisconnectReason.Timeout)); } else { _events.HandleClientDisconnected(this, new ConnectionEventArgs(ipPort, DisconnectReason.Normal)); } _clients.TryRemove(ipPort, out _); _clientsLastSeen.TryRemove(ipPort, out _); _clientsKicked.TryRemove(ipPort, out _); _clientsTimedout.TryRemove(ipPort, out _); if (client != null) { client.Dispose(); } }
private async Task AcceptConnections() { while (!_listenerToken.IsCancellationRequested) { ClientMetadata client = null; try { TcpClient tcpClient = await _listener.AcceptTcpClientAsync().ConfigureAwait(false); string clientIp = tcpClient.Client.RemoteEndPoint.ToString(); client = new ClientMetadata(tcpClient); if (_ssl) { if (_settings.AcceptInvalidCertificates) { client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(AcceptCertificate)); } else { client.SslStream = new SslStream(client.NetworkStream, false); } bool success = await StartTls(client).ConfigureAwait(false); if (!success) { client.Dispose(); continue; } } _clients.TryAdd(clientIp, client); _clientsLastSeen.TryAdd(clientIp, DateTime.Now); Logger?.Invoke($"{_header}starting data receiver for: {clientIp}"); _events.HandleClientConnected(this, new ConnectionEventArgs(clientIp)); if (_keepalive.EnableTcpKeepAlives) { EnableKeepalives(tcpClient); } CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(client.Token, _token); Task unawaited = Task.Run(() => DataReceiver(client), linkedCts.Token); } catch (Exception ex) { if (ex is TaskCanceledException || ex is OperationCanceledException || ex is ObjectDisposedException || ex is InvalidOperationException) { _isListening = false; if (client != null) { client.Dispose(); } Logger?.Invoke($"{_header}stopped listening"); break; } else { if (client != null) { client.Dispose(); } Logger?.Invoke($"{_header}exception while awaiting connections: {ex}"); continue; } } } _isListening = false; }