public TcpConnection(TcpPeer parent) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } this.latencySimulationRecvQueue = new ConcurrentQueue <DelayedMessage>(); this.stashed = true; this.Statistics = new TcpConnectionStatistics(); this.sendSemaphore = new SemaphoreSlim(1, 1); this.recvBuffer = new byte[parent.Configuration.BufferSize]; this.sendBuffer = new byte[parent.Configuration.BufferSize]; this.awaitingMessageHeader = new TcpRawMessageHeader(); this.Parent = parent; this.logger = parent.Configuration.LogManager.GetLogger(nameof(TcpConnection)); this.logger.Meta["kind"] = this.GetType().Name; this.logger.Meta["connection_endpoint"] = new RefLogLabel <TcpConnection>(this, v => v.RemoteEndpoint); this.logger.Meta["connected"] = new RefLogLabel <TcpConnection>(this, s => s.Connected); this.logger.Meta["closed"] = new RefLogLabel <TcpConnection>(this, s => s.closed); this.logger.Meta["latency"] = new RefLogLabel <TcpConnection>(this, s => { var lat = s.Statistics.Latency; if (lat.HasValue) { return(lat.Value); } else { return(""); } }); // return $"{nameof(TcpConnection)}[id={Id}, connected={Connected}, endpoint={RemoteEndpoint}]"; }
async Task SendMessageInternalAsync(TcpRawMessage message) { try { var socket = this.socket; if (!Connected) { return; // throw new OperationCanceledException("Send operation cancelled. Connection not established"); } await sendSemaphore.WaitAsync().ConfigureAwait(false); if (message.Flags.HasFlag(MessageHeaderFlags.KeepAliveRequest) || message.Flags.HasFlag(MessageHeaderFlags.KeepAliveResponse)) { logger.Trace($"Connection #{Id} sending {message}"); } else { logger.Debug($"Connection #{Id} sending {message}"); } TcpRawMessageHeader header = new TcpRawMessageHeader(message); var headerBytes = header.Build(); Buffer.BlockCopy(headerBytes.Array, headerBytes.Offset, sendBuffer, 0, headerBytes.Count); int bufferPosition = headerBytes.Count; int totalBytesSent = 0; bool messageEof = false; message.Position = 0; do { int bufferFreeSpace = sendBuffer.Length - bufferPosition; int messageLeftBytes = (int)(message.BaseStream.Length - message.BaseStream.Position); int toCopy = bufferFreeSpace; if (messageLeftBytes <= toCopy) { toCopy = messageLeftBytes; messageEof = true; } message.BaseStream.Read(sendBuffer, bufferPosition, toCopy); bufferPosition += toCopy; int bufferSendPosition = 0; while (bufferSendPosition < bufferPosition) { int sent = await Task.Factory.FromAsync(socket.BeginSend(sendBuffer, bufferSendPosition, bufferPosition - bufferSendPosition, SocketFlags.None, null, null), socket.EndSend) .ConfigureAwait(false); logger.Trace($"Connection #{Id} sent {sent} bytes"); bufferSendPosition += sent; totalBytesSent += sent; } bufferPosition = 0; } while (!messageEof); Statistics.PacketOut(); Statistics.BytesOut(totalBytesSent); } catch (SocketException) { Close(); } catch (ObjectDisposedException) { Close(); } catch (Exception ex) { logger.Error($"Exception in #{Id} on {message} sending: {ex}"); Close(); } finally { sendSemaphore.Release(); message.Dispose(); } }
internal void ReceiveCallback(IAsyncResult result) { try { if (socket == null || !socket.Connected) { return; } int bytesRead = socket.EndReceive(result); if (bytesRead == 0) { Close(); return; } Statistics.BytesIn(bytesRead); logger.Trace($"Connection #{Id} recv data {bytesRead} bytes"); int recvBufferPos = 0; int counter = 0; while (recvBufferPos <= bytesRead) { int bytesLeft = bytesRead - recvBufferPos; if (awaitingNextMessage == null) { if (!awaitingNextMessageHeaderValid && bytesLeft > 0) { awaitingNextMessageHeaderValid = awaitingMessageHeader.Write( new ArraySegment <byte>(recvBuffer, recvBufferPos, bytesLeft), out int headerGotRead); recvBufferPos += headerGotRead; } else if (awaitingNextMessageHeaderValid) { awaitingNextMessage = new TcpRawMessage(Parent.Configuration.MemoryStreamPool, awaitingMessageHeader.MessageSize); awaitingNextMessageWrote = 0; } else if (bytesLeft == 0) { break; } } else { if (awaitingNextMessageWrote < awaitingMessageHeader.MessageSize && bytesLeft > 0) { int toRead = bytesLeft; if (toRead > awaitingMessageHeader.MessageSize - awaitingNextMessageWrote) { toRead = awaitingMessageHeader.MessageSize - awaitingNextMessageWrote; } if (toRead > 0) { awaitingNextMessage.BaseStream.Write(recvBuffer, recvBufferPos, toRead); awaitingNextMessageWrote += toRead; recvBufferPos += toRead; } } else if (awaitingNextMessageWrote == awaitingMessageHeader.MessageSize) { Statistics.PacketIn(); awaitingNextMessage.BaseStream.Position = 0; var message = awaitingNextMessage; awaitingNextMessage = null; message.Flags = awaitingMessageHeader.Options.Flags; OnMessageReceivedInternalWithSimulation(message); awaitingNextMessageWrote = 0; awaitingMessageHeader = new TcpRawMessageHeader(); awaitingNextMessageHeaderValid = false; } else if (bytesLeft == 0) { break; } } //Infinite loop protection if (counter++ > recvBuffer.Length / 2 + 100) { logger.Critical($"Infinite loop in {this}"); throw new InvalidOperationException("Infinite loop"); } } if (socket != null) { StartReceive(); } } catch (ObjectDisposedException) { } catch (SocketException sex) { if (sex.SocketErrorCode != SocketError.ConnectionReset) { logger.Error($"Connection #{Id} broken due to exception: {sex}"); } else { logger.Info($"Connection #{Id} reset"); } Close(); } catch (Exception ex) { logger.Error($"Connection #{Id} broken due to exception: {ex}"); Close(); } }