/// <summary> /// Returns a new WebSocketFrameHeader constructed from a set of fragments. /// </summary> /// <param name="fragmentStart">The header of the frame that started the set of fragments.</param> /// <param name="payloadLength">The combined total length of the payloads of all fragments in the set.</param> /// <returns></returns> internal static WebSocketFrameHeader FromFragments(WebSocketFrameHeader fragmentStart, int payloadLength) { WebSocketFrameHeader h = new WebSocketFrameHeader(fragmentStart); h.payloadLength = (ulong)payloadLength; return(h); }
internal WebSocketFrameHeader(WebSocketFrameHeader other) { fin = other.fin; opcode = other.opcode; mask = other.mask; maskBytes = other.maskBytes; payloadLength = other.payloadLength; }
internal void SendFrame(WebSocketOpcode opcode, byte[] data) { lock (sendLock) { // Write frame header WebSocketFrameHeader head = new WebSocketFrameHeader(opcode, data.Length); head.Write(tcpStream); // Write payload tcpStream.Write(data, 0, data.Length); } }
internal WebSocketBinaryFrame(WebSocketFrameHeader head, Stream stream) : base(head) { if (!head.fin || head.opcode == WebSocketOpcode.Continuation) { throw new WebSocketException(WebSocketCloseCode.InternalError, "WebSocketBinaryFrame stream constructor is not compatible with fragmented frames."); } if (head.payloadLength > (ulong)WebSocket.MAX_PAYLOAD_BYTES) { throw new WebSocketException(WebSocketCloseCode.MessageTooBig, null); } this.Data = ByteUtil.ReadNBytes(stream, (int)head.payloadLength); Head.XORMask(this.Data); }
internal WebSocketCloseFrame(WebSocketFrameHeader head, Stream stream) : base(head, stream) { if (Data.Length > 1) { CloseCode = (WebSocketCloseCode)ByteUtil.ReadInt16(Data, 0); } else { CloseCode = WebSocketCloseCode.None; } if (Data.Length > 2) { Message = ByteUtil.ReadUtf8(Data, 2, Data.Length - 2); } }
private void WebSocketRead() { WebSocketCloseFrame closeFrame = null; try { WebSocketFrameHeader fragmentStart = null; List <byte[]> fragments = new List <byte[]>(); ulong totalLength = 0; while (true) { WebSocketFrameHeader head = new WebSocketFrameHeader(tcpStream); if (head.opcode == WebSocketOpcode.Close) { closeFrame = new WebSocketCloseFrame(head, tcpStream); Send(WebSocketCloseCode.Normal); //SimpleHttpLogger.LogVerbose("WebSocket connection closed with code: " // + (ushort)closeFrame.CloseCode // + " (" + closeFrame.CloseCode + ")" // + (!string.IsNullOrEmpty(closeFrame.Message) ? " -- \"" + closeFrame.Message + "\"" : "")); return; } else if (head.opcode == WebSocketOpcode.Ping) { WebSocketPingFrame pingFrame = new WebSocketPingFrame(head, tcpStream); SendFrame(WebSocketOpcode.Pong, pingFrame.Data); continue; } else if (head.opcode == WebSocketOpcode.Pong) { WebSocketPongFrame pingFrame = new WebSocketPongFrame(head, tcpStream); continue; } else if (head.opcode == WebSocketOpcode.Continuation || head.opcode == WebSocketOpcode.Text || head.opcode == WebSocketOpcode.Binary) { // The WebSocket protocol supports payload fragmentation, which is the // reason for much of the complexity to follow. // (The primary purpose of fragmentation is to allow sending a message // that is of unknown size when the message is started without having to // buffer that message.) // Validate Payload Length totalLength += head.payloadLength; if (totalLength > (ulong)MAX_PAYLOAD_BYTES) { throw new WebSocketException(WebSocketCloseCode.MessageTooBig); } // Keep track of the frame that started each set of fragments if (fragmentStart == null) { if (head.opcode == WebSocketOpcode.Continuation) { throw new WebSocketException(WebSocketCloseCode.ProtocolError, "Continuation frame did not follow a Text or Binary frame."); } fragmentStart = head; } // Read the Frame's Payload fragments.Add(ByteUtil.ReadNBytes(tcpStream, (int)head.payloadLength)); if (head.fin) { // This ends a set of 1 or more fragments. // Assemble the final payload. byte[] payload; if (fragments.Count == 1) { payload = fragments[0]; } else { // We must assemble a fragmented payload. payload = new byte[(int)totalLength]; int soFar = 0; for (int i = 0; i < fragments.Count; i++) { byte[] part = fragments[i]; fragments[i] = null; Array.Copy(part, 0, payload, soFar, part.Length); soFar += part.Length; } } // Call onMessageReceived callback try { if (fragmentStart.opcode == WebSocketOpcode.Text) { onMessageReceived(new WebSocketTextFrame(fragmentStart, payload)); } else { onMessageReceived(new WebSocketBinaryFrame(fragmentStart, payload)); } } catch (ThreadAbortException) { } catch (Exception ex) { if (!HttpProcessor.IsOrdinaryDisconnectException(ex)) { SimpleHttpLogger.Log(ex); } } // Reset fragmentation state fragmentStart = null; fragments.Clear(); totalLength = 0; } } } } catch (ThreadAbortException) { if (closeFrame == null) { closeFrame = new WebSocketCloseFrame(); closeFrame.CloseCode = WebSocketCloseCode.Normal; } Try.Swallow(() => { tcpClient.SendTimeout = Math.Min(tcpClient.SendTimeout, 1000); Send(closeFrame.CloseCode); }); } catch (Exception ex) { bool isDisconnect = HttpProcessor.IsOrdinaryDisconnectException(ex); if (!isDisconnect) { SimpleHttpLogger.LogVerbose(ex); } if (closeFrame == null) { closeFrame = new WebSocketCloseFrame(); closeFrame.CloseCode = isDisconnect ? WebSocketCloseCode.ConnectionLost : WebSocketCloseCode.InternalError; } Try.Swallow(() => { Send(closeFrame.CloseCode); }); } finally { try { if (closeFrame == null) { // This should not happen, but it is possible that further development could leave a code path where closeFrame did not get set. closeFrame = new WebSocketCloseFrame(); closeFrame.CloseCode = WebSocketCloseCode.InternalError; } onClose(closeFrame); } catch (ThreadAbortException) { } catch (Exception) { } } }
internal WebSocketPingFrame(WebSocketFrameHeader head, Stream stream) : base(head, stream) { }
internal WebSocketTextFrame(WebSocketFrameHeader head, byte[] data) : base(head, data) { this.Text = ByteUtil.ReadUtf8(Data); }
internal WebSocketTextFrame(WebSocketFrameHeader head, Stream stream) : base(head, stream) { this.Text = ByteUtil.ReadUtf8(Data); }
internal WebSocketBinaryFrame(WebSocketFrameHeader head, byte[] data) : base(head) { this.Data = data; Head.XORMask(this.Data); }
internal WebSocketFrame(WebSocketFrameHeader head) { this.Head = head; }