private async Task <bool> StartTls(ClientMetadata client) { try { // the two bools in this should really be contruction paramaters // maybe re-use mutualAuthentication and acceptInvalidCerts ? await client.SslStream.AuthenticateAsServerAsync(_SslCertificate, true, SslProtocols.Tls12, false); if (!client.SslStream.IsEncrypted) { Log("*** StartTls stream from " + client.IpPort + " not encrypted"); client.Dispose(); return(false); } if (!client.SslStream.IsAuthenticated) { Log("*** StartTls stream from " + client.IpPort + " not authenticated"); client.Dispose(); return(false); } if (_MutuallyAuthenticate && !client.SslStream.IsMutuallyAuthenticated) { Log("*** StartTls stream from " + client.IpPort + " failed mutual authentication"); client.Dispose(); return(false); } } catch (IOException ex) { // Some type of problem initiating the SSL connection switch (ex.Message) { case "Authentication failed because the remote party has closed the transport stream.": case "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.": Log("*** StartTls IOException " + client.IpPort + " closed the connection."); break; case "The handshake failed due to an unexpected packet format.": Log("*** StartTls IOException " + client.IpPort + " disconnected, invalid handshake."); break; default: Log("*** StartTls IOException from " + client.IpPort + Environment.NewLine + ex.ToString()); break; } client.Dispose(); return(false); } catch (Exception ex) { Log("*** StartTls Exception from " + client.IpPort + Environment.NewLine + ex.ToString()); client.Dispose(); return(false); } return(true); }
private void FinalizeConnection(ClientMetadata client) { #region Add-to-Client-List if (!AddClient(client)) { Log("*** FinalizeConnection unable to add client " + client.IpPort); client.Dispose(); return; } // Do not decrement in this block, decrement is done by the connection reader int activeCount = Interlocked.Increment(ref _ActiveClients); #endregion #region Start-Data-Receiver Log("*** FinalizeConnection starting data receiver for " + client.IpPort + " (now " + activeCount + " clients)"); if (_ClientConnected != null) { Task.Run(() => _ClientConnected(client.IpPort)); } Task.Run(async() => await DataReceiver(client)); #endregion }
private async Task DataReceiver(ClientMetadata client) { try { #region Wait-for-Data while (true) { try { if (!IsConnected(client)) { break; } byte[] data = await MessageReadAsync(client); if (data == null) { // no message available await Task.Delay(30); continue; } if (_MessageReceived != null) { Task <bool> unawaited = Task.Run(() => _MessageReceived(client.IpPort, data)); } } catch (Exception) { break; } } #endregion } finally { int activeCount = Interlocked.Decrement(ref _ActiveClients); RemoveClient(client); if (_ClientDisconnected != null) { Task <bool> unawaited = Task.Run(() => _ClientDisconnected(client.IpPort)); } Log("*** DataReceiver client " + client.IpPort + " disconnected (now " + activeCount + " clients active)"); client.Dispose(); } }
private void FinalizeConnection(ClientMetadata client) { #region Add-to-Client-List if (!AddClient(client)) { Log("*** FinalizeConnection unable to add client " + client.IpPort); client.Dispose(); return; } // Do not decrement in this block, decrement is done by the connection reader int activeCount = Interlocked.Increment(ref _ActiveClients); #endregion #region Request-Authentication if (!String.IsNullOrEmpty(PresharedKey)) { Log("*** FinalizeConnection soliciting authentication material from " + client.IpPort); _UnauthenticatedClients.TryAdd(client.IpPort, DateTime.Now); byte[] data = Encoding.UTF8.GetBytes("Authentication required"); WatsonMessage authMsg = new WatsonMessage(); authMsg.Status = MessageStatus.AuthRequired; authMsg.Data = null; authMsg.ContentLength = 0; MessageWrite(client, authMsg, null); } #endregion #region Start-Data-Receiver Log("*** FinalizeConnection starting data receiver for " + client.IpPort + " (now " + activeCount + " clients)"); if (ClientConnected != null) { Task.Run(() => ClientConnected(client.IpPort)); } Task.Run(async() => await DataReceiver(client)); #endregion }
private async Task DataReceiver(ClientMetadata client, CancellationToken token) { string header = "[" + client.IpPort + "]"; while (true) { try { token.ThrowIfCancellationRequested(); if (!IsConnected(client)) { break; } WatsonMessage msg = null; bool buildSuccess = false; if (_Mode == Mode.Ssl) { msg = new WatsonMessage(client.SslStream, Debug); } else if (_Mode == Mode.Tcp) { msg = new WatsonMessage(client.NetworkStream, Debug); } if (_MessageReceived != null) { buildSuccess = await msg.Build(); } else if (_StreamReceived != null) { buildSuccess = await msg.BuildStream(); } else { break; } if (!buildSuccess) { break; } if (msg == null) { // no message available await Task.Delay(30); continue; } if (!String.IsNullOrEmpty(PresharedKey)) { if (_UnauthenticatedClients.ContainsKey(client.IpPort)) { Log(header + " message received from unauthenticated endpoint"); if (msg.Status == MessageStatus.AuthRequested) { // check preshared key if (msg.PresharedKey != null && msg.PresharedKey.Length > 0) { string clientPsk = Encoding.UTF8.GetString(msg.PresharedKey).Trim(); if (PresharedKey.Trim().Equals(clientPsk)) { Log(header + " accepted authentication"); _UnauthenticatedClients.TryRemove(client.IpPort, out DateTime dt); byte[] data = Encoding.UTF8.GetBytes("Authentication successful"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthSuccess; MessageWrite(client, authMsg, null); continue; } else { Log(header + " declined authentication"); byte[] data = Encoding.UTF8.GetBytes("Authentication declined"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthFailure; MessageWrite(client, authMsg, null); continue; } } else { Log(header + " no authentication material"); byte[] data = Encoding.UTF8.GetBytes("No authentication material"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthFailure; MessageWrite(client, authMsg, null); continue; } } else { // decline the message Log(header + " no authentication material"); byte[] data = Encoding.UTF8.GetBytes("Authentication required"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthRequired; MessageWrite(client, authMsg, null); continue; } } } if (msg.Status == MessageStatus.Disconnecting) { Log(header + " sent notification of disconnection"); break; } if (msg.Status == MessageStatus.Removed) { Log(header + " sent notification of removal"); break; } if (_MessageReceived != null) { // does not need to be awaited, because the stream has been fully read Task unawaited = Task.Run(() => _MessageReceived(client.IpPort, msg.Data)); } else if (_StreamReceived != null) { // must be awaited, the stream has not been fully read await _StreamReceived(client.IpPort, msg.ContentLength, msg.DataStream); } else { break; } UpdateClientLastSeen(client.IpPort); } catch (Exception e) { Log(Environment.NewLine + "[" + client.IpPort + "] Data receiver exception:" + Environment.NewLine + e.ToString() + Environment.NewLine); break; } } Log(header + " data receiver terminated"); if (ClientDisconnected != null) { Task unawaited = null; if (_ClientsKicked.ContainsKey(client.IpPort)) { unawaited = Task.Run(() => ClientDisconnected(client.IpPort, DisconnectReason.Kicked)); } else if (_ClientsTimedout.ContainsKey(client.IpPort)) { unawaited = Task.Run(() => ClientDisconnected(client.IpPort, DisconnectReason.Timeout)); } else { unawaited = Task.Run(() => ClientDisconnected(client.IpPort, DisconnectReason.Normal)); } } DateTime removedTs; _Clients.TryRemove(client.IpPort, out ClientMetadata removedClient); _ClientsLastSeen.TryRemove(client.IpPort, out removedTs); _ClientsKicked.TryRemove(client.IpPort, out removedTs); _ClientsTimedout.TryRemove(client.IpPort, out removedTs); _UnauthenticatedClients.TryRemove(client.IpPort, out removedTs); Log(header + " disposing"); client.Dispose(); }
private async Task DataReceiver(ClientMetadata client) { try { #region Wait-for-Data while (true) { try { if (!IsConnected(client)) { break; } WatsonMessage msg = await MessageReadAsync(client); if (msg == null) { // no message available await Task.Delay(30); continue; } if (!String.IsNullOrEmpty(PresharedKey)) { if (_UnauthenticatedClients.ContainsKey(client.IpPort)) { Log("*** DataReceiver message received from unauthenticated endpoint: " + client.IpPort); if (msg.Status == MessageStatus.AuthRequested) { // check preshared key if (msg.PresharedKey != null && msg.PresharedKey.Length > 0) { string clientPsk = Encoding.UTF8.GetString(msg.PresharedKey).Trim(); if (PresharedKey.Trim().Equals(clientPsk)) { if (Debug) { Log("DataReceiver accepted authentication from " + client.IpPort); } _UnauthenticatedClients.TryRemove(client.IpPort, out DateTime dt); byte[] data = Encoding.UTF8.GetBytes("Authentication successful"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthSuccess; MessageWrite(client, authMsg, null); continue; } else { if (Debug) { Log("DataReceiver declined authentication from " + client.IpPort); } byte[] data = Encoding.UTF8.GetBytes("Authentication declined"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthFailure; MessageWrite(client, authMsg, null); continue; } } else { if (Debug) { Log("DataReceiver no authentication material from " + client.IpPort); } byte[] data = Encoding.UTF8.GetBytes("No authentication material"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthFailure; MessageWrite(client, authMsg, null); continue; } } else { // decline the message if (Debug) { Log("DataReceiver no authentication material from " + client.IpPort); } byte[] data = Encoding.UTF8.GetBytes("Authentication required"); WatsonMessage authMsg = new WatsonMessage(data, Debug); authMsg.Status = MessageStatus.AuthRequired; MessageWrite(client, authMsg, null); continue; } } } if (ReadDataStream) { if (MessageReceived != null) { Task <bool> unawaited = Task.Run(() => MessageReceived(client.IpPort, msg.Data)); } } else { if (StreamReceived != null) { StreamReceived(client.IpPort, msg.ContentLength, msg.DataStream); } } } catch (Exception) { break; } } #endregion } finally { int activeCount = Interlocked.Decrement(ref _ActiveClients); RemoveClient(client); if (ClientDisconnected != null) { Task <bool> unawaited = Task.Run(() => ClientDisconnected(client.IpPort)); } Log("*** DataReceiver client " + client.IpPort + " disconnected (now " + activeCount + " clients active)"); client.Dispose(); } }