public void DecodePayload(byte[] buffer, int offset, Header frameHeader, out byte[] payload, out int payloadOffset, out int payloadCount) { payload = buffer; payloadOffset = offset + frameHeader.Length; payloadCount = frameHeader.PayloadLength; if (frameHeader.IsMasked) { payload = new byte[payloadCount]; for (var i = 0; i < payloadCount; i++) { payload[i] = (byte)(buffer[payloadOffset + i] ^ buffer[offset + frameHeader.MaskingKeyOffset + i % MaskingKeyLength]); } payloadOffset = 0; payloadCount = payload.Length; } // Payload data: (x+y) bytes // Extension data: x bytes // Application data: y bytes // The "Extension data" is 0 bytes unless an extension has been // negotiated. Any extension MUST specify the length of the // "Extension data", or how that length may be calculated, and how // the extension use MUST be negotiated during the opening handshake. // If present, the "Extension data" is included in the total payload length. if (this.NegotiatedExtensions != null) { byte[] bakedBuffer = null; foreach (var extension in this.NegotiatedExtensions.Reverse().Select(e => e.Value)) { if (bakedBuffer == null) { bakedBuffer = extension.ProcessIncomingMessagePayload(payload, payloadOffset, payloadCount); } else { bakedBuffer = extension.ProcessIncomingMessagePayload(bakedBuffer, 0, bakedBuffer.Length); } } payload = bakedBuffer; payloadOffset = 0; payloadCount = payload.Length; } }
public bool TryDecodeFrameHeader(byte[] buffer, int offset, int count, out Header frameHeader) { frameHeader = DecodeFrameHeader(buffer, offset, count); return frameHeader != null; }
private Header DecodeFrameHeader(byte[] buffer, int offset, int count) { if (count < 2) return null; // parse fixed header var header = new Header() { IsFIN = ((buffer[offset + 0] & 0x80) == 0x80), IsRSV1 = ((buffer[offset + 0] & 0x40) == 0x40), IsRSV2 = ((buffer[offset + 0] & 0x20) == 0x20), IsRSV3 = ((buffer[offset + 0] & 0x10) == 0x10), OpCode = (OpCode)(buffer[offset + 0] & 0x0f), IsMasked = ((buffer[offset + 1] & 0x80) == 0x80), PayloadLength = (buffer[offset + 1] & 0x7f), Length = 2, }; // parse extended payload length if (header.PayloadLength >= 126) { if (header.PayloadLength == 126) header.Length += 2; else header.Length += 8; if (count < header.Length) return null; if (header.PayloadLength == 126) { header.PayloadLength = buffer[offset + 2] * 256 + buffer[offset + 3]; } else { int totalLength = 0; int level = 1; for (int i = 7; i >= 0; i--) { totalLength += buffer[offset + i + 2] * level; level *= 256; } header.PayloadLength = totalLength; } } // parse masking key if (header.IsMasked) { if (count < header.Length + MaskingKeyLength) return null; header.MaskingKeyOffset = header.Length; header.Length += MaskingKeyLength; } return header; }
private async Task HandlePingFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (!frameHeader.IsFIN) { throw new WebSocketException(string.Format( "Server received unfinished frame [{0}] from remote [{1}].", frameHeader.OpCode, RemoteEndPoint)); } // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in // response, unless it already received a Close frame. It SHOULD // respond with Pong frame as soon as is practical. Pong frames are // discussed in Section 5.5.3. // // An endpoint MAY send a Ping frame any time after the connection is // established and before the connection is closed. // // A Ping frame may serve either as a keep-alive or as a means to // verify that the remote endpoint is still responsive. var ping = Encoding.UTF8.GetString(payload, payloadOffset, payloadCount); #if DEBUG _log.DebugFormat("Session [{0}] received client side ping frame [{1}].", this, ping); #endif if (State == WebSocketState.Open) { // A Pong frame sent in response to a Ping frame must have identical // "Application data" as found in the message body of the Ping frame being replied to. var pong = new PongFrame(ping, false).ToArray(_frameBuilder); await SendFrame(pong); #if DEBUG _log.DebugFormat("Session [{0}] sends server side pong frame [{1}].", this, ping); #endif } }
private async Task HandlePongFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (!frameHeader.IsFIN) { throw new WebSocketException(string.Format( "Server received unfinished frame [{0}] from remote [{1}].", frameHeader.OpCode, RemoteEndPoint)); } // If an endpoint receives a Ping frame and has not yet sent Pong // frame(s) in response to previous Ping frame(s), the endpoint MAY // elect to send a Pong frame for only the most recently processed Ping frame. // // A Pong frame MAY be sent unsolicited. This serves as a // unidirectional heartbeat. A response to an unsolicited Pong frame is not expected. var pong = Encoding.UTF8.GetString(payload, payloadOffset, payloadCount); StopKeepAliveTimeoutTimer(); #if DEBUG _log.DebugFormat("Session [{0}] received client side pong frame [{1}].", this, pong); #endif await Task.CompletedTask; }
private async Task HandleBinaryFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (frameHeader.IsFIN) { try { await _module.OnSessionBinaryReceived(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } } else { try { await _module.OnSessionFragmentationStreamOpened(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } } }
private async Task HandleCloseFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (!frameHeader.IsFIN) { throw new WebSocketException(string.Format( "Server received unfinished frame [{0}] from remote [{1}].", frameHeader.OpCode, RemoteEndPoint)); } if (payloadCount > 1) { var statusCode = payload[payloadOffset + 0] * 256 + payload[payloadOffset + 1]; var closeCode = (WebSocketCloseCode)statusCode; var closeReason = string.Empty; if (payloadCount > 2) { closeReason = Encoding.UTF8.GetString(payload, payloadOffset + 2, payloadCount - 2); } #if DEBUG _log.DebugFormat("Session [{0}] received client side close frame [{1}] [{2}].", this, closeCode, closeReason); #endif // If an endpoint receives a Close frame and did not previously send a // Close frame, the endpoint MUST send a Close frame in response. (When // sending a Close frame in response, the endpoint typically echos the // status code it received.) It SHOULD do so as soon as practical. await Close(closeCode, closeReason); } else { #if DEBUG _log.DebugFormat("Session [{0}] received client side close frame but no status code.", this); #endif await Close(WebSocketCloseCode.InvalidPayloadData); } }
private async Task HandleTextFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (frameHeader.IsFIN) { try { var text = Encoding.UTF8.GetString(payload, payloadOffset, payloadCount); await _module.OnSessionTextReceived(this, text); } catch (Exception ex) { HandleUserSideError(ex); } } else { try { await _module.OnSessionFragmentationStreamOpened(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } } }
private async Task HandleContinuationFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (!frameHeader.IsFIN) { try { await _module.OnSessionFragmentationStreamContinued(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } } else { try { await _module.OnSessionFragmentationStreamClosed(this, payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } } }
public void DecodePayload(byte[] buffer, int offset, Header frameHeader, out byte[] payload, out int payloadOffset, out int payloadCount) { payload = buffer; payloadOffset = offset + frameHeader.Length; payloadCount = frameHeader.PayloadLength; if (frameHeader.IsMasked) { payload = new byte[payloadCount]; for (var i = 0; i < payloadCount; i++) { payload[i] = (byte)(buffer[payloadOffset + i] ^ buffer[offset + frameHeader.MaskingKeyOffset + i % MaskingKeyLength]); } payloadOffset = 0; payloadCount = payload.Length; } }
private void HandleBinaryFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { if (frameHeader.IsFIN) { try { RaiseServerBinaryReceived(payload, payloadOffset, payloadCount); } catch (Exception ex) { HandleUserSideError(ex); } } else { throw new WebSocketException(string.Format( "Client received continuation opcode [{0}] from remote [{1}] but not supported.", frameHeader.OpCode, RemoteEndPoint)); } }
private void HandleContinuationFrame(Header frameHeader, byte[] payload, int payloadOffset, int payloadCount) { throw new WebSocketException(string.Format( "Client received continuation opcode [{0}] from remote [{1}] but not supported.", frameHeader.OpCode, RemoteEndPoint)); }