private void ParseHeader(Int32 readed) { if (!TryReadHeaderUntil(ref readed, 6)) { Close(WebSocketCloseReasons.ProtocolError); return; } Int32 headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset); if (!TryReadHeaderUntil(ref readed, headerlength)) { Close(WebSocketCloseReasons.ProtocolError); return; } WebSocketFrameHeader header; if (!WebSocketFrameHeader.TryParse(_headerBuffer.Array, _headerBuffer.Offset, headerlength, _keyBuffer, out header)) { throw new WebSocketException("Cannot understand frame header"); } CurrentHeader = header; if (!header.Flags.Option.IsData()) { ProcessControlFrame(_clientStream); CurrentHeader = null; } else { _ongoingMessageAwaiting = 0; } }
public ArraySegment <byte> PrepareFrame(ArraySegment <byte> payload, int length, bool isCompleted, bool headerSent, WebSocketMessageType type, WebSocketExtensionFlags extensionFlags) { var mask = 0U; if (this.maskData) { mask = unchecked ((uint)ThreadStaticRandom.NextNotZero()); } var header = WebSocketFrameHeader.Create(length, isCompleted, headerSent, mask, (WebSocketFrameOption)type, extensionFlags); if (header.WriteTo(payload.Array, payload.Offset - header.HeaderLength) != header.HeaderLength) { throw new WebSocketException("Wrong frame header written."); } if (this.log.IsDebugEnabled) { this.log.Debug($"({this.GetHashCode():X}) [FRAME->] {header}"); } header.EncodeBytes(payload.Array, payload.Offset, length); return(new ArraySegment <byte>(payload.Array, payload.Offset - header.HeaderLength, length + header.HeaderLength)); }
internal async Task WriteInternalAsync(ArraySegment <byte> buffer, int count, bool isCompleted, bool headerSent, WebSocketFrameOption option, WebSocketExtensionFlags extensionFlags, CancellationToken cancel) { try { var header = WebSocketFrameHeader.Create(count, isCompleted, headerSent, option, extensionFlags); header.ToBytes(buffer.Array, buffer.Offset - header.HeaderLength); if (!await _writeSemaphore.WaitAsync(_options.WebSocketSendTimeout, cancel).ConfigureAwait(false)) { throw new WebSocketException("Write timeout"); } await _clientStream.WriteAsync(buffer.Array, buffer.Offset - header.HeaderLength, count + header.HeaderLength, cancel).ConfigureAwait(false); } catch (OperationCanceledException) { Close(WebSocketCloseReasons.GoingAway); } catch (InvalidOperationException) { Close(WebSocketCloseReasons.UnexpectedCondition); } catch (IOException) { Close(WebSocketCloseReasons.UnexpectedCondition); } catch (Exception ex) { Close(WebSocketCloseReasons.UnexpectedCondition); throw new WebSocketException("Cannot write on WebSocket", ex); } finally { SafeEnd.ReleaseSemaphore(_writeSemaphore); } }
private async Task WriteInternalAsync(ArraySegment <Byte> buffer, Int32 count, Boolean isCompleted, Boolean headerSent, WebSocketFrameOption option, WebSocketExtensionFlags extensionFlags, CancellationToken cancellation) { CancellationTokenRegistration reg = cancellation.Register(this.Close, false); try { var header = WebSocketFrameHeader.Create(count, isCompleted, headerSent, option, extensionFlags); header.ToBytes(buffer.Array, buffer.Offset - header.HeaderLength); if (!_writeSemaphore.Wait(_options.WebSocketSendTimeout)) { throw new WebSocketException("Write timeout"); } await _clientStream.WriteAsync(buffer.Array, buffer.Offset - header.HeaderLength, count + header.HeaderLength, cancellation).ConfigureAwait(false); } catch (InvalidOperationException) { Close(WebSocketCloseReasons.UnexpectedCondition); } catch (IOException) { Close(WebSocketCloseReasons.UnexpectedCondition); } catch (Exception ex) { Close(WebSocketCloseReasons.UnexpectedCondition); throw new WebSocketException("Cannot write on WebSocket", ex); } finally { reg.Dispose(); _writeSemaphore.Release(); } }
internal void WriteInternal(ArraySegment <Byte> buffer, Int32 count, Boolean isCompleted, Boolean headerSent, WebSocketFrameOption option, WebSocketExtensionFlags extensionFlags) { try { var header = WebSocketFrameHeader.Create(count, isCompleted, headerSent, option, extensionFlags); header.ToBytes(buffer.Array, buffer.Offset - header.HeaderLength); if (!_writeSemaphore.Wait(_options.WebSocketSendTimeout)) { throw new WebSocketException("Write timeout"); } _clientStream.Write(buffer.Array, buffer.Offset - header.HeaderLength, count + header.HeaderLength); } catch (InvalidOperationException) { Close(WebSocketCloseReasons.UnexpectedCondition); } catch (IOException) { Close(WebSocketCloseReasons.UnexpectedCondition); } catch (Exception ex) { Close(WebSocketCloseReasons.UnexpectedCondition); throw new WebSocketException("Cannot write on WebSocket", ex); } finally { if (_isClosed == 0) { SafeEnd.ReleaseSemaphore(_writeSemaphore); } } }
public void DisposeCurrentHeaderIfFinished() { if (this.CurrentHeader != null && this.CurrentHeader.RemainingBytes < 0) { throw new InvalidOperationException("Extra bytes are read from transport connection. Report to package developer about it."); } if (this.CurrentHeader != null && this.CurrentHeader.RemainingBytes == 0) { this.CurrentHeader = null; } }
private int GetBytesToRead(WebSocketFrameHeader header, int bufferSize) { if (bufferSize <= 0) { throw new ArgumentOutOfRangeException(nameof(bufferSize)); } if (header == null) { return(0); } return((int)Math.Min(bufferSize, header.RemainingBytes)); }
private void ParseHeader(int readed) { if (!TryReadHeaderUntil(ref readed, 6)) { Close(WebSocketCloseReasons.ProtocolError); return; } var headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset); if (!TryReadHeaderUntil(ref readed, headerlength)) { Close(WebSocketCloseReasons.ProtocolError); return; } ProcessHeaderFrame(headerlength); }
private async Task ParseHeaderAsync(int readed) { if (await TryReadHeaderUntilAsync(readed, 6).ConfigureAwait(false) == -1) { Close(WebSocketCloseReasons.ProtocolError); return; } var headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset); if (await TryReadHeaderUntilAsync(readed, headerlength).ConfigureAwait(false) == -1) { Close(WebSocketCloseReasons.ProtocolError); return; } await ProcessHeaderFrameAsync(headerlength).ConfigureAwait(false); }
private async Task ReadHeader(CancellationToken cancellation) { Int32 readed = 0; var success = await TryReadHeaderUntil(readed, 6, cancellation).ConfigureAwait(false); if (!success) { Close(WebSocketCloseReasons.ProtocolError); return; } readed += 6; Int32 headerlength = WebSocketFrameHeader.GetHeaderLength(_headerBuffer.Array, _headerBuffer.Offset); success = await TryReadHeaderUntil(readed, headerlength, cancellation).ConfigureAwait(false); if (!success) { Close(WebSocketCloseReasons.ProtocolError); return; } WebSocketFrameHeader header; if (!WebSocketFrameHeader.TryParse(_headerBuffer.Array, _headerBuffer.Offset, headerlength, _keyBuffer, out header)) { throw new WebSocketException("Cannot understand frame header"); } CurrentHeader = header; if (!header.Flags.Option.IsData()) { ProcessControlFrame(_clientStream); CurrentHeader = null; } else { _ongoingMessageAwaiting = 0; } _ping.NotifyActivity(); }
private void ProcessHeaderFrame(int headerlength) { if (!WebSocketFrameHeader.TryParse(_headerBuffer.Array, _headerBuffer.Offset, headerlength, _keyBuffer, out WebSocketFrameHeader header)) { throw new WebSocketException("Cannot understand frame header"); } CurrentHeader = header; if (!header.Flags.Option.IsData()) { ProcessControlFrame(); CurrentHeader = null; } else { _ongoingMessageAwaiting = 0; } _ping.NotifyActivity(); }
private async Task ParseHeaderAsync(int read) { if (read < 2) { if (this.log.IsWarningEnabled) { this.log.Warning($"{nameof(this.ParseHeaderAsync)} is called with only {read} bytes buffer. Minimal is 2 bytes."); } await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false); return; } var headerLength = WebSocketFrameHeader.GetHeaderLength(this.headerBuffer.Array, this.headerBuffer.Offset); if (read != headerLength) { if (this.log.IsWarningEnabled) { this.log.Warning($"{nameof(this.ParseHeaderAsync)} is called with {read} bytes buffer. While whole header is {headerLength} bytes length."); } await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false); return; } WebSocketFrameHeader header; if (!WebSocketFrameHeader.TryParse(this.headerBuffer.Array, this.headerBuffer.Offset, headerLength, out header)) { throw new WebSocketException("Frame header is malformed."); } if (this.log.IsDebugEnabled) { this.log.Debug($"({this.GetHashCode():X}) [FRAME<-] {header}"); } this.CurrentHeader = header; if (!header.Flags.Option.IsData()) { await this.ProcessControlFrameAsync().ConfigureAwait(false); this.CurrentHeader = null; } else { this.ongoingMessageAwaiting = 0; } try { this.pingHandler.NotifyActivity(); } catch (Exception notifyPingError) { if (this.log.IsWarningEnabled) { this.log.Warning($"({this.GetHashCode():X}) An error occurred while trying to call {this.pingHandler.GetType().Name}.{nameof(this.pingHandler.NotifyActivity)}() method.", notifyPingError); } } }
public static bool TryParse(byte[] frameStart, int offset, int headerLength, out WebSocketFrameHeader header) { if (frameStart == null) { throw new ArgumentNullException(nameof(frameStart)); } header = null; var availableLength = frameStart.Length - offset; if (availableLength < 6 || availableLength < headerLength) { return(false); } var value = frameStart[offset + 1]; var contentLength = (long)(value >= 128 ? value - 128 : value); if (contentLength <= 125) { // small frame } else if (contentLength == 126) { if (availableLength < headerLength) { return(false); } contentLength = EndianBitConverter.ToUInt16Be(frameStart, offset + 2); } else if (contentLength == 127) { if (availableLength < headerLength) { return(false); } var length = EndianBitConverter.ToUInt64Be(frameStart, offset + 2); if (length > long.MaxValue) { throw new WebSocketException("The maximum supported frame length is 9223372036854775807, current frame is " + length.ToString()); } contentLength = (long)length; } else { return(false); } WebSocketFrameHeaderFlags flags; if (!WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags)) { return(false); } var maskKey = 0U; if (flags.MASK) { headerLength -= 4; maskKey = EndianBitConverter.ToUInt32Le(frameStart, offset + headerLength); } header = new WebSocketFrameHeader { ContentLength = contentLength, HeaderLength = headerLength, Flags = flags, RemainingBytes = contentLength, MaskKey = maskKey }; return(true); }
public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment<Byte> keySegment, out WebSocketFrameHeader header) { header = null; if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength)) return false; Int32 value = frameStart[offset+1]; UInt64 contentLength = (UInt64)(value>=128?value - 128:value); if (contentLength <= 125) { // small frame } else if (contentLength == 126) { if (frameStart.Length < headerLength) return false; if(BitConverter.IsLittleEndian) frameStart.ReversePortion(offset + 2, 2); contentLength = BitConverter.ToUInt16(frameStart, 2); } else if (contentLength == 127) { if (frameStart.Length < headerLength) return false; if (BitConverter.IsLittleEndian) frameStart.ReversePortion(offset + 2, 8); contentLength = (UInt64)BitConverter.ToUInt64(frameStart, 2); } else return false; WebSocketFrameHeaderFlags flags; if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags)) { header = new WebSocketFrameHeader(keySegment) { ContentLength = contentLength, HeaderLength = headerLength, Flags = flags, RemainingBytes = contentLength }; if (flags.MASK) { headerLength -= 4; for (int i = 0; i < 4; i++) header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength]; } return true; } return false; }
public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment <Byte> keySegment, out WebSocketFrameHeader header) { header = null; if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength)) { return(false); } Int32 value = frameStart[offset + 1]; UInt64 contentLength = (UInt64)(value >= 128?value - 128:value); if (contentLength <= 125) { // small frame } else if (contentLength == 126) { if (frameStart.Length < headerLength) { return(false); } if (BitConverter.IsLittleEndian) { frameStart.ReversePortion(offset + 2, 2); } contentLength = BitConverter.ToUInt16(frameStart, 2); } else if (contentLength == 127) { if (frameStart.Length < headerLength) { return(false); } if (BitConverter.IsLittleEndian) { frameStart.ReversePortion(offset + 2, 8); } contentLength = (UInt64)BitConverter.ToUInt64(frameStart, 2); } else { return(false); } WebSocketFrameHeaderFlags flags; if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags)) { header = new WebSocketFrameHeader(keySegment) { ContentLength = contentLength, HeaderLength = headerLength, Flags = flags, RemainingBytes = contentLength }; if (flags.MASK) { headerLength -= 4; for (int i = 0; i < 4; i++) { header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength]; } } return(true); } return(false); }
public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment <Byte> keySegment, out WebSocketFrameHeader header) { header = null; if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength)) { return(false); } Int32 value = frameStart[offset + 1]; Int64 contentLength = (Int64)(value >= 128?value - 128:value); if (contentLength <= 125) { // small frame } else if (contentLength == 126) { if (frameStart.Length < headerLength) { return(false); } if (BitConverter.IsLittleEndian) { frameStart.ReversePortion(offset + 2, 2); } contentLength = BitConverter.ToUInt16(frameStart, 2); } else if (contentLength == 127) { if (frameStart.Length < headerLength) { return(false); } if (BitConverter.IsLittleEndian) { frameStart.ReversePortion(offset + 2, 8); } UInt64 length = BitConverter.ToUInt64(frameStart, 2); if (length > Int64.MaxValue) { throw new WebSocketException("The maximum supported frame length is 9223372036854775807, current frame is " + length.ToString()); } contentLength = (Int64)length; } else { return(false); } WebSocketFrameHeaderFlags flags; if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags)) { header = new WebSocketFrameHeader(keySegment) { ContentLength = contentLength, HeaderLength = headerLength, Flags = flags, RemainingBytes = contentLength }; if (flags.MASK) { headerLength -= 4; for (int i = 0; i < 4; i++) { header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength]; } } return(true); } return(false); }
public static Boolean TryParse(Byte[] frameStart, Int32 offset, Int32 headerLength, ArraySegment<Byte> keySegment, out WebSocketFrameHeader header) { header = null; if (frameStart == null || frameStart.Length < 6 || frameStart.Length < (offset + headerLength)) return false; Int32 value = frameStart[offset+1]; Int64 contentLength = (Int64)(value>=128?value - 128:value); if (contentLength <= 125) { // small frame } else if (contentLength == 126) { if (frameStart.Length < headerLength) return false; if(BitConverter.IsLittleEndian) frameStart.ReversePortion(offset + 2, 2); contentLength = BitConverter.ToUInt16(frameStart, 2); } else if (contentLength == 127) { if (frameStart.Length < headerLength) return false; if (BitConverter.IsLittleEndian) frameStart.ReversePortion(offset + 2, 8); UInt64 length = BitConverter.ToUInt64(frameStart, 2); if(length > Int64.MaxValue) { throw new WebSocketException("The maximum supported frame length is 9223372036854775807, current frame is " + length.ToString()); } contentLength = (Int64)length; } else return false; WebSocketFrameHeaderFlags flags; if (WebSocketFrameHeaderFlags.TryParse(frameStart, offset, out flags)) { header = new WebSocketFrameHeader(keySegment) { ContentLength = contentLength, HeaderLength = headerLength, Flags = flags, RemainingBytes = contentLength }; if (flags.MASK) { headerLength -= 4; for (int i = 0; i < 4; i++) header._key.Array[header._key.Offset + i] = frameStart[offset + i + headerLength]; } return true; } return false; }
public async Task AwaitHeaderAsync(CancellationToken cancellation) { this.CheckForDoubleRead(); try { while (this.IsConnected && this.CurrentHeader == null) { var buffered = 0; var estimatedHeaderLength = 2; // try read minimal frame first while (buffered < estimatedHeaderLength && !cancellation.IsCancellationRequested) { var read = await this.networkConnection.ReadAsync(this.headerBuffer.Array, this.headerBuffer.Offset + buffered, estimatedHeaderLength - buffered, cancellation).ConfigureAwait(false); if (read == 0) { buffered = 0; break; } buffered += read; if (buffered >= 2) { estimatedHeaderLength = WebSocketFrameHeader.GetHeaderLength(this.headerBuffer.Array, this.headerBuffer.Offset); } } if (buffered == 0 || cancellation.IsCancellationRequested) { if (buffered == 0) { if (this.log.IsDebugEnabled) { this.log.Debug($"({this.GetHashCode():X}) Connection has been closed while async awaiting header."); } } await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false); return; } await this.ParseHeaderAsync(buffered).ConfigureAwait(false); } } catch (Exception awaitHeaderError) when(awaitHeaderError.Unwrap() is ThreadAbortException == false) { if (!this.IsConnected) { return; } var awaitHeaderErrorUnwrap = awaitHeaderError.Unwrap(); if (this.log.IsDebugEnabled && awaitHeaderErrorUnwrap is OperationCanceledException == false && this.IsConnected) { this.log.Debug($"({this.GetHashCode():X}) An error occurred while async awaiting header.", awaitHeaderErrorUnwrap); } if (this.IsConnected) { await this.CloseAsync(WebSocketCloseReasons.ProtocolError).ConfigureAwait(false); } if (awaitHeaderErrorUnwrap is WebSocketException == false && awaitHeaderErrorUnwrap is OperationCanceledException == false) { throw new WebSocketException("Read operation on WebSocket stream is failed. More detailed information in inner exception.", awaitHeaderErrorUnwrap); } else { throw; } } }