From 6824ee27e79164029b2baa7b21526e5a23950ffe Mon Sep 17 00:00:00 2001 From: Ivan Shynkarenka Date: Wed, 26 Oct 2022 19:14:34 +0400 Subject: [PATCH] Extended payload length bug. #229 --- source/NetCoreServer/IWebSocket.cs | 3 +- source/NetCoreServer/NetCoreServer.csproj | 2 +- source/NetCoreServer/UdpClient.cs | 4 +- source/NetCoreServer/UdpServer.cs | 4 +- source/NetCoreServer/WebSocket.cs | 74 ++++++++++++++--------- source/NetCoreServer/WsClient.cs | 10 +-- source/NetCoreServer/WsSession.cs | 10 +-- source/NetCoreServer/WssClient.cs | 10 +-- source/NetCoreServer/WssSession.cs | 10 +-- 9 files changed, 74 insertions(+), 53 deletions(-) diff --git a/source/NetCoreServer/IWebSocket.cs b/source/NetCoreServer/IWebSocket.cs index 0ea91e8..63f6181 100644 --- a/source/NetCoreServer/IWebSocket.cs +++ b/source/NetCoreServer/IWebSocket.cs @@ -53,7 +53,8 @@ void OnWsReceived(byte[] buffer, long offset, long size) {} /// Received buffer /// Received buffer offset /// Received buffer size - void OnWsClose(byte[] buffer, long offset, long size) {} + /// WebSocket close status (default is 1000) + void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) {} /// /// Handle WebSocket ping notification diff --git a/source/NetCoreServer/NetCoreServer.csproj b/source/NetCoreServer/NetCoreServer.csproj index bd978d8..27df22b 100644 --- a/source/NetCoreServer/NetCoreServer.csproj +++ b/source/NetCoreServer/NetCoreServer.csproj @@ -2,7 +2,7 @@ net6.0 - 6.6.0.0 + 6.7.0.0 Ivan Shynkarenka Copyright (c) 2019-2022 Ivan Shynkarenka https://github.com/chronoxor/NetCoreServer diff --git a/source/NetCoreServer/UdpClient.cs b/source/NetCoreServer/UdpClient.cs index 76f8365..e982277 100644 --- a/source/NetCoreServer/UdpClient.cs +++ b/source/NetCoreServer/UdpClient.cs @@ -457,7 +457,7 @@ public virtual long Send(EndPoint endpoint, ReadOnlySpan buffer) try { // Sent datagram to the server - int sent = Socket.SendTo(buffer, SocketFlags.None, endpoint); + long sent = Socket.SendTo(buffer, SocketFlags.None, endpoint); if (sent > 0) { // Update statistic @@ -632,7 +632,7 @@ public virtual long Receive(ref EndPoint endpoint, byte[] buffer, long offset, l try { // Receive datagram from the server - int received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint); + long received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint); // Update statistic DatagramsReceived++; diff --git a/source/NetCoreServer/UdpServer.cs b/source/NetCoreServer/UdpServer.cs index 250ed5b..13cd1eb 100644 --- a/source/NetCoreServer/UdpServer.cs +++ b/source/NetCoreServer/UdpServer.cs @@ -473,7 +473,7 @@ public virtual long Send(EndPoint endpoint, ReadOnlySpan buffer) try { // Sent datagram to the client - int sent = Socket.SendTo(buffer, SocketFlags.None, endpoint); + long sent = Socket.SendTo(buffer, SocketFlags.None, endpoint); if (sent > 0) { // Update statistic @@ -610,7 +610,7 @@ public virtual long Receive(ref EndPoint endpoint, byte[] buffer, long offset, l try { // Receive datagram from the client - int received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint); + long received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint); // Update statistic DatagramsReceived++; diff --git a/source/NetCoreServer/WebSocket.cs b/source/NetCoreServer/WebSocket.cs index 75d2d73..e33f43e 100644 --- a/source/NetCoreServer/WebSocket.cs +++ b/source/NetCoreServer/WebSocket.cs @@ -253,7 +253,7 @@ public bool PerformServerUpgrade(HttpRequest request, HttpResponse response) /// WebSocket status (default is 0) public void PrepareSendFrame(byte opcode, bool mask, ReadOnlySpan buffer, int status = 0) { - int size = buffer.Length; + long size = (((opcode & WS_CLOSE) == WS_CLOSE) && (buffer.Length > 0)) ? (buffer.Length + 2) : buffer.Length; // Clear the previous WebSocket send buffer WsSendBuffer.Clear(); @@ -263,7 +263,7 @@ public void PrepareSendFrame(byte opcode, bool mask, ReadOnlySpan buffer, // Append WebSocket frame size if (size <= 125) - WsSendBuffer.Append((byte)((size & 0xFF) | (mask ? 0x80 : 0))); + WsSendBuffer.Append((byte)(((int)size & 0xFF) | (mask ? 0x80 : 0))); else if (size <= 65535) { WsSendBuffer.Append((byte)(126 | (mask ? 0x80 : 0))); @@ -284,11 +284,21 @@ public void PrepareSendFrame(byte opcode, bool mask, ReadOnlySpan buffer, } // Resize WebSocket frame buffer - int offset = (int)WsSendBuffer.Size; + long offset = WsSendBuffer.Size; WsSendBuffer.Resize(WsSendBuffer.Size + size); + int index = 0; + + // Append WebSocket close status + if (((opcode & WS_CLOSE) == WS_CLOSE) && (buffer.Length > 0)) + { + index += 2; + WsSendBuffer.Append((byte)((status >> 8) & 0xFF)); + WsSendBuffer.Append((byte)(status & 0xFF)); + } + // Mask WebSocket frame content - for (int i = 0; i < size; i++) + for (int i = index; i < size; i++) WsSendBuffer.Data[offset + i] = (byte)(buffer[i] ^ WsSendMask[i % 4]); } @@ -302,7 +312,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) { lock (WsReceiveLock) { - var index = 0; + int index = 0; // Clear received data after WebSocket frame was processed if (WsFrameReceived) @@ -339,7 +349,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) // Prepare WebSocket frame opcode and mask flag if (WsReceiveFrameBuffer.Size < 2) { - for (int i = 0; i < 2; i++, index++, size--) + for (long i = 0; i < 2; i++, index++, size--) { if (size == 0) return; @@ -350,7 +360,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) 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); + long payload = WsReceiveFrameBuffer[1] & (~0x80); // Prepare WebSocket opcode WsOpcode = (opcode != 0) ? opcode : WsOpcode; @@ -365,7 +375,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) { if (WsReceiveFrameBuffer.Size < 4) { - for (int i = 0; i < 2; i++, index++, size--) + for (long i = 0; i < 2; i++, index++, size--) { if (size == 0) return; @@ -381,7 +391,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) { if (WsReceiveFrameBuffer.Size < 10) { - for (int i = 0; i < 8; i++, index++, size--) + for (long i = 0; i < 8; i++, index++, size--) { if (size == 0) return; @@ -399,7 +409,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) { if (WsReceiveFrameBuffer.Size < WsHeaderSize) { - for (int i = 0; i < 4; i++, index++, size--) + for (long i = 0; i < 4; i++, index++, size--) { if (size == 0) return; @@ -409,12 +419,12 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) } } - int total = WsHeaderSize + WsPayloadSize; - int length = Math.Min(total - (int)WsReceiveFrameBuffer.Size, (int)size); + long total = WsHeaderSize + WsPayloadSize; + long length = Math.Min(total - WsReceiveFrameBuffer.Size, size); // Prepare WebSocket frame payload - WsReceiveFrameBuffer.Append(buffer[((int)offset + index)..((int)offset + index + length)]); - index += length; + WsReceiveFrameBuffer.Append(buffer[((int)offset + index)..((int)offset + index + (int)length)]); + index += (int)length; size -= length; // Process WebSocket frame @@ -423,11 +433,11 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) // Unmask WebSocket frame content if (mask) { - for (int i = 0; i < WsPayloadSize; i++) + for (long i = 0; i < WsPayloadSize; i++) WsReceiveFinalBuffer.Append((byte)(WsReceiveFrameBuffer[WsHeaderSize + i] ^ WsReceiveMask[i % 4])); } else - WsReceiveFinalBuffer.Append(WsReceiveFrameBuffer.AsSpan().Slice(WsHeaderSize, WsPayloadSize)); + WsReceiveFinalBuffer.Append(WsReceiveFrameBuffer.AsSpan().Slice((int)WsHeaderSize, (int)WsPayloadSize)); WsFrameReceived = true; @@ -452,8 +462,18 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) } case WS_CLOSE: { + int sindex = 0; + int status = 1000; + + // Read WebSocket close status + if (WsReceiveFinalBuffer.Size > 2) + { + sindex += 2; + status = ((WsReceiveFinalBuffer[0] << 8) | (WsReceiveFinalBuffer[1] << 0)); + } + // Call the WebSocket close handler - _wsHandler.OnWsClose(WsReceiveFinalBuffer.Data, 0, WsReceiveFinalBuffer.Size); + _wsHandler.OnWsClose(WsReceiveFinalBuffer.Data, sindex, WsReceiveFinalBuffer.Size - sindex, status); break; } case WS_BINARY: @@ -473,7 +493,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size) /// /// Required WebSocket receive frame size /// - public int RequiredReceiveFrameSize() + public long RequiredReceiveFrameSize() { lock (WsReceiveLock) { @@ -482,23 +502,23 @@ public int RequiredReceiveFrameSize() // Required WebSocket frame opcode and mask flag if (WsReceiveFrameBuffer.Size < 2) - return 2 - (int)WsReceiveFrameBuffer.Size; + return 2 - WsReceiveFrameBuffer.Size; bool mask = ((WsReceiveFrameBuffer[1] >> 7) & 0x01) != 0; - int payload = WsReceiveFrameBuffer[1] & (~0x80); + long payload = WsReceiveFrameBuffer[1] & (~0x80); // Required WebSocket frame size if ((payload == 126) && (WsReceiveFrameBuffer.Size < 4)) - return 4 - (int)WsReceiveFrameBuffer.Size; + return 4 - WsReceiveFrameBuffer.Size; if ((payload == 127) && (WsReceiveFrameBuffer.Size < 10)) - return 10 - (int)WsReceiveFrameBuffer.Size; + return 10 - WsReceiveFrameBuffer.Size; // Required WebSocket frame mask if ((mask) && (WsReceiveFrameBuffer.Size < WsHeaderSize)) - return WsHeaderSize - (int)WsReceiveFrameBuffer.Size; + return WsHeaderSize - WsReceiveFrameBuffer.Size; // Required WebSocket frame payload - return WsHeaderSize + WsPayloadSize - (int)WsReceiveFrameBuffer.Size; + return WsHeaderSize + WsPayloadSize - WsReceiveFrameBuffer.Size; } } @@ -561,15 +581,15 @@ public void ClearWsBuffers() /// /// Received frame opcode /// - internal int WsOpcode; + internal byte WsOpcode; /// /// Received frame header size /// - internal int WsHeaderSize; + internal long WsHeaderSize; /// /// Received frame payload size /// - internal int WsPayloadSize; + internal long WsPayloadSize; /// /// Receive buffer lock diff --git a/source/NetCoreServer/WsClient.cs b/source/NetCoreServer/WsClient.cs index 46fa9e7..ce7bbb7 100644 --- a/source/NetCoreServer/WsClient.cs +++ b/source/NetCoreServer/WsClient.cs @@ -220,9 +220,9 @@ public string ReceiveText() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = base.Receive(cache.Data, 0, required); if (received != required) return result.ExtractString(0, result.Data.Length); WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -251,9 +251,9 @@ public Buffer ReceiveBinary() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = base.Receive(cache.Data, 0, required); if (received != required) return result; WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -378,7 +378,7 @@ public virtual void OnWsConnected(HttpRequest request) {} public virtual void OnWsDisconnecting() {} public virtual void OnWsDisconnected() {} public virtual void OnWsReceived(byte[] buffer, long offset, long size) {} - public virtual void OnWsClose(byte[] buffer, long offset, long size) { CloseAsync(1000); } + public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { CloseAsync(status); } public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); } public virtual void OnWsPong(byte[] buffer, long offset, long size) {} public virtual void OnWsError(string error) { OnError(SocketError.SocketError); } diff --git a/source/NetCoreServer/WsSession.cs b/source/NetCoreServer/WsSession.cs index 2296244..a81f4ab 100644 --- a/source/NetCoreServer/WsSession.cs +++ b/source/NetCoreServer/WsSession.cs @@ -187,9 +187,9 @@ public string ReceiveText() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = base.Receive(cache.Data, 0, required); if (received != required) return result.ExtractString(0, result.Data.Length); WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -218,9 +218,9 @@ public Buffer ReceiveBinary() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = base.Receive(cache.Data, 0, required); if (received != required) return result; WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -330,7 +330,7 @@ public virtual void OnWsConnected(HttpRequest request) {} public virtual void OnWsDisconnecting() {} public virtual void OnWsDisconnected() {} public virtual void OnWsReceived(byte[] buffer, long offset, long size) {} - public virtual void OnWsClose(byte[] buffer, long offset, long size) { Close(1000); } + public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { Close(status); } public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); } public virtual void OnWsPong(byte[] buffer, long offset, long size) {} public virtual void OnWsError(string error) { OnError(SocketError.SocketError); } diff --git a/source/NetCoreServer/WssClient.cs b/source/NetCoreServer/WssClient.cs index bc4906b..263b412 100644 --- a/source/NetCoreServer/WssClient.cs +++ b/source/NetCoreServer/WssClient.cs @@ -224,9 +224,9 @@ public string ReceiveText() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = (int)base.Receive(cache.Data, 0, required); if (received != required) return result.ExtractString(0, result.Data.Length); WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -255,9 +255,9 @@ public Buffer ReceiveBinary() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = (int)base.Receive(cache.Data, 0, required); if (received != required) return result; WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -382,7 +382,7 @@ public virtual void OnWsConnected(HttpRequest request) {} public virtual void OnWsDisconnecting() {} public virtual void OnWsDisconnected() {} public virtual void OnWsReceived(byte[] buffer, long offset, long size) {} - public virtual void OnWsClose(byte[] buffer, long offset, long size) { CloseAsync(1000); } + public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { CloseAsync(status); } public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); } public virtual void OnWsPong(byte[] buffer, long offset, long size) {} public virtual void OnWsError(string error) { OnError(SocketError.SocketError); } diff --git a/source/NetCoreServer/WssSession.cs b/source/NetCoreServer/WssSession.cs index c0fb4da..7553d0b 100644 --- a/source/NetCoreServer/WssSession.cs +++ b/source/NetCoreServer/WssSession.cs @@ -187,9 +187,9 @@ public string ReceiveText() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = base.Receive(cache.Data, 0, required); if (received != required) return result.ExtractString(0, result.Data.Length); WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -218,9 +218,9 @@ public Buffer ReceiveBinary() { while (!WebSocket.WsFrameReceived) { - int required = WebSocket.RequiredReceiveFrameSize(); + long required = WebSocket.RequiredReceiveFrameSize(); cache.Resize(required); - int received = (int)base.Receive(cache.Data, 0, required); + long received = base.Receive(cache.Data, 0, required); if (received != required) return result; WebSocket.PrepareReceiveFrame(cache.Data, 0, received); @@ -330,7 +330,7 @@ public virtual void OnWsConnected(HttpRequest request) {} public virtual void OnWsDisconnecting() {} public virtual void OnWsDisconnected() {} public virtual void OnWsReceived(byte[] buffer, long offset, long size) {} - public virtual void OnWsClose(byte[] buffer, long offset, long size) { Close(1000); } + public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { Close(status); } public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); } public virtual void OnWsPong(byte[] buffer, long offset, long size) {} public virtual void OnWsError(string error) { OnError(SocketError.SocketError); }