/// <summary> /// Reads a packet from a stream, decrypting it. This method blocks until a packet (which can be null) is read. /// </summary> /// <param name="stream">The stream to read from.</param> /// <param name="rsa">The RSA encryption object used for secure communication.</param> /// <returns>See summary.</returns> /// <exception cref="ArgumentNullException"><paramref name="stream"/> is <c>null</c> -or- <paramref name="rsa"/> is <c>null</c>.</exception> public static Packet ReadFromStream(BinaryReader stream, RsaEncryption rsa) { if (stream == null || rsa == null) { throw new ArgumentNullException(stream == null ? "stream" : "rsa"); } byte[] data = Packet.ReadBytesFromStream(stream); if (data != null) { return SerializationHelper.DeserializeBytes<Packet>(rsa.Decrypt(data)); } return null; }
/// <summary> /// Initializes a new instance of the <see cref="NetworkServerHandler"/> class. /// </summary> /// <param name="connection">The TCP client object describing the client's binding to the server.</param> /// <param name="serverRsa">The server's RSA encryption utility instance.</param> /// <param name="authenticationRequired">Whether authentication is required.</param> /// <exception cref="ArgumentException">The stream does not support reading, the stream is null, or the stream is already closed.</exception> /// <exception cref="InvalidOperationException">The client is not connected to a remote host or has been disposed.</exception> internal NetworkServerHandler(TcpClient connection, RsaEncryption serverRsa, bool authenticationRequired) { this.connection = connection; this.serverRsa = serverRsa; try { this.binaryReader = new BinaryReader(connection.GetStream()); this.binaryWriter = new BinaryWriter(connection.GetStream()); } catch (ArgumentException e) { throw e; } catch (InvalidOperationException e) { throw e; } // Send the server's public key to the client this.SendPacket(new ServerInitPacket(this.serverRsa.PublicKey, this.authenticationRequired = authenticationRequired)); new Thread(this.Run).Start(); }
/// <summary> /// Writes the packet to a stream through which serialized data is being passed, and encrypts it. /// </summary> /// <param name="stream">The stream to write to.</param> /// <param name="rsa">The RSA encryption object used for secure communication.</param> /// <returns>A value indicating whether the packet was sent successfully.</returns> /// <exception cref="ArgumentNullException"><paramref name="stream"/> is <c>null</c> -or- <paramref name="rsa"/> is <c>null</c>.</exception> public bool WriteToStream(BinaryWriter stream, RsaEncryption rsa) { if (stream == null || rsa == null) { throw new ArgumentNullException(stream == null ? "stream" : "rsa"); } return this.WriteToStream(stream, rsa.Encrypt(SerializationHelper.SerializeBytes(this))); }
/// <summary> /// Begins the infinite loop of the client's data listener. /// </summary> private void Run() { Monitor.Enter(this); // Only run if not already running and object hasn't been destroyed if (!this.running && !this.Disposed) { this.running = true; Monitor.Exit(this); Thread.CurrentThread.Name = "Listener Thread"; while (this.running && !this.Disposed && this.connection.Connected) { try { Packet packet = this.clientRsa != null ? Packet.ReadFromStream(this.binaryReader, this.serverRsa) : Packet.ReadFromStream(this.binaryReader); ClientInitPacket init = packet as ClientInitPacket; if (init != null) { this.clientRsa = new RsaEncryption(init.PublicKey); continue; } AuthenticationPacket auth = packet as AuthenticationPacket; if (auth != null) { ClientAuthenticatingEventArgs e = new ClientAuthenticatingEventArgs(auth.UserId, auth.Password); this.ClientAuthenticating(this, e); this.SendPacket(new AuthenticationResultPacket(e.AuthenticationResult)); continue; } this.PacketReceived(this, new PacketEventArgs(this, packet)); } catch (Exception e) { // If there was an exception, disconnect the client Console.WriteLine(e); this.Dispose(); return; } } this.Dispose(); } }