//public void SendMessage(RawMessage message) //{ // SendMessageAsync(message); //} public virtual async Task SendMessageAsync(TcpRawMessage message) { if (!Connected) { message.Dispose(); throw new InvalidOperationException($"Connection is not established"); } if (Parent.Configuration.ConnectionSimulation != null) { int delay = Parent.Configuration.ConnectionSimulation.GetHalfDelay(); if (delay > 0) { await Task.Delay(delay).ConfigureAwait(false); } } Task newSendTask = null; lock (sendMutex) { sendTask = sendTask.ContinueWith( (task, msg) => { return(SendMessageInternalAsync(msg as TcpRawMessage)); }, message) .Unwrap(); newSendTask = sendTask; } await newSendTask.ConfigureAwait(false); }
public virtual void Stash() { if (Disposed) { throw new ObjectDisposedException(nameof(TcpConnection)); } if (Stashed) { return; } Close(); DestroySocket(); this.awaitingMessageHeader.Reset(); this.Statistics.Reset(); this.lastKeepAliveSent = new DateTime(0); this.awaitingNextMessageWrote = 0; this.awaitingNextMessageHeaderValid = false; this.LastKeepAliveRequestReceived = null; if (this.awaitingNextMessage != null) { this.awaitingNextMessage.Dispose(); this.awaitingNextMessage = null; } while (this.latencySimulationRecvQueue.TryDequeue(out DelayedMessage removed)) { removed.message.Dispose(); } stashed = true; logger.Debug($"Connection #{Id} stashed!"); }
/// <summary> /// Returns the memory used by this connection /// </summary> /// <param name="disposing">Whether we're disposing (true), or being called by the finalizer (false)</param> protected virtual void Dispose(bool disposing) { if (disposed) { return; } disposed = true; Close(); DestroySocket(); if (this.awaitingNextMessage != null) { this.awaitingNextMessage.Dispose(); this.awaitingNextMessage = null; } if (sendSemaphore != null) { sendSemaphore.Dispose(); sendSemaphore = null; } logger.Debug($"Connection #{Id} disposed!"); }
public bool SendReliable(ICustomMessage message) { if (!this.Connected) { return(false); } TcpRawMessage rawMessage = Parent.CreateMessage(); using (WardenStreamWriter sw = new WardenStreamWriter(rawMessage.BaseStream, true)) { message.WriteTo(new WriteFormatterInfo(sw, configuration.Serializer)); } if (rawMessage.Length >= configuration.CompressionThreshold) { logger.Trace($"Message {message} size exceeds compression threshold {configuration.CompressionThreshold}, compressing it"); using (rawMessage) { var compressedMessage = rawMessage.Compress(CompressionLevel.Optimal); logger.Trace($"Compressing {rawMessage} to {compressedMessage}"); compressedMessage.Position = 0; SendRawMessage(compressedMessage); } } else { SendRawMessage(rawMessage); } return(true); }
private protected override void SendRawMessage(TcpRawMessage message) { using (message) { message.Position = 0; TcpRawMessage encryptedMessage = message.Encrypt(cipher); logger.Trace($"Encrypting {message} to {encryptedMessage}"); base.SendRawMessage(encryptedMessage); } }
protected internal virtual void PollEventsInternal() { if (Parent.Configuration.KeepAliveEnabled) { TimeSpan timeSinceLastKeepAlive = DateTime.UtcNow - this.lastKeepAliveSent; if (keepAliveResponseGot) { if (timeSinceLastKeepAlive.TotalMilliseconds > Parent.Configuration.KeepAliveInterval) { keepAliveResponseGot = false; this.lastKeepAliveSent = DateTime.UtcNow; _ = SendMessageAsync(TcpRawMessage.GetEmpty(Parent.Configuration.MemoryStreamPool, MessageHeaderFlags.KeepAliveRequest)); } } else { if (timeSinceLastKeepAlive.TotalMilliseconds > TcpConnectionStatistics.UNSTABLE_CONNECTION_TIMEOUT) { Statistics.SetUnstable(); } if (Parent.Configuration.KeepAliveTimeout > Timeout.Infinite && timeSinceLastKeepAlive.TotalMilliseconds > Parent.Configuration.KeepAliveTimeout) { logger.Debug($"Connection #{Id} closing, KeepAliveTimeout exceeded"); Close(); } } } Statistics.PollEvents(); while (latencySimulationRecvQueue.Count > 0 && Connected) { if (latencySimulationRecvQueue.TryPeek(out DelayedMessage msg)) { if (DateTime.UtcNow > msg.releaseTimestamp) { latencySimulationRecvQueue.TryDequeue(out DelayedMessage _msg); OnMessageReceivedInternal(msg.message); } else { break; } } else { break; } } }
public MessageEventArgs(TcpConnection connection, TcpRawMessage message) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } this.Connection = connection; this.Message = message; }
void OnMessageReceivedInternalWithSimulation(TcpRawMessage message) { if (Parent.Configuration.ConnectionSimulation != null) { int delay = Parent.Configuration.ConnectionSimulation.GetHalfDelay(); latencySimulationRecvQueue.Enqueue(new DelayedMessage() { message = message, releaseTimestamp = DateTime.UtcNow.AddMilliseconds(delay) }); return; } OnMessageReceivedInternal(message); }
void OnMessageReceivedInternal(TcpRawMessage message) { if (message.Flags.HasFlag(MessageHeaderFlags.KeepAliveRequest) || message.Flags.HasFlag(MessageHeaderFlags.KeepAliveResponse)) { logger.Trace($"Connection #{Id} recv message {message}"); } else { logger.Debug($"Connection #{Id} recv message {message}"); } if (message.Flags.HasFlag(MessageHeaderFlags.KeepAliveRequest)) { LastKeepAliveRequestReceived = DateTime.UtcNow; _ = SendMessageAsync(TcpRawMessage.GetEmpty(Parent.Configuration.MemoryStreamPool, MessageHeaderFlags.KeepAliveResponse)); message.Dispose(); return; } if (message.Flags.HasFlag(MessageHeaderFlags.KeepAliveResponse)) { Statistics.UpdateLatency((float)(DateTime.UtcNow - this.lastKeepAliveSent).TotalMilliseconds); keepAliveResponseGot = true; message.Dispose(); return; } Parent.Configuration.SynchronizeSafe(() => { try { OnMessageReceived(new MessageEventArgs(this, message)); } catch (Exception ex) { logger.Error($"Unhandled exception in #{Id} -> {this.GetType().Name}.OnMessageReceived: {ex}"); } }, logger); }
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(); } }
private protected virtual void SendRawMessage(TcpRawMessage message) { _ = this.SendMessageAsync(message); }
public void BeforeServerToClient(TcpRawMessage serverMessage) { }
public void BeforeClientToServer(TcpRawMessage clientMessage) { }