static ArrayBuffer CopyMessageToBuffer(BufferPool bufferPool, bool expectMask, byte[] buffer, int msgOffset, int payloadLength) { ArrayBuffer arrayBuffer = bufferPool.Take(payloadLength); if (expectMask) { int maskOffset = msgOffset - Constants.MaskSize; // write the result of toggle directly into arrayBuffer to avoid 2nd copy call MessageProcessor.ToggleMask(buffer, msgOffset, arrayBuffer, payloadLength, buffer, maskOffset); } else { arrayBuffer.CopyFrom(buffer, msgOffset, payloadLength); } return(arrayBuffer); }
static void HandleCloseMessage(Config config, byte[] buffer, int msgOffset, int payloadLength) { (Connection conn, int _, bool expectMask, ConcurrentQueue <Message> _, BufferPool _) = config; if (expectMask) { int maskOffset = msgOffset - Constants.MaskSize; MessageProcessor.ToggleMask(buffer, msgOffset, payloadLength, buffer, maskOffset); } // dump after mask off Log.DumpBuffer($"Message", buffer, msgOffset, payloadLength); Log.Info($"Close: {GetCloseCode(buffer, msgOffset)} message:{GetCloseMessage(buffer, msgOffset, payloadLength)}"); conn.Dispose(); }
static void ReadOneMessage(Config config, byte[] buffer) { (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config; Stream stream = conn.stream; int offset = 0; // read 2 offset = ReadHelper.Read(stream, buffer, offset, Constants.HeaderMinSize); // log after first blocking call Log.Verbose($"Message From {conn}"); if (MessageProcessor.NeedToReadShortLength(buffer)) { offset = ReadHelper.Read(stream, buffer, offset, Constants.ShortLength); } MessageProcessor.ValidateHeader(buffer, maxMessageSize, expectMask); if (expectMask) { offset = ReadHelper.Read(stream, buffer, offset, Constants.MaskSize); } int opcode = MessageProcessor.GetOpcode(buffer); int payloadLength = MessageProcessor.GetPayloadLength(buffer); Log.Verbose($"Header ln:{payloadLength} op:{opcode} mask:{expectMask}"); Log.DumpBuffer($"Raw Header", buffer, 0, offset); int msgOffset = offset; offset = ReadHelper.Read(stream, buffer, offset, payloadLength); switch (opcode) { case 2: HandleArrayMessage(config, buffer, msgOffset, payloadLength); break; case 8: HandleCloseMessage(config, buffer, msgOffset, payloadLength); break; } }
static void HandleArrayMessage(Config config, byte[] buffer, int msgOffset, int payloadLength) { (Connection conn, int _, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config; ArrayBuffer arrayBuffer = bufferPool.Take(payloadLength); if (expectMask) { int maskOffset = msgOffset - Constants.MaskSize; // write the result of toggle directly into arrayBuffer to avoid 2nd copy call MessageProcessor.ToggleMask(buffer, msgOffset, arrayBuffer, payloadLength, buffer, maskOffset); } else { arrayBuffer.CopyFrom(buffer, msgOffset, payloadLength); } // dump after mask off Log.DumpBuffer($"Message", arrayBuffer); queue.Enqueue(new Message(conn.connId, arrayBuffer)); }
static Header ReadHeader(Config config, byte[] buffer, bool opCodeContinuation = false) { (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config; Stream stream = conn.stream; Header header = new Header(); // read 2 header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.HeaderMinSize); // log after first blocking call Log.Verbose($"Message From {conn}"); if (MessageProcessor.NeedToReadShortLength(buffer)) { header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.ShortLength); } if (MessageProcessor.NeedToReadLongLength(buffer)) { header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.LongLength); } Log.DumpBuffer($"Raw Header", buffer, 0, header.offset); MessageProcessor.ValidateHeader(buffer, maxMessageSize, expectMask, opCodeContinuation); if (expectMask) { header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.MaskSize); } header.opcode = MessageProcessor.GetOpcode(buffer); header.payloadLength = MessageProcessor.GetPayloadLength(buffer); header.finished = MessageProcessor.Finished(buffer); Log.Verbose($"Header ln:{header.payloadLength} op:{header.opcode} mask:{expectMask}"); return(header); }
/// <returns>new offset in buffer</returns> static int SendMessage(byte[] buffer, int startOffset, ArrayBuffer msg, bool setMask, MaskHelper maskHelper) { int msgLength = msg.count; int offset = WriteHeader(buffer, startOffset, msgLength, setMask); if (setMask) { offset = maskHelper.WriteMask(buffer, offset); } msg.CopyTo(buffer, offset); offset += msgLength; // dump before mask on Log.DumpBuffer("Send", buffer, startOffset, offset); if (setMask) { int messageOffset = offset - msgLength; MessageProcessor.ToggleMask(buffer, messageOffset, msgLength, buffer, messageOffset - Constants.MaskSize); } return(offset); }
static void SendMessage(Stream stream, byte[] buffer, ArrayBuffer msg, bool setMask, MaskHelper maskHelper) { int msgLength = msg.count; int sendLength = WriteHeader(buffer, msgLength, setMask); if (setMask) { sendLength = maskHelper.WriteMask(buffer, sendLength); } msg.CopyTo(buffer, sendLength); sendLength += msgLength; // dump before mask on Log.DumpBuffer("Send", buffer, 0, sendLength); if (setMask) { int messageOffset = sendLength - msgLength; MessageProcessor.ToggleMask(buffer, messageOffset, msgLength, buffer, messageOffset - Constants.MaskSize); } stream.Write(buffer, 0, sendLength); }
static void ReadOneMessage(Config config, byte[] buffer) { (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config; Stream stream = conn.stream; Header header = ReadHeader(config, buffer); int msgOffset = header.offset; header.offset = ReadHelper.Read(stream, buffer, header.offset, header.payloadLength); if (header.finished) { switch (header.opcode) { case 2: HandleArrayMessage(config, buffer, msgOffset, header.payloadLength); break; case 8: HandleCloseMessage(config, buffer, msgOffset, header.payloadLength); break; } } else { // todo cache this to avoid allocations Queue <ArrayBuffer> fragments = new Queue <ArrayBuffer>(); fragments.Enqueue(CopyMessageToBuffer(bufferPool, expectMask, buffer, msgOffset, header.payloadLength)); int totalSize = header.payloadLength; while (!header.finished) { header = ReadHeader(config, buffer, opCodeContinuation: true); msgOffset = header.offset; header.offset = ReadHelper.Read(stream, buffer, header.offset, header.payloadLength); fragments.Enqueue(CopyMessageToBuffer(bufferPool, expectMask, buffer, msgOffset, header.payloadLength)); totalSize += header.payloadLength; MessageProcessor.ThrowIfMsgLengthTooLong(totalSize, maxMessageSize); } ArrayBuffer msg = bufferPool.Take(totalSize); msg.count = 0; while (fragments.Count > 0) { ArrayBuffer part = fragments.Dequeue(); part.CopyTo(msg.array, msg.count); msg.count += part.count; part.Release(); } // dump after mask off Log.DumpBuffer($"Message", msg); queue.Enqueue(new Message(conn.connId, msg)); } }