/// <summary> /// Callback method for asynchronous receive operation of handshake data. /// </summary> private void ReceiveHandshakeAsyncCallback(IAsyncResult asyncResult) { TransportProvider<Socket> udpServer = (TransportProvider<Socket>)asyncResult.AsyncState; // Received handshake data from client so we'll process it. try { // Update statistics and pointers. EndPoint client = Transport.CreateEndPoint(string.Empty, 0); udpServer.Statistics.UpdateBytesReceived(udpServer.Provider.EndReceiveFrom(asyncResult, ref client)); udpServer.ReceiveBufferLength = udpServer.Statistics.LastBytesReceived; // Process the received handshake message. Payload.ProcessReceived(ref udpServer.ReceiveBuffer, ref udpServer.ReceiveBufferOffset, ref udpServer.ReceiveBufferLength, Encryption, HandshakePassphrase, Compression); HandshakeMessage handshake = new HandshakeMessage(); if (handshake.Initialize(udpServer.ReceiveBuffer, udpServer.ReceiveBufferOffset, udpServer.ReceiveBufferLength) != -1) { // Received handshake message could be parsed successfully. if (handshake.ID != Guid.Empty && handshake.Passphrase == HandshakePassphrase) { // Create a random socket and connect it to the client. TransportProvider<Socket> udpClient = new TransportProvider<Socket>(); udpClient.ReceiveBuffer = new byte[ReceiveBufferSize]; udpClient.Passphrase = HandshakePassphrase; udpClient.Provider = Transport.CreateSocket(0, ProtocolType.Udp); udpClient.Provider.Connect(client); // Authentication is successful; respond to the handshake. udpClient.ID = handshake.ID; handshake.ID = this.ServerID; if (SecureSession) { // Create a secret key for ciphering client data. udpClient.Passphrase = Cipher.GenerateKey(260); handshake.Passphrase = udpClient.Passphrase; } // Prepare binary image of handshake response to be transmitted. udpClient.SendBuffer = handshake.BinaryImage; udpClient.SendBufferOffset = 0; udpClient.SendBufferLength = udpClient.SendBuffer.Length; Payload.ProcessTransmit(ref udpClient.SendBuffer, ref udpClient.SendBufferOffset, ref udpClient.SendBufferLength, Encryption, HandshakePassphrase, Compression); // Transmit the prepared and processed handshake response message. udpClient.Provider.SendTo(udpClient.SendBuffer, udpClient.Provider.RemoteEndPoint); // Handshake process is complete and client is considered connected. lock (m_udpClients) { m_udpClients.Add(udpClient.ID, udpClient); } OnClientConnected(udpClient.ID); ReceiveHandshakeAsync(udpServer); try { ReceivePayloadOneAsync(udpClient); } catch { // Receive will fail if client disconnected before handshake is complete. TerminateConnection(udpClient, true); } } else { // Authentication during handshake failed, so we terminate the client connection. TerminateConnection(udpServer, false); OnHandshakeProcessUnsuccessful(); } } else { // Handshake message could not be parsed, so we terminate the client connection. TerminateConnection(udpServer, false); OnHandshakeProcessUnsuccessful(); } } catch { // Server socket has been terminated. udpServer.Reset(); OnServerStopped(); } }
/// <summary> /// Callback method for asynchronous receive operation of handshake data. /// </summary> private void ReceiveHandshakeAsyncCallback(IAsyncResult asyncResult) { TransportProvider<Socket> udpClient = (TransportProvider<Socket>)asyncResult.AsyncState; if (!asyncResult.IsCompleted) { // Handshake response is not recevied in a timely fashion. TerminateConnection(udpClient, false); OnHandshakeProcessTimeout(); } else { // Received handshake response from server so we'll process it. try { // Update statistics and pointers. udpClient.Statistics.UpdateBytesReceived(udpClient.Provider.EndReceiveFrom(asyncResult, ref m_udpServer)); udpClient.ReceiveBufferLength = udpClient.Statistics.LastBytesReceived; // Process the received handshake response message. Payload.ProcessReceived(ref udpClient.ReceiveBuffer, ref udpClient.ReceiveBufferOffset, ref udpClient.ReceiveBufferLength, Encryption, HandshakePassphrase, Compression); HandshakeMessage handshake = new HandshakeMessage(); if (handshake.Initialize(udpClient.ReceiveBuffer, udpClient.ReceiveBufferOffset, udpClient.ReceiveBufferLength) != -1) { // Received handshake response message could be parsed. this.ServerID = handshake.ID; udpClient.Passphrase = handshake.Passphrase; // Client is now considered to be connected to the server. OnConnectionEstablished(); ReceivePayloadAsync(udpClient); } else { // Received handshake response message could not be parsed. TerminateConnection(udpClient, false); OnHandshakeProcessUnsuccessful(); } } catch { // This is most likely because the server forcibly disconnected the client. TerminateConnection(udpClient, false); OnHandshakeProcessUnsuccessful(); } } }
/// <summary> /// Callback method for asynchronous receive operation of handshake data. /// </summary> private void ReceiveHandshakeAsyncCallback(IAsyncResult asyncResult) { TransportProvider<Socket> tcpClient = (TransportProvider<Socket>)asyncResult.AsyncState; if (!asyncResult.IsCompleted) { // Handshake didn't complete in a timely fashion. TerminateConnection(tcpClient, false); OnHandshakeProcessTimeout(); } else { // Received handshake data from client so we'll process it. try { // Update statistics and pointers. tcpClient.Statistics.UpdateBytesReceived(tcpClient.Provider.EndReceive(asyncResult)); tcpClient.ReceiveBufferLength = tcpClient.Statistics.LastBytesReceived; if (tcpClient.Statistics.LastBytesReceived == 0) // Client disconnected gracefully. throw new SocketException((int)SocketError.Disconnecting); // Process the received handshake message. Payload.ProcessReceived(ref tcpClient.ReceiveBuffer, ref tcpClient.ReceiveBufferOffset, ref tcpClient.ReceiveBufferLength, Encryption, HandshakePassphrase, Compression); HandshakeMessage handshake = new HandshakeMessage(); if (handshake.Initialize(tcpClient.ReceiveBuffer, tcpClient.ReceiveBufferOffset, tcpClient.ReceiveBufferLength) != -1) { // Received handshake message could be parsed successfully. if (handshake.ID != Guid.Empty && handshake.Passphrase == HandshakePassphrase) { // Authentication is successful; respond to the handshake. tcpClient.ID = handshake.ID; handshake.ID = this.ServerID; if (SecureSession) { // Create a secret key for ciphering client data. tcpClient.Passphrase = Cipher.GenerateKey(260); handshake.Passphrase = tcpClient.Passphrase; } // Prepare binary image of handshake response to be transmitted. tcpClient.SendBuffer = handshake.BinaryImage; tcpClient.SendBufferOffset = 0; tcpClient.SendBufferLength = tcpClient.SendBuffer.Length; Payload.ProcessTransmit(ref tcpClient.SendBuffer, ref tcpClient.SendBufferOffset, ref tcpClient.SendBufferLength, Encryption, HandshakePassphrase, Compression); // Transmit the prepared and processed handshake response message. tcpClient.Provider.Send(tcpClient.SendBuffer); // Handshake process is complete and client is considered connected. lock (m_tcpClients) { m_tcpClients.Add(tcpClient.ID, tcpClient); } OnClientConnected(tcpClient.ID); ReceivePayloadAsync(tcpClient); } else { // Authentication during handshake failed, so we terminate the client connection. TerminateConnection(tcpClient, false); OnHandshakeProcessUnsuccessful(); } } else { // Handshake message could not be parsed, so we terminate the client connection. TerminateConnection(tcpClient, false); OnHandshakeProcessUnsuccessful(); } } catch { // Handshake process could not be completed most likely due to client disconnect. TerminateConnection(tcpClient, false); OnHandshakeProcessUnsuccessful(); } } }
/// <summary> /// Connects the <see cref="UdpClient"/> to the server asynchronously. /// </summary> /// <exception cref="FormatException">Server property in <see cref="ClientBase.ConnectionString"/> is invalid.</exception> /// <exception cref="InvalidOperationException">Attempt is made to connect the <see cref="UdpClient"/> when it is not disconnected.</exception> public override void ConnectAsync() { if (CurrentState == ClientState.Disconnected) { // Initialize if unitialized. Initialize(); m_udpClient = new TransportProvider<Socket>(); m_udpClient.ID = this.ClientID; m_udpClient.Passphrase = HandshakePassphrase; m_udpClient.ReceiveBuffer = new byte[ReceiveBufferSize]; // Create a server endpoint. if (m_connectData.ContainsKey("server")) { // Client has a server endpoint specified. string[] parts = m_connectData["server"].Split(':'); if (parts.Length == 2) { m_udpServer = Transport.CreateEndPoint(parts[0], int.Parse(parts[1])); } else { throw new FormatException(string.Format("Server property in ConnectionString is invalid. Example: {0}.", DefaultConnectionString)); } } else { if (Handshake) throw new InvalidOperationException("Handshake requires Server property in the ConnectionString."); // Create a random server endpoint since one is not specified. m_udpServer = Transport.CreateEndPoint(string.Empty, 0); } if (Handshake) { // Handshaking must be performed. m_receivedGoodbye = DoGoodbyeCheck; HandshakeMessage handshake = new HandshakeMessage(); handshake.ID = this.ClientID; handshake.Passphrase = this.HandshakePassphrase; // Prepare binary image of handshake to be transmitted. m_udpClient.Provider = Transport.CreateSocket(0, ProtocolType.Udp); m_udpClient.SendBuffer = handshake.BinaryImage; m_udpClient.SendBufferOffset = 0; m_udpClient.SendBufferLength = m_udpClient.SendBuffer.Length; Payload.ProcessTransmit(ref m_udpClient.SendBuffer, ref m_udpClient.SendBufferOffset, ref m_udpClient.SendBufferLength, Encryption, HandshakePassphrase, Compression); // Initialiate handshake process from a seperate thread. new Thread((ThreadStart)delegate() { int connectionAttempts = 0; while (true) { try { connectionAttempts++; OnConnectionAttempt(); // Transmit the prepared and processed handshake message. m_udpClient.Provider.SendTo(m_udpClient.SendBuffer, m_udpServer); // Wait for the server's reponse to the handshake message. Thread.Sleep(1000); ReceiveHandshakeAsync(m_udpClient); break; } catch (SocketException ex) { OnConnectionException(ex); if (ex.SocketErrorCode == SocketError.ConnectionReset && (MaxConnectionAttempts == -1 || connectionAttempts < MaxConnectionAttempts)) { // Server is unavailable, so keep retrying connection to the server. continue; } else { // For any other reason, clean-up as if the client was disconnected. TerminateConnection(m_udpClient, false); break; } } catch (Exception ex) { // This is highly unlikely, but we must handle this situation just-in-case. OnConnectionException(ex); TerminateConnection(m_udpClient, false); break; } } }).Start(); } else { // Disable SocketError.ConnectionReset exception from being thrown when the enpoint is not listening. m_udpClient.Provider = Transport.CreateSocket(int.Parse(m_connectData["port"]), ProtocolType.Udp); m_udpClient.Provider.IOControl(SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null); OnConnectionAttempt(); m_receivedGoodbye = NoGoodbyeCheck; OnConnectionEstablished(); ReceivePayloadAsync(m_udpClient); } } else { throw new InvalidOperationException("Client is currently not disconnected."); } }