/// <summary> /// Callback method for asynchronous accept operation. /// </summary> private void ProcessAccept() { TransportProvider<Socket> client = new TransportProvider<Socket>(); SocketAsyncEventArgs receiveArgs = null; TcpClientInfo clientInfo; try { if (CurrentState == ServerState.NotRunning) return; if (m_acceptArgs.SocketError != SocketError.Success) { // Error is unrecoverable. // We need to make sure to restart the // server before we throw the error. SocketError error = m_acceptArgs.SocketError; ThreadPool.QueueUserWorkItem(state => ReStart()); throw new SocketException((int)error); } // Process the newly connected client. client.Provider = m_acceptArgs.AcceptSocket; // Set up SocketAsyncEventArgs for receive operations. receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); receiveArgs.Completed += ReceiveHandler; // Return to accepting new connections. m_acceptArgs.AcceptSocket = null; if (!m_tcpServer.AcceptAsync(m_acceptArgs)) { ThreadPool.QueueUserWorkItem(state => ProcessAccept()); } #if !MONO // Authenticate the connected client Windows credentials. if (m_integratedSecurity) { NetworkStream socketStream = null; NegotiateStream authenticationStream = null; try { socketStream = new NetworkStream(client.Provider); authenticationStream = new NegotiateStream(socketStream); authenticationStream.AuthenticateAsServer(); if (authenticationStream.RemoteIdentity is WindowsIdentity) Thread.CurrentPrincipal = new WindowsPrincipal((WindowsIdentity)authenticationStream.RemoteIdentity); } finally { if (socketStream != null) socketStream.Dispose(); if (authenticationStream != null) authenticationStream.Dispose(); } } #endif if (MaxClientConnections != -1 && ClientIDs.Length >= MaxClientConnections) { // Reject client connection since limit has been reached. TerminateConnection(client, receiveArgs, false); } else { // We can proceed further with receiving data from the client. clientInfo = new TcpClientInfo() { Client = client, SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(), SendLock = new SpinLock(), SendQueue = new ConcurrentQueue<TcpServerPayload>() }; // Set up socket args. client.SetSendBuffer(SendBufferSize); clientInfo.SendArgs.Completed += m_sendHandler; clientInfo.SendArgs.SetBuffer(client.SendBuffer, 0, client.SendBufferSize); m_clientInfoLookup.TryAdd(client.ID, clientInfo); OnClientConnected(client.ID); if (!m_payloadAware) { receiveArgs.UserToken = client; } else { EventArgs<TransportProvider<Socket>, bool> userToken = ReusableObjectPool<EventArgs<TransportProvider<Socket>, bool>>.Default.TakeObject(); userToken.Argument1 = client; receiveArgs.UserToken = userToken; } ReceivePayloadAsync(client, receiveArgs); } } catch (Exception ex) { // Notify of the exception. if ((object)client.Provider != null) { string clientAddress = ((IPEndPoint)client.Provider.RemoteEndPoint).Address.ToString(); string errorMessage = string.Format("Unable to accept connection to client [{0}]: {1}", clientAddress, ex.Message); OnClientConnectingException(new Exception(errorMessage, ex)); } if ((object)receiveArgs != null) { TerminateConnection(client, receiveArgs, false); } } }
/// <summary> /// Callback method for asynchronous connect operation. /// </summary> private void ProcessConnect() { try { // Perform post-connect operations. m_connectionAttempts++; if (m_connectArgs.SocketError != SocketError.Success) throw new SocketException((int)m_connectArgs.SocketError); #if !MONO // Send current Windows credentials for authentication. if (m_integratedSecurity) { NetworkStream socketStream = null; NegotiateStream authenticationStream = null; try { socketStream = new NetworkStream(m_tcpClient.Provider); authenticationStream = new NegotiateStream(socketStream); authenticationStream.AuthenticateAsClient(); } finally { if (socketStream != null) socketStream.Dispose(); if (authenticationStream != null) authenticationStream.Dispose(); } } #endif // Set up send and receive args. using (SocketAsyncEventArgs sendArgs = m_sendArgs, receiveArgs = m_receiveArgs) { m_sendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); m_receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); } m_tcpClient.SetSendBuffer(SendBufferSize); m_sendArgs.SetBuffer(m_tcpClient.SendBuffer, 0, m_tcpClient.SendBufferSize); m_sendArgs.Completed += m_sendHandler; m_receiveArgs.Completed += ReceiveHandler; // Notify user of established connection. m_connectWaitHandle.Set(); OnConnectionEstablished(); // Set up send buffer and begin receiving. ReceivePayloadAsync(); } catch (SocketException ex) { OnConnectionException(ex); if (ex.SocketErrorCode == SocketError.ConnectionRefused && (MaxConnectionAttempts == -1 || m_connectionAttempts < MaxConnectionAttempts)) { // Server is unavailable, so keep retrying connection to the server. try { ConnectAsync(); } catch { TerminateConnection(); } } else { // For any other reason, clean-up as if the client was disconnected. TerminateConnection(); } } catch (Exception ex) { // This is highly unlikely, but we must handle this situation just-in-case. OnConnectionException(ex); TerminateConnection(); } }
/// <summary> /// Callback method for asynchronous accept operation. /// </summary> private void ProcessAccept(SocketAsyncEventArgs acceptArgs) { TransportProvider<Socket> client = new TransportProvider<Socket>(); SocketAsyncEventArgs receiveArgs = null; WindowsPrincipal clientPrincipal = null; TcpClientInfo clientInfo; try { if (CurrentState == ServerState.NotRunning) return; // If acceptArgs was disposed, m_acceptArgs will either // be null or another instance of SocketAsyncEventArgs. // This check will tell us whether it's been disposed. if ((object)acceptArgs != m_acceptArgs) return; if (acceptArgs.SocketError != SocketError.Success) { // Error is unrecoverable. // We need to make sure to restart the // server before we throw the error. SocketError error = acceptArgs.SocketError; ThreadPool.QueueUserWorkItem(state => ReStart()); throw new SocketException((int)error); } // Process the newly connected client. client.Provider = acceptArgs.AcceptSocket; client.Provider.ReceiveBufferSize = ReceiveBufferSize; // Set up SocketAsyncEventArgs for receive operations. receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); receiveArgs.Completed += ReceiveHandler; // Return to accepting new connections. acceptArgs.AcceptSocket = null; if (!m_tcpServer.AcceptAsync(acceptArgs)) { ThreadPool.QueueUserWorkItem(state => ProcessAccept(acceptArgs)); } #if !MONO // Authenticate the connected client Windows credentials. if (m_integratedSecurity) { NetworkStream socketStream = null; NegotiateStream authenticationStream = null; try { socketStream = new NetworkStream(client.Provider); authenticationStream = new NegotiateStream(socketStream); authenticationStream.AuthenticateAsServer(); if (authenticationStream.RemoteIdentity is WindowsIdentity) clientPrincipal = new WindowsPrincipal((WindowsIdentity)authenticationStream.RemoteIdentity); } catch (InvalidCredentialException) { if (!m_ignoreInvalidCredentials) throw; } finally { if (socketStream != null) socketStream.Dispose(); if (authenticationStream != null) authenticationStream.Dispose(); } } #endif if (MaxClientConnections != -1 && ClientIDs.Length >= MaxClientConnections) { // Reject client connection since limit has been reached. TerminateConnection(client, receiveArgs, false); } else { // We can proceed further with receiving data from the client. clientInfo = new TcpClientInfo { Client = client, SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(), SendLock = new object(), SendQueue = new ConcurrentQueue<TcpServerPayload>(), ClientPrincipal = clientPrincipal }; // Create operation to dump send queue payloads when the queue grows too large. clientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() => { TcpServerPayload payload; // Check to see if the client has reached the maximum send queue size. if (m_maxSendQueueSize > 0 && clientInfo.SendQueue.Count >= m_maxSendQueueSize) { for (int i = 0; i < m_maxSendQueueSize; i++) { if (clientInfo.SendQueue.TryDequeue(out payload)) { payload.WaitHandle.Set(); payload.WaitHandle.Dispose(); payload.WaitHandle = null; } } throw new InvalidOperationException(string.Format("Client {0} connected to TCP server reached maximum send queue size. {1} payloads dumped from the queue.", clientInfo.Client.ID, m_maxSendQueueSize)); } }, ex => OnSendClientDataException(clientInfo.Client.ID, ex)); // Set up socket args. client.SetSendBuffer(SendBufferSize); clientInfo.SendArgs.Completed += m_sendHandler; clientInfo.SendArgs.SetBuffer(client.SendBuffer, 0, client.SendBufferSize); m_clientInfoLookup.TryAdd(client.ID, clientInfo); OnClientConnected(client.ID); if (!m_payloadAware) { receiveArgs.UserToken = client; } else { EventArgs<TransportProvider<Socket>, bool> userToken = FastObjectFactory<EventArgs<TransportProvider<Socket>, bool>>.CreateObjectFunction(); userToken.Argument1 = client; receiveArgs.UserToken = userToken; } ReceivePayloadAsync(client, receiveArgs); } } catch (ObjectDisposedException) { // m_acceptArgs may be disposed while in the middle of accepting a connection } catch (Exception ex) { // Notify of the exception. if ((object)client.Provider != null && (object)client.Provider.RemoteEndPoint != null) { string clientAddress = ((IPEndPoint)client.Provider.RemoteEndPoint).Address.ToString(); string errorMessage = string.Format("Unable to accept connection to client [{0}]: {1}", clientAddress, ex.Message); OnClientConnectingException(new Exception(errorMessage, ex)); } else { string errorMessage = string.Format("Unable to accept connection to client [unknown]: {0}", ex.Message); OnClientConnectingException(new Exception(errorMessage, ex)); } if ((object)receiveArgs != null) { TerminateConnection(client, receiveArgs, false); } } }