/// <summary> /// Runs when data is received from a client. Parses the information and sends it off /// to a method to handle the information. /// </summary> /// <param name="asyncResult">Result containing the client info</param> public void DataReceivedCallback(IAsyncResult asyncResult) { ClientInfo client = (ClientInfo)asyncResult.AsyncState; try { var readBytes = _usingSsl ? client._clientSslStream.EndRead(asyncResult) : client.ClientSocket().EndReceive(asyncResult); client.ClientStringBuilder().Append(Encoding.ASCII.GetString(client.DataBuffer(), 0, readBytes));// Add on the new data string currentData = client.ClientStringBuilder().ToString(); int position; while ((position = currentData.IndexOf("<EOF>", StringComparison.Ordinal)) != -1)// Keep going until we don't have any more commands { string command = currentData.Substring(0, position); Console.WriteLine($"<{client._username}> {command}"); currentData = currentData.Remove(0, position + 5); // Remove the command from the currentData string HelperMethods.CommandHandler(command, client); // Handle the command } client.ClientStringBuilder().Clear(); // We used the data in the string builder so now we can clear it client.ClientStringBuilder().Append(currentData); // There still might be some data left so we add it back in client.BeginReceiveData(); // Continue receiving data } catch (ObjectDisposedException) { Console.WriteLine("DataReceivedCallback(): Socket was closed before finishing receive"); } catch (SocketException se) { if (se.ErrorCode == 10054)// Connection reset by peer. { Console.WriteLine($"DataReceivedCallback(): Client went offline"); } else { Console.WriteLine($"DataReceivedCallback(): {se.Message} Error Code: {se.ErrorCode}"); } HelperMethods.RemoveClientFromAll(client); } catch (IOException ioe) { if (ioe.InnerException is SocketException se) { if (se.ErrorCode == 10054)// Connection reset by peer. { Console.WriteLine($"DataReceivedCallback(): Client went offline"); } } else { Console.WriteLine($"DataReceivedCallback(): {ioe.Message}"); } HelperMethods.RemoveClientFromAll(client); } catch (Exception e) { Console.WriteLine($"DataReceivedCallbackSsl(): {e.Message}"); if (e.InnerException != null) { Console.WriteLine($"DataReceivedCallbackSsl(): {e.InnerException}"); } HelperMethods.RemoveClientFromAll(client); } }
/// <summary> /// Runs on a new client connection, and sets a client id and adds to list of clients. /// </summary> /// <param name="asyncResult">Result from connection containing socket to client</param> public static void ClientConnectCallback(IAsyncResult asyncResult) { try { Socket clientSocket = Globals.Listener.EndAccept(asyncResult); NetworkStream networkStream = new NetworkStream(clientSocket); SslStream sslStream = new SslStream(networkStream, false); // Authenticate the server but don't require the client to authenticate. try { sslStream.AuthenticateAsServer(Globals.ServerCertificate, false, true); // Display the properties and settings for the authenticated stream. HelperMethods.DisplaySecurityLevel(sslStream); HelperMethods.DisplaySecurityServices(sslStream); HelperMethods.DisplayCertificateInformation(sslStream); HelperMethods.DisplayStreamProperties(sslStream); // Set timeouts to 5 seconds. sslStream.ReadTimeout = 5000; sslStream.WriteTimeout = 5000; } catch (AuthenticationException e) { Console.WriteLine($"Exception: {e.Message}"); if (e.InnerException != null) { Console.WriteLine($"Inner exception: {e.InnerException.Message}"); } Console.WriteLine("Authentication failed - closing the connection."); sslStream.Close(); clientSocket.Close(); Globals.Listener.BeginAccept(ClientConnectCallback, null);// keep listening return; } catch (Exception e) { Console.WriteLine($"Exception: {e.Message}"); sslStream.Close(); clientSocket.Close(); Globals.Listener.BeginAccept(ClientConnectCallback, null);// keep listening return; } byte[] clientId = new byte[10]; Globals.Random.NextBytes(clientId); string idString = clientId.Aggregate("", (current, idByte) => current + idByte); // Keep trying until we get a username that isn't taken while (HelperMethods.UsernameTaken(idString)) { Globals.Random.NextBytes(clientId); idString = clientId.Aggregate("", (current, idByte) => current + idByte); } ClientInfo newClient = new ClientInfo(clientSocket, sslStream, networkStream); newClient.SetUsername(idString);// Set the default username to the randomly generated byte id Globals.ClientList.Add(newClient); Console.WriteLine($"Client {newClient.GetUsername()} connected"); newClient.BeginReceiveData(); Globals.Listener.BeginAccept(ClientConnectCallback, null); } catch (ObjectDisposedException) { Console.WriteLine("ClientConnectCallback(): Object already disposed"); } catch (SocketException se) { Console.WriteLine(se.Message); } }