/// <summary> /// Get direct access to the underlying client stream. /// </summary> /// <param name="ipPort">The client IP:port string.</param> /// <returns>Stream.</returns> public Stream GetStream(string ipPort) { if (String.IsNullOrEmpty(ipPort)) { throw new ArgumentNullException(nameof(ipPort)); } ClientMetadata client = null; lock (_ClientsLock) { if (!_Clients.ContainsKey(ipPort)) { throw new KeyNotFoundException("Client with IP:port of " + ipPort + " not found."); } client = _Clients[ipPort]; } if (!_Ssl) { return(client.NetworkStream); } else { return(client.SslStream); } }
private void ClientConnectionMonitor(ClientMetadata client) { string ipPort = client.IpPort; while (true) { Task.Delay(1000).Wait(); if (client == null || client.Client == null || !IsClientConnected(client.Client)) { Logger?.Invoke(_Header + "Client " + ipPort + " no longer connected"); DisconnectClient(ipPort); break; } } }
/// <summary> /// Disconnects the specified client. /// </summary> /// <param name="ipPort">IP:port of the client.</param> public void DisconnectClient(string ipPort) { if (String.IsNullOrEmpty(ipPort)) { throw new ArgumentNullException(nameof(ipPort)); } lock (_ClientsLock) { if (_Clients.ContainsKey(ipPort)) { ClientMetadata client = _Clients[ipPort]; client.Dispose(); _Clients.Remove(ipPort); } Logger?.Invoke(_Header + "Removed: " + ipPort); } ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(ipPort, DisconnectReason.Kicked)); }
private async Task <bool> StartTls(ClientMetadata client) { try { await client.SslStream.AuthenticateAsServerAsync( _SslCertificate, MutuallyAuthenticate, SslProtocols.Tls12, !AcceptInvalidCertificates); 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 (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.ToString()); client.Dispose(); return(false); } return(true); }
private async Task <ReadResult> ReadInternalAsync(string ipPort, long count) { if (count < 1) { return(new ReadResult(ReadResultStatus.Success, 0, null)); } ClientMetadata client = null; lock (_ClientsLock) { if (!_Clients.ContainsKey(ipPort)) { return(new ReadResult(ReadResultStatus.ClientNotFound, 0, null)); } client = _Clients[ipPort]; } ReadResult result = new ReadResult(ReadResultStatus.Success, 0, null); try { await client.ReadSemaphore.WaitAsync(1); MemoryStream ms = new MemoryStream(); long bytesRemaining = count; while (bytesRemaining > 0) { byte[] buffer = null; if (bytesRemaining >= _StreamBufferSize) { buffer = new byte[_StreamBufferSize]; } else { buffer = new byte[bytesRemaining]; } int bytesRead = 0; if (!_Ssl) { bytesRead = await client.NetworkStream.ReadAsync(buffer, 0, buffer.Length); } else { bytesRead = await client.SslStream.ReadAsync(buffer, 0, buffer.Length); } if (bytesRead > 0) { if (bytesRead == buffer.Length) { await ms.WriteAsync(buffer, 0, buffer.Length); } else { await ms.WriteAsync(buffer, 0, bytesRead); } result.BytesRead += bytesRead; Stats.ReceivedBytes += bytesRead; bytesRemaining -= bytesRead; } } ms.Seek(0, SeekOrigin.Begin); result.DataStream = ms; return(result); } catch (Exception) { result.Status = ReadResultStatus.Disconnected; result.BytesRead = 0; result.DataStream = null; return(result); } finally { client.ReadSemaphore.Release(); } }
private async Task <WriteResult> SendInternalAsync(string ipPort, long contentLength, Stream stream) { ClientMetadata client = null; lock (_ClientsLock) { if (!_Clients.ContainsKey(ipPort)) { return(new WriteResult(WriteResultStatus.ClientNotFound, 0)); } client = _Clients[ipPort]; } WriteResult result = new WriteResult(WriteResultStatus.Success, 0); try { client.WriteSemaphore.Wait(1); if (contentLength > 0 && stream != null && stream.CanRead) { long bytesRemaining = contentLength; while (bytesRemaining > 0) { byte[] buffer = new byte[_StreamBufferSize]; int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); if (bytesRead > 0) { byte[] data = null; if (bytesRead == buffer.Length) { data = new byte[buffer.Length]; Buffer.BlockCopy(buffer, 0, data, 0, buffer.Length); } else { data = new byte[bytesRead]; Buffer.BlockCopy(buffer, 0, data, 0, bytesRead); } if (!_Ssl) { await client.NetworkStream.WriteAsync(data, 0, data.Length); await client.NetworkStream.FlushAsync(); } else { await client.SslStream.WriteAsync(data, 0, data.Length); await client.SslStream.FlushAsync(); } result.BytesWritten += bytesRead; Stats.SentBytes += bytesRead; bytesRemaining -= bytesRead; } } } return(result); } catch (Exception) { result.Status = WriteResultStatus.Disconnected; return(result); } finally { client.WriteSemaphore.Release(); } }
private async void AcceptConnections() { while (!_Token.IsCancellationRequested) { ClientMetadata client = null; try { System.Net.Sockets.TcpClient tcpClient = await _Listener.AcceptTcpClientAsync(); string clientIp = tcpClient.Client.RemoteEndPoint.ToString(); client = new ClientMetadata(tcpClient); if (_Ssl) { if (AcceptInvalidCertificates) { client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(AcceptCertificate)); } else { client.SslStream = new SslStream(client.NetworkStream, false); } bool success = await StartTls(client); if (!success) { client.Dispose(); continue; } } lock (_Clients) { _Clients.Add(clientIp, client); } Logger?.Invoke("Starting connection monitor for: " + clientIp); Task unawaited = Task.Run(() => ClientConnectionMonitor(client), client.Token); ClientConnected?.Invoke(this, new ClientConnectedEventArgs(clientIp)); } catch (OperationCanceledException) { return; } catch (ObjectDisposedException) { if (client != null) { client.Dispose(); } continue; } catch (Exception e) { if (client != null) { client.Dispose(); } Logger?.Invoke(_Header + "Exception while awaiting connections: " + e.ToString()); continue; } } _IsListening = false; }