protected MongoMessage( MongoServer server, MessageOpcode opcode ) { this.server = server; this.opcode = opcode; }
protected int messageStartPosition = -1; // start position in buffer for backpatching messageLength #endregion #region constructors protected MongoRequestMessage( MongoServer server, MessageOpcode opcode ) : this(server, opcode, null) { }
private async Task SendFrameFallbackAsync(MessageOpcode opcode, ArraySegment <byte> payloadBuffer, CancellationToken cancellationToken) { var sendBuffer = WriteFrameToSendBuffer(opcode, payloadBuffer); await _sendFrameAsyncLock.WaitAsync().ConfigureAwait(false); try { using (cancellationToken.Register(s => ((MazeSocket)s).Abort(), this)) { await _stream.WriteAsync(sendBuffer.Array, sendBuffer.Offset, sendBuffer.Count, cancellationToken) .ConfigureAwait(false); } } catch (Exception exc) { throw State == WebSocketState.Aborted ? CreateOperationCanceledException(exc, cancellationToken) : new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); } finally { _sendFrameAsyncLock.Release(); ReleaseSendBuffer(sendBuffer.Array); } }
protected MongoMessage( MongoConnection connection, MessageOpcode opcode ) { this.connection = connection; this.opcode = opcode; }
protected int messageStartPosition = -1; // start position in buffer for backpatching messageLength #endregion #region constructors protected MongoRequestMessage( MongoConnection connection, MessageOpcode opcode ) : this(connection, opcode, null) { }
protected MongoRequestMessage( MongoServer server, MessageOpcode opcode ) : this(server, opcode, null) { }
private int _messageStartPosition = -1; // start position in buffer for backpatching messageLength // constructors protected MongoRequestMessage( MessageOpcode opcode, BsonBinaryWriterSettings writerSettings) : base(opcode) { _writerSettings = writerSettings; RequestId = Interlocked.Increment(ref __lastRequestId); }
protected MongoRequestMessage( MessageOpcode opcode, BsonBuffer buffer // not null if piggybacking this message onto an existing buffer ) : base(opcode) { this.buffer = buffer ?? new BsonBuffer(); this.disposeBuffer = buffer == null; // only call Dispose if we allocated the buffer this.requestId = Interlocked.Increment(ref lastRequestId); }
/// <summary>Writes a frame into the send buffer, which can then be sent over the network.</summary> private ArraySegment <byte> WriteFrameToSendBuffer(MessageOpcode opcode, ArraySegment <byte> payloadBuffer) { var sendBuffer = AllocateSendBuffer(payloadBuffer.Count + MaxMessageHeaderLength); var headerLength = WriteHeader(opcode, sendBuffer, payloadBuffer); if (payloadBuffer.Count > 0) { Buffer.BlockCopy(payloadBuffer.Array, payloadBuffer.Offset, sendBuffer, headerLength, payloadBuffer.Count); } return(new ArraySegment <byte>(sendBuffer, 0, headerLength + payloadBuffer.Count)); }
protected MongoRequestMessage( MongoConnection connection, MessageOpcode opcode, BsonBuffer buffer // not null if piggybacking this message onto an existing buffer ) : base(connection, opcode) { if (buffer == null) { this.buffer = new BsonBuffer(); this.disposeBuffer = true; // only call Dispose if we allocated the buffer } else { this.buffer = buffer; this.disposeBuffer = false; } this.requestId = Interlocked.Increment(ref lastRequestId); }
private void ProcessPacket(ClientPacket packet) { using var stream = new PacketCryptoStream(packet.Header.Seed, packet.Data); using var reader = new BinaryReader(stream); byte group = reader.ReadByte(); byte index = reader.ReadByte(); MessageOpcode opcode = (MessageOpcode)((group << 8) | index); IReadable message = MessageManager.Instance.GetMessage(opcode); if (message == null) { log.Warn($"Received unknown message {opcode}(0x{opcode:X})!"); return; } (MessageHandlerAttribute attribute, MessageHandlerDelegate @delegate) = MessageManager.Instance.GetMessageInformation(opcode); if (attribute == null) { log.Warn($"Received unhandled message {opcode}(0x{opcode:X})!"); return; } if (state != attribute.State) { log.Warn($"Received message {opcode}(0x{opcode:X}) while in an invalid state!"); return; } log.Trace($"Received message {opcode}(0x{opcode:X})."); message.Read(reader); if (reader.BaseStream.Remaining() > 0) { log.Warn($"Failed to read entire contents of message {opcode}(0x{opcode:X})!"); } try { @delegate.Invoke(this, message); } catch (Exception exception) { log.Error(exception); } }
protected int messageStartPosition = -1; // start position in buffer for backpatching messageLength // constructors protected MongoRequestMessage(MessageOpcode opcode, BsonBuffer buffer, BsonBinaryWriterSettings writerSettings) : base(opcode) { // buffer is not null if piggybacking this message onto an existing buffer if (buffer == null) { this.buffer = new BsonBuffer(); this.disposeBuffer = true; // only call Dispose if we allocated the buffer } else { this.buffer = buffer; this.disposeBuffer = false; } this.writerSettings = writerSettings; this.requestId = Interlocked.Increment(ref lastRequestId); }
// constructors protected MongoRequestMessage(MessageOpcode opcode, BsonBuffer buffer, BsonBinaryWriterSettings writerSettings) : base(opcode) { // buffer is not null if piggybacking this message onto an existing buffer if (buffer == null) { this.buffer = new BsonBuffer(); this.disposeBuffer = true; // only call Dispose if we allocated the buffer } else { this.buffer = buffer; this.disposeBuffer = false; } this.writerSettings = writerSettings; this.requestId = Interlocked.Increment(ref lastRequestId); }
public TelemetryMessage(MessageOpcode typeMessageType, string[] parts) { MessageType = typeMessageType; TransmissionTypeId = MessageUtil.GetIntField(parts, MessageField.TransmissionType); TransmissionType = (TransmissionType)TransmissionTypeId; SessionId = MessageUtil.GetIntField(parts, MessageField.SessionId); AircraftId = MessageUtil.GetIntField(parts, MessageField.AircraftId); HexId = MessageUtil.GetField(parts, MessageField.HexIdent); FlightId = MessageUtil.GetIntField(parts, MessageField.FlightId); DateTimeGenerated = DateTime.Parse( $"{MessageUtil.GetField(parts, MessageField.DateMsgGenerated)} {MessageUtil.GetField(parts, MessageField.TimeMsgGenerated)}"); DateTimeLogged = DateTime.Parse( $"{MessageUtil.GetField(parts, MessageField.DateMsgLogged)} {MessageUtil.GetField(parts, MessageField.TimeMsgLogged)}"); }
public ServerPacket(MessageOpcode opcode, ushort seed, IWritable message) { using (var stream = new PacketCryptoStream(seed)) { using var writer = new BinaryWriter(stream); writer.Write((byte)((int)opcode >> 8)); writer.Write((byte)((int)opcode & 0xFF)); message.Write(writer); Data = stream.ToArray(); } Header = new PacketHeader { Seed = seed, Length = (ushort)(Data.Length + PacketHeader.Size), Unknown2 = 1 }; }
private static int WriteHeader(MessageOpcode opcode, byte[] sendBuffer, ReadOnlyMemory <byte> payload) { sendBuffer[0] = (byte)opcode; var offset = 1; // Store the payload length. // Write out an int 7 bits at a time. The high bit of the byte, // when on, tells reader to continue reading more bytes. var v = (uint)payload.Length; // support negative numbers while (v >= 0x80) { sendBuffer[offset++] = (byte)(v | 0x80); v >>= 7; } sendBuffer[offset++] = (byte)v; return(offset); }
private static int WriteHeader(MessageOpcode opcode, byte[] sendBuffer, ArraySegment<byte> payload, bool endOfMessage, bool useMask) { // Client header format: // 1 bit - FIN - 1 if this is the final fragment in the message (it could be the only fragment), otherwise 0 // 1 bit - RSV1 - Reserved - 0 // 1 bit - RSV2 - Reserved - 0 // 1 bit - RSV3 - Reserved - 0 // 4 bits - Opcode - How to interpret the payload // - 0x0 - continuation // - 0x1 - text // - 0x2 - binary // - 0x8 - connection close // - 0x9 - ping // - 0xA - pong // - (0x3 to 0x7, 0xB-0xF - reserved) // 1 bit - Masked - 1 if the payload is masked, 0 if it's not. Must be 1 for the client // 7 bits, 7+16 bits, or 7+64 bits - Payload length // - For length 0 through 125, 7 bits storing the length // - For lengths 126 through 2^16, 7 bits storing the value 126, followed by 16 bits storing the length // - For lengths 2^16+1 through 2^64, 7 bits storing the value 127, followed by 64 bytes storing the length // 0 or 4 bytes - Mask, if Masked is 1 - random value XOR'd with each 4 bytes of the payload, round-robin // Length bytes - Payload data Debug.Assert(sendBuffer.Length >= MaxMessageHeaderLength, $"Expected sendBuffer to be at least {MaxMessageHeaderLength}, got {sendBuffer.Length}"); sendBuffer[0] = (byte)opcode; // 4 bits for the opcode if (endOfMessage) { sendBuffer[0] |= 0x80; // 1 bit for FIN } // Store the payload length. int maskOffset; if (payload.Count <= 125) { sendBuffer[1] = (byte)payload.Count; maskOffset = 2; // no additional payload length } else if (payload.Count <= ushort.MaxValue) { sendBuffer[1] = 126; sendBuffer[2] = (byte)(payload.Count / 256); sendBuffer[3] = (byte)payload.Count; maskOffset = 2 + sizeof(ushort); // additional 2 bytes for 16-bit length } else { sendBuffer[1] = 127; int length = payload.Count; for (int i = 9; i >= 2; i--) { sendBuffer[i] = (byte)length; length = length / 256; } maskOffset = 2 + sizeof(ulong); // additional 8 bytes for 64-bit length } if (useMask) { // Generate the mask. sendBuffer[1] |= 0x80; WriteRandomMask(sendBuffer, maskOffset); } // Return the position of the mask. return maskOffset; }
/// <summary>Writes a frame into the send buffer, which can then be sent over the network.</summary> private int WriteFrameToSendBuffer(MessageOpcode opcode, bool endOfMessage, ArraySegment<byte> payloadBuffer) { // Grow our send buffer as needed. We reuse the buffer for all messages, with it protected by the send frame lock. EnsureBufferLength(ref _sendBuffer, payloadBuffer.Count + MaxMessageHeaderLength); // Write the message header data to the buffer. int headerLength; int? maskOffset = null; if (_isServer) { // The server doesn't send a mask, so the mask offset returned by WriteHeader // is actually the end of the header. headerLength = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage, useMask: false); } else { // We need to know where the mask starts so that we can use the mask to manipulate the payload data, // and we need to know the total length for sending it on the wire. maskOffset = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage, useMask: true); headerLength = maskOffset.GetValueOrDefault() + MaskLength; } // Write the payload if (payloadBuffer.Count > 0) { Buffer.BlockCopy(payloadBuffer.Array, payloadBuffer.Offset, _sendBuffer, headerLength, payloadBuffer.Count); // If we added a mask to the header, XOR the payload with the mask. We do the manipulation in the send buffer so as to avoid // changing the data in the caller-supplied payload buffer. if (maskOffset.HasValue) { ApplyMask(_sendBuffer, headerLength, _sendBuffer, maskOffset.Value, 0, payloadBuffer.Count); } } // Return the number of bytes in the send buffer return headerLength + payloadBuffer.Count; }
private async Task SendFrameFallbackAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment<byte> payloadBuffer, CancellationToken cancellationToken) { await _sendFrameAsyncLock.WaitAsync().ConfigureAwait(false); try { int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer); using (cancellationToken.Register(s => ((ManagedWebSocket)s).Abort(), this)) { await _stream.WriteAsync(_sendBuffer, 0, sendBytes, cancellationToken).ConfigureAwait(false); } } catch (Exception exc) { throw _state == WebSocketState.Aborted ? CreateOperationCanceledException(exc, cancellationToken) : new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); } finally { _sendFrameAsyncLock.Release(); } }
/// <summary>Sends a websocket frame to the network. The caller must hold the sending lock.</summary> /// <param name="opcode">The opcode for the message.</param> /// <param name="endOfMessage">The value of the FIN bit for the message.</param> /// <param name="payloadBuffer">The buffer containing the payload data fro the message.</param> private Task SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment<byte> payloadBuffer) { Debug.Assert(_sendFrameAsyncLock.CurrentCount == 0, "Caller should hold the _sendFrameAsyncLock"); // If we get here, the cancellation token is not cancelable so we don't have to worry about it, // and we own the semaphore, so we don't need to asynchronously wait for it. Task writeTask = null; bool releaseSemaphore = true; try { // Write the payload synchronously to the buffer, then write that buffer out to the network. int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer); writeTask = _stream.WriteAsync(_sendBuffer, 0, sendBytes, CancellationToken.None); // If the operation happens to complete synchronously (or, more specifically, by // the time we get from the previous line to here, release the semaphore, propagate // exceptions, and we're done. if (writeTask.IsCompleted) { writeTask.GetAwaiter().GetResult(); // propagate any exceptions return Task.CompletedTask; } // Up until this point, if an exception occurred (such as when accessing _stream or when // calling GetResult), we want to release the semaphore. After this point, the semaphore needs // to remain held until writeTask completes. releaseSemaphore = false; } catch (Exception exc) { return Task.FromException(_state == WebSocketState.Aborted ? CreateOperationCanceledException(exc) : new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc)); } finally { if (releaseSemaphore) { _sendFrameAsyncLock.Release(); } } // The write was not yet completed. Create and return a continuation that will // release the semaphore and translate any exception that occurred. return writeTask.ContinueWith((t, s) => { var thisRef = (ManagedWebSocket)s; thisRef._sendFrameAsyncLock.Release(); try { t.GetAwaiter().GetResult(); } catch (Exception exc) { throw thisRef._state == WebSocketState.Aborted ? CreateOperationCanceledException(exc) : new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); } }, this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); }
/// <summary>Sends a websocket frame to the network.</summary> /// <param name="opcode">The opcode for the message.</param> /// <param name="endOfMessage">The value of the FIN bit for the message.</param> /// <param name="payloadBuffer">The buffer containing the payload data fro the message.</param> /// <param name="cancellationToken">The CancellationToken to use to cancel the websocket.</param> private Task SendFrameAsync(MessageOpcode opcode, bool endOfMessage, ArraySegment<byte> payloadBuffer, CancellationToken cancellationToken) { // TODO: #4900 SendFrameAsync should in theory typically complete synchronously, making it fast and allocation free. // However, due to #4900, it almost always yields, resulting in all of the allocations involved in an async method // yielding, e.g. the boxed state machine, the Action delegate, the MoveNextRunner, and the resulting Task, plus it's // common that the awaited operation completes so fast after the await that we may end up allocating an AwaitTaskContinuation // inside of the TaskAwaiter. Since SendFrameAsync is such a core code path, until that can be fixed, we put some // optimizations in place to avoid a few of those expenses, at the expense of more complicated code; for the common case, // this code has fewer than half the number and size of allocations. If/when that issue is fixed, this method should be deleted // and replaced by SendFrameFallbackAsync, which is the same logic but in a much more easily understand flow. // If a cancelable cancellation token was provided, that would require registering with it, which means more state we have to // pass around (the CancellationTokenRegistration), so if it is cancelable, just immediately go to the fallback path. // Similarly, it should be rare that there are multiple outstanding calls to SendFrameAsync, but if there are, again // fall back to the fallback path. return cancellationToken.CanBeCanceled || !_sendFrameAsyncLock.Wait(0) ? SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken) : SendFrameLockAcquiredNonCancelableAsync(opcode, endOfMessage, payloadBuffer); }
// constructors protected MongoMessage(MessageOpcode opcode) { _opcode = opcode; }
/// <summary>Writes a frame into the send buffer, which can then be sent over the network.</summary> private int WriteFrameToSendBuffer(MessageOpcode opcode, bool endOfMessage, ArraySegment<byte> payloadBuffer) { // Grow our send buffer as needed. We reuse the buffer for all messages, with it protected by the send frame lock. EnsureBufferLength(ref _sendBuffer, payloadBuffer.Count + MaxSendMessageHeaderLength); // Write the message header data to the buffer. We need to know where the mask starts so that we can use // the mask to manipulate the payload data, and we need to know the total length for sending it on the wire. int maskOffset = WriteHeader(opcode, _sendBuffer, payloadBuffer, endOfMessage); int headerLength = maskOffset + MaskLength; // If there is payload data, XOR it with the mask. We do the manipulation in the send buffer so as to avoid // changing the data in the caller-supplied payload buffer. if (payloadBuffer.Count > 0) { for (int i = 0; i < payloadBuffer.Count; i++) { _sendBuffer[i + headerLength] = (byte) (payloadBuffer.Array[payloadBuffer.Offset + i] ^ _sendBuffer[maskOffset + (i & 3)]); // (i % MaskLength) } } // Return the number of bytes in the send buffer return headerLength + payloadBuffer.Count; }
public MessageHandlerAttribute(MessageOpcode opcode, SessionState state = SessionState.Authenticated) { Opcode = opcode; State = state; }
// constructors protected MongoMessage(MessageOpcode opcode) { this.opcode = opcode; }
/// <summary>Sends a websocket frame to the network. The caller must hold the sending lock.</summary> /// <param name="opcode">The opcode for the message.</param> /// <param name="payloadBuffer">The buffer containing the payload data fro the message.</param> private Task SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode, ArraySegment <byte> payloadBuffer) { // If we get here, the cancellation token is not cancelable so we don't have to worry about it, // and we own the semaphore, so we don't need to asynchronously wait for it. Task writeTask = default; var releaseSemaphoreAndSendBuffer = true; var sendBuffer = WriteFrameToSendBuffer(opcode, payloadBuffer); try { // Write the payload synchronously to the buffer, then write that buffer out to the network. writeTask = _stream.WriteAsync(sendBuffer.Array, sendBuffer.Offset, sendBuffer.Count); // If the operation happens to complete synchronously (or, more specifically, by // the time we get from the previous line to here), release the semaphore, return // the task, and we're done. if (writeTask.IsCompleted) { return(writeTask); } // Up until this point, if an exception occurred (such as when accessing _stream or when // calling GetResult), we want to release the semaphore and the send buffer. After this point, // both need to be held until writeTask completes. releaseSemaphoreAndSendBuffer = false; } catch (Exception exc) { return(Task.FromException(exc is OperationCanceledException ? exc : State == WebSocketState.Aborted ? CreateOperationCanceledException(exc) : new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc))); } finally { if (releaseSemaphoreAndSendBuffer) { _sendFrameAsyncLock.Release(); ReleaseSendBuffer(sendBuffer.Array); } } // The write was not yet completed. Create and return a continuation that will // release the semaphore and translate any exception that occurred. return(writeTask.ContinueWith((t, s) => { var thisRef = (MazeSocket)s; thisRef._sendFrameAsyncLock.Release(); thisRef.ReleaseSendBuffer(sendBuffer.Array); try { t.GetAwaiter().GetResult(); } catch (Exception exc) { throw thisRef.State == WebSocketState.Aborted ? CreateOperationCanceledException(exc) : new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc); } }, this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)); }
protected MongoRequestMessage( MessageOpcode opcode ) : this(opcode, null) { }
public MessageAttribute(MessageOpcode opcode) { Opcode = opcode; }
/// <summary>Sends a websocket frame to the network.</summary> /// <param name="opcode">The opcode for the message.</param> /// <param name="payloadBuffer">The buffer containing the payload data fro the message.</param> /// <param name="bufferHasRequiredLength">True if the buffer has the required length</param> /// <param name="cancellationToken">The CancellationToken to use to cancel the websocket.</param> public Task SendFrameAsync(MessageOpcode opcode, ArraySegment <byte> payloadBuffer, bool bufferHasRequiredLength, CancellationToken cancellationToken) => cancellationToken.CanBeCanceled || !_sendFrameAsyncLock.Wait(0) ? SendFrameFallbackAsync(opcode, payloadBuffer, cancellationToken) : SendFrameLockAcquiredNonCancelableAsync(opcode, payloadBuffer);