/// <summary> /// Start the server (synchronous) /// </summary> /// <returns>'true' if the server was successfully started, 'false' if the server failed to start</returns> public override Boolean Start() { if (IsStarted) { return(false); } // Setup buffers _receiveBuffer = new NetworkDataBuffer(); _sendBuffer = new NetworkDataBuffer(); // Setup event args _receiveEventArg = new SocketAsyncEventArgs(); _receiveEventArg.Completed += OnAsyncCompleted; _sendEventArg = new SocketAsyncEventArgs(); _sendEventArg.Completed += OnAsyncCompleted; // Create a new server socket Socket = new Socket(Endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); // Update the server socket disposed flag IsSocketDisposed = false; // Apply the option: reuse address Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, OptionReuseAddress); // Apply the option: exclusive address use Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, OptionExclusiveAddressUse); // Apply the option: dual mode (this option must be applied before recieving) if (Socket.AddressFamily == AddressFamily.InterNetworkV6) { Socket.DualMode = OptionDualMode; } // Bind the server socket to the IP endpoint Socket.Bind(Endpoint); // Refresh the endpoint property based on the actual endpoint created Endpoint = (IPEndPoint)Socket.LocalEndPoint; // Prepare receive endpoint _receiveEndpoint = new IPEndPoint(Endpoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); // Prepare receive & send buffers _receiveBuffer.Reserve(OptionReceiveBufferSize); // Reset statistic BytesPending = 0; BytesSending = 0; BytesSent = 0; BytesReceived = 0; DatagramsSent = 0; DatagramsReceived = 0; // Update the started flag IsStarted = true; // Call the server started handler OnStarted(); return(true); }
/// <summary> /// This method is invoked when an asynchronous receive operation completes /// </summary> private void ProcessReceive(IAsyncResult result) { try { if (!IsHandshaked) { return; } // Validate SSL stream Id Guid?sslStreamId = result.AsyncState as Guid?; if (_sslStreamId != sslStreamId) { return; } // End the SSL read Int64 size = _sslStream.EndRead(result); // Received some data from the client if (size > 0) { // Update statistic BytesReceived += size; Interlocked.Add(ref Server.bytesReceived, size); // Call the buffer received handler OnReceived(_receiveBuffer.Data, 0, size); // If the receive buffer is full increase its size if (_receiveBuffer.Capacity == size) { _receiveBuffer.Reserve(2 * size); } } receiving = false; // If zero is returned from a read operation, the remote end has closed the connection if (size > 0) { if (!result.CompletedSynchronously) { TryReceive(); } } else { Disconnect(); } } catch (Exception) { SendError(SocketError.OperationAborted); Disconnect(); } }
/// <summary> /// This method is invoked when an asynchronous receive operation completes /// </summary> private Boolean ProcessReceive(SocketAsyncEventArgs e) { if (!IsConnected) { return(false); } Int64 size = e.BytesTransferred; // Received some data from the client if (size > 0) { // Update statistic BytesReceived += size; Interlocked.Add(ref Server.bytesReceived, size); // Call the buffer received handler OnReceived(_receiveBuffer.Data, 0, size); // If the receive buffer is full increase its size if (_receiveBuffer.Capacity == size) { _receiveBuffer.Reserve(2 * size); } } receiving = false; // Try to receive again if the session is valid if (e.SocketError == SocketError.Success) { // If zero is returned from a read operation, the remote end has closed the connection if (size > 0) { return(true); } Disconnect(); } else { SendError(e.SocketError); Disconnect(); } return(false); }
/// <summary> /// This method is invoked when an asynchronous receive from operation completes /// </summary> private void ProcessReceiveFrom(SocketAsyncEventArgs e) { _receiving = false; if (!IsStarted) { return; } // Check for error if (e.SocketError != SocketError.Success) { SendError(e.SocketError); // Call the datagram received zero handler OnReceived(e.RemoteEndPoint, _receiveBuffer.Data, 0, 0); return; } Int64 size = e.BytesTransferred; // Received some data from the client if (size <= 0) { return; } // Update statistic DatagramsReceived++; BytesReceived += size; // Call the datagram received handler OnReceived(e.RemoteEndPoint, _receiveBuffer.Data, 0, size); // If the receive buffer is full increase its size if (_receiveBuffer.Capacity == size) { _receiveBuffer.Reserve(2 * size); } }
/// <summary> /// Connect the session /// </summary> /// <param name="socket">Session socket</param> public override void Connect(Socket socket) { if (IsConnected) { throw new AlreadyInitializedException("Already connected"); } Socket = socket; // Update the session socket disposed flag IsSocketDisposed = false; // Setup buffers _receiveBuffer = new NetworkDataBuffer(); sendBufferMain = new NetworkDataBuffer(); sendBufferFlush = new NetworkDataBuffer(); // Apply the option: keep alive if (Server.OptionKeepAlive) { Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); } // Apply the option: no delay if (Server.OptionNoDelay) { Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); } // Prepare receive & send buffers _receiveBuffer.Reserve(OptionReceiveBufferSize); sendBufferMain.Reserve(OptionSendBufferSize); sendBufferFlush.Reserve(OptionSendBufferSize); // Reset statistic BytesPending = 0; BytesSending = 0; BytesSent = 0; BytesReceived = 0; // Update the connected flag IsConnected = true; // Call the session connected handler OnConnected(); // Call the session connected handler in the server Server.OnConnectedInternal(this); try { // Create SSL stream _sslStreamId = Guid.NewGuid(); _sslStream = Server.Context.CertificateValidationCallback is not null ? new SslStream(new NetworkStream(Socket, false), false, Server.Context.CertificateValidationCallback) : new SslStream(new NetworkStream(Socket, false), false); // Begin the SSL handshake _sslStream.BeginAuthenticateAsServer(Server.Context.Certificate, Server.Context.ClientCertificateRequired, Server.Context.Protocols, false, ProcessHandshake, _sslStreamId); } catch (Exception) { SendError(SocketError.NotConnected); Disconnect(); } }
/// <summary> /// Connect the client (synchronous) /// </summary> /// <remarks> /// Please note that synchronous connect will not receive data automatically! /// You should use Receive() or ReceiveAsync() method manually after successful connection. /// </remarks> /// <returns>'true' if the client was successfully connected, 'false' if the client failed to connect</returns> public override Boolean Connect() { if (IsConnected || IsHandshaked || IsConnecting || IsHandshaking) { return(false); } // Setup buffers receiveBuffer = new NetworkDataBuffer(); sendBufferMain = new NetworkDataBuffer(); sendBuffer = new NetworkDataBuffer(); // Setup event args connectEventArg = new SocketAsyncEventArgs { RemoteEndPoint = Endpoint }; connectEventArg.Completed += OnAsyncCompleted; // Create a new client socket Socket = new Socket(Endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Apply the option: dual mode (this option must be applied before connecting) if (Socket.AddressFamily == AddressFamily.InterNetworkV6) { Socket.DualMode = OptionDualMode; } try { // Connect to the server Socket.Connect(Endpoint); } catch (SocketException ex) { // Close the client socket Socket.Close(); // Dispose the client socket Socket.Dispose(); // Dispose event arguments connectEventArg.Dispose(); // Call the client disconnected handler SendError(ex.SocketErrorCode); OnDisconnected(); return(false); } // Update the client socket disposed flag IsSocketDisposed = false; // Apply the option: keep alive if (OptionKeepAlive) { Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); } // Apply the option: no delay if (OptionNoDelay) { Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); } // Prepare receive & send buffers receiveBuffer.Reserve(OptionReceiveBufferSize); sendBufferMain.Reserve(OptionSendBufferSize); sendBuffer.Reserve(OptionSendBufferSize); // Reset statistic BytesPending = 0; BytesSending = 0; BytesSent = 0; BytesReceived = 0; // Update the connected flag IsConnected = true; // Call the client connected handler OnConnected(); try { // Create SSL stream _sslStreamId = Guid.NewGuid(); _sslStream = Context.CertificateValidationCallback is not null ? new SslStream(new NetworkStream(Socket, false), false, Context.CertificateValidationCallback) : new SslStream(new NetworkStream(Socket, false), false); // SSL handshake _sslStream.AuthenticateAsClient(Address, Context.Certificates ?? new X509CertificateCollection(new[] { Context.Certificate }), Context.Protocols, true); } catch (Exception) { SendError(SocketError.NotConnected); DisconnectAsync(); return(false); } // Update the handshaked flag IsHandshaked = true; // Call the session handshaked handler OnHandshaked(); // Call the empty send buffer handler if (sendBufferMain.IsEmpty) { OnEmpty(); } return(true); }
/// <summary> /// Connect the client (synchronous) /// </summary> /// <remarks> /// Please note that synchronous connect will not receive data automatically! /// You should use Receive() or ReceiveAsync() method manually after successful connection. /// </remarks> /// <returns>'true' if the client was successfully connected, 'false' if the client failed to connect</returns> public override Boolean Connect() { if (IsConnected || IsConnecting) { return(false); } // Setup buffers receiveBuffer = new NetworkDataBuffer(); sendBufferMain = new NetworkDataBuffer(); sendBuffer = new NetworkDataBuffer(); // Setup event args connectEventArg = new SocketAsyncEventArgs { RemoteEndPoint = Endpoint }; connectEventArg.Completed += OnAsyncCompleted; _receiveEventArg = new SocketAsyncEventArgs(); _receiveEventArg.Completed += OnAsyncCompleted; _sendEventArg = new SocketAsyncEventArgs(); _sendEventArg.Completed += OnAsyncCompleted; // Create a new client socket Socket = new Socket(Endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Apply the option: dual mode (this option must be applied before connecting) if (Socket.AddressFamily == AddressFamily.InterNetworkV6) { Socket.DualMode = OptionDualMode; } try { // Connect to the server Socket.Connect(Endpoint); } catch (SocketException ex) { // Close the client socket Socket.Close(); // Dispose the client socket Socket.Dispose(); // Dispose event arguments connectEventArg.Dispose(); _receiveEventArg.Dispose(); _sendEventArg.Dispose(); // Call the client disconnected handler SendError(ex.SocketErrorCode); OnDisconnected(); return(false); } // Update the client socket disposed flag IsSocketDisposed = false; // Apply the option: keep alive if (OptionKeepAlive) { Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); } // Apply the option: no delay if (OptionNoDelay) { Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); } // Prepare receive & send buffers receiveBuffer.Reserve(OptionReceiveBufferSize); sendBufferMain.Reserve(OptionSendBufferSize); sendBuffer.Reserve(OptionSendBufferSize); // Reset statistic BytesPending = 0; BytesSending = 0; BytesSent = 0; BytesReceived = 0; // Update the connected flag IsConnected = true; // Call the client connected handler OnConnected(); // Call the empty send buffer handler if (sendBufferMain.IsEmpty) { OnEmpty(); } return(true); }
/// <summary> /// Connect the session /// </summary> /// <param name="socket">Session socket</param> public override void Connect(Socket socket) { if (IsConnected) { throw new AlreadyInitializedException("Already connected"); } Socket = socket; // Update the session socket disposed flag IsSocketDisposed = false; // Setup buffers _receiveBuffer = new NetworkDataBuffer(); sendBufferMain = new NetworkDataBuffer(); sendBufferFlush = new NetworkDataBuffer(); // Setup event args _receiveEventArg = new SocketAsyncEventArgs(); _receiveEventArg.Completed += OnAsyncCompleted; _sendEventArg = new SocketAsyncEventArgs(); _sendEventArg.Completed += OnAsyncCompleted; // Apply the option: keep alive if (Server.OptionKeepAlive) { Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); } // Apply the option: no delay if (Server.OptionNoDelay) { Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); } // Prepare receive & send buffers _receiveBuffer.Reserve(OptionReceiveBufferSize); sendBufferMain.Reserve(OptionSendBufferSize); sendBufferFlush.Reserve(OptionSendBufferSize); // Reset statistic BytesPending = 0; BytesSending = 0; BytesSent = 0; BytesReceived = 0; // Update the connected flag IsConnected = true; // Call the session connected handler OnConnected(); // Call the session connected handler in the server Server.OnConnectedInternal(this); // Call the empty send buffer handler if (sendBufferMain.IsEmpty) { OnEmpty(); } // Try to receive something from the client TryReceive(); }