public bool UpdateConnection(NetConnection connection) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (connection.ProtocolState != ProtocolState.Closing) { return(true); } bool connected = connection.Socket.Connected; if (!connected || connection.SendBuffer.Length == 0) { lock (ConnectionMutex) { if (!_connections.Remove(connection)) { throw new InvalidOperationException(); } } // There won't be a queue if there was no packet send attempt during connection. if (Orchestrator.PacketSendQueues.TryRemove(connection, out var removedQueue)) { // There may be packet holders queued if the socket gets // closed before everything is sent. // The orchestrator should empty the queue. Orchestrator.QueuesToFlush.Enqueue(removedQueue); } connection.Close(immediate: true); } return(false); }
/// <summary> /// Connection flow/lifetime: /// Every connection begins in <see cref="EngageClientConnection"/>, where a loop reads /// asynchrounsly from the client socket. /// Successful reads get copied to the connection's receive buffer. /// </summary> public async Task EngageClientConnection(NetConnection connection, CancellationToken cancellationToken) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } var readBuffer = new byte[1024 * 4]; // Clients don't really need a big read buffer. var readMemory = readBuffer.AsMemory(); var socket = connection.Socket; var receiveBuffer = connection.ReceiveBuffer; var state = new ReceiveState( connection, new NetBinaryReader(receiveBuffer), cancellationToken); try { int read; while ((read = await socket.ReceiveAsync( readMemory, SocketFlags.None, state.CancellationToken).Unchain()) != 0) { // Insert received data into beginning of receive buffer. var readSlice = readMemory.Slice(0, read); receiveBuffer.Seek(0, SeekOrigin.End); receiveBuffer.Write(readSlice.Span); receiveBuffer.Seek(0, SeekOrigin.Begin); connection.BytesReceived += readSlice.Length; // We process by the message length (unless it's a legacy server list ping), // so don't worry if we received parts of the next message. OperationStatus handleStatus; while ((handleStatus = HandlePacket(ref state)) == OperationStatus.Done) { if (!connection.IsAlive) { break; } } if (!connection.IsAlive) { break; } receiveBuffer.TrimStart((int)receiveBuffer.Position); } } catch (SocketException sockEx) when(sockEx.SocketErrorCode == SocketError.ConnectionReset) { // TODO: increment statistic? } catch (SocketException sockEx) when(sockEx.SocketErrorCode == SocketError.ConnectionAborted) { Console.WriteLine("Connection aborted for " + connection.RemoteEndPoint); // TODO: increment statistic? } catch (Exception ex) { Console.WriteLine(ex); connection.Kick(ex); return; } connection.Close(immediate: false); }