/// <summary> /// Clear WebSocket send/receive buffers /// </summary> public void ClearWsBuffers() { lock (WsReceiveLock) { WsFrameReceived = false; WsFinalReceived = false; WsHeaderSize = 0; WsPayloadSize = 0; WsReceiveFrameBuffer.Clear(); WsReceiveFinalBuffer.Clear(); Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length); } lock (WsSendLock) { WsSendBuffer.Clear(); Array.Clear(WsSendMask, 0, WsSendMask.Length); } }
/// <summary> /// Prepare WebSocket send frame /// </summary> /// <param name="buffer">Buffer to send</param> /// <param name="offset">Buffer offset</param> /// <param name="size">Buffer size</param> public void PrepareReceiveFrame(byte[] buffer, int offset, int size) { lock (WsReceiveLock) { var index = 0; // Clear received data after WebSocket frame was processed if (WsFrameReceived) { WsFrameReceived = false; WsHeaderSize = 0; WsPayloadSize = 0; WsReceiveFrameBuffer.Clear(); Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length); } if (WsFinalReceived) { WsFinalReceived = false; WsReceiveFinalBuffer.Clear(); } while (size > 0) { // Clear received data after WebSocket frame was processed if (WsFrameReceived) { WsFrameReceived = false; WsHeaderSize = 0; WsPayloadSize = 0; WsReceiveFrameBuffer.Clear(); Array.Clear(WsReceiveMask, 0, WsReceiveMask.Length); } if (WsFinalReceived) { WsFinalReceived = false; WsReceiveFinalBuffer.Clear(); } // Prepare WebSocket frame opcode and mask flag if (WsReceiveFrameBuffer.Count < 2) { for (int i = 0; i < 2; i++, index++, size--) { if (size == 0) { return; } WsReceiveFrameBuffer.Add(buffer[offset + index]); } } byte opcode = (byte)(WsReceiveFrameBuffer[0] & 0x0F); bool fin = ((WsReceiveFrameBuffer[0] >> 7) & 0x01) != 0; bool mask = ((WsReceiveFrameBuffer[1] >> 7) & 0x01) != 0; int payload = WsReceiveFrameBuffer[1] & (~0x80); // Prepare WebSocket opcode WsOpcode = (opcode != 0) ? opcode : WsOpcode; // Prepare WebSocket frame size if (payload <= 125) { WsHeaderSize = 2 + (mask ? 4 : 0); WsPayloadSize = payload; } else if (payload == 126) { if (WsReceiveFrameBuffer.Count < 4) { for (int i = 0; i < 2; i++, index++, size--) { if (size == 0) { return; } WsReceiveFrameBuffer.Add(buffer[offset + index]); } } payload = ((WsReceiveFrameBuffer[2] << 8) | (WsReceiveFrameBuffer[3] << 0)); WsHeaderSize = 4 + (mask ? 4 : 0); WsPayloadSize = payload; } else if (payload == 127) { if (WsReceiveFrameBuffer.Count < 10) { for (int i = 0; i < 8; i++, index++, size--) { if (size == 0) { return; } WsReceiveFrameBuffer.Add(buffer[offset + index]); } } payload = ((WsReceiveFrameBuffer[2] << 56) | (WsReceiveFrameBuffer[3] << 48) | (WsReceiveFrameBuffer[4] << 40) | (WsReceiveFrameBuffer[5] << 32) | (WsReceiveFrameBuffer[6] << 24) | (WsReceiveFrameBuffer[7] << 16) | (WsReceiveFrameBuffer[8] << 8) | (WsReceiveFrameBuffer[9] << 0)); WsHeaderSize = 10 + (mask ? 4 : 0); WsPayloadSize = payload; } // Prepare WebSocket frame mask if (mask) { if (WsReceiveFrameBuffer.Count < WsHeaderSize) { for (int i = 0; i < 4; i++, index++, size--) { if (size == 0) { return; } WsReceiveFrameBuffer.Add(buffer[offset + index]); WsReceiveMask[i] = buffer[offset + index]; } } } int total = WsHeaderSize + WsPayloadSize; int length = Math.Min(total - WsReceiveFrameBuffer.Count, size); // Prepare WebSocket frame payload WsReceiveFrameBuffer.AddRange(buffer.Skip(offset + index).Take(length)); index += length; size -= length; // Process WebSocket frame if (WsReceiveFrameBuffer.Count == total) { // Unmask WebSocket frame content if (mask) { for (int i = 0; i < WsPayloadSize; i++) { WsReceiveFinalBuffer.Add((byte)(WsReceiveFrameBuffer[WsHeaderSize + i] ^ WsReceiveMask[i % 4])); } } else { WsReceiveFinalBuffer.AddRange(WsReceiveFrameBuffer.GetRange(WsHeaderSize, WsPayloadSize)); } WsFrameReceived = true; // Finalize WebSocket frame if (fin) { WsFinalReceived = true; switch (WsOpcode) { case WS_PING: { // Call the WebSocket ping handler _wsHandler.OnWsPing(WsReceiveFinalBuffer.ToArray(), 0, WsReceiveFinalBuffer.Count); break; } case WS_PONG: { // Call the WebSocket pong handler _wsHandler.OnWsPong(WsReceiveFinalBuffer.ToArray(), 0, WsReceiveFinalBuffer.Count); break; } case WS_CLOSE: { // Call the WebSocket close handler _wsHandler.OnWsClose(WsReceiveFinalBuffer.ToArray(), 0, WsReceiveFinalBuffer.Count); break; } case WS_BINARY: case WS_TEXT: { // Call the WebSocket received handler _wsHandler.OnWsReceived(WsReceiveFinalBuffer.ToArray(), 0, WsReceiveFinalBuffer.Count); break; } } } } } } }