protected override unsafe void Encode(IChannelHandlerContext ctx, WebSocketFrame msg, List <object> output) { IByteBuffer data = msg.Content; var mask = stackalloc byte[4]; byte opcode = 0; switch (msg.Opcode) { case Opcode.Text: opcode = OpcodeText; break; case Opcode.Ping: opcode = OpcodePing; break; case Opcode.Pong: opcode = OpcodePong; break; case Opcode.Close: opcode = OpcodeClose; break; case Opcode.Binary: opcode = OpcodeBinary; break; case Opcode.Cont: opcode = OpcodeCont; break; default: ThrowNotSupportedException(msg); break; } int length = data.ReadableBytes; if (Logger.TraceEnabled) { Logger.EncodingWebSocketFrameOpCode(opcode, length); } int b0 = 0; if (msg.IsFinalFragment) { b0 |= 1 << 7; } b0 |= msg.Rsv % 8 << 4; b0 |= opcode % 128; if (opcode == OpcodePing && length > 125) { ThrowTooLongFrameException(length); } bool release = true; IByteBuffer buf = null; try { int maskLength = this.maskPayload ? 4 : 0; if (length <= 125) { int size = 2 + maskLength; if (this.maskPayload || length <= GatheringWriteThreshold) { size += length; } buf = ctx.Allocator.Buffer(size); _ = buf.WriteByte(b0); byte b = (byte)(this.maskPayload ? 0x80 | (byte)length : (byte)length); _ = buf.WriteByte(b); } else if (length <= 0xFFFF) { int size = 4 + maskLength; if (this.maskPayload || length <= GatheringWriteThreshold) { size += length; } buf = ctx.Allocator.Buffer(size); _ = buf.WriteByte(b0); _ = buf.WriteByte(this.maskPayload ? 0xFE : 126); _ = buf.WriteByte(length.RightUShift(8) & 0xFF); _ = buf.WriteByte(length & 0xFF); } else { int size = 10 + maskLength; if (this.maskPayload || length <= GatheringWriteThreshold) { size += length; } buf = ctx.Allocator.Buffer(size); _ = buf.WriteByte(b0); _ = buf.WriteByte(this.maskPayload ? 0xFF : 127); _ = buf.WriteLong(length); } // Write payload if (this.maskPayload) { int intMask = (this.random.Next() * int.MaxValue); // Mask bytes in BE uint unsignedValue = (uint)intMask; * mask = (byte)(unsignedValue >> 24); *(mask + 1) = (byte)(unsignedValue >> 16); *(mask + 2) = (byte)(unsignedValue >> 8); *(mask + 3) = (byte)unsignedValue; // Mask in BE _ = buf.WriteInt(intMask); int counter = 0; int i = data.ReaderIndex; int end = data.WriterIndex; for (; i + 3 < end; i += 4) { int intData = data.GetInt(i); _ = buf.WriteInt(intData ^ intMask); } for (; i < end; i++) { byte byteData = data.GetByte(i); _ = buf.WriteByte(byteData ^ mask[counter++ % 4]); } output.Add(buf); } else { if (buf.WritableBytes >= data.ReadableBytes) { // merge buffers as this is cheaper then a gathering write if the payload is small enough _ = buf.WriteBytes(data); output.Add(buf); } else { output.Add(buf); output.Add(data.Retain()); } } release = false; } finally { if (release) { _ = (buf?.Release()); } } }