/// <summary> /// Get a whole basic close frame, completely built. /// </summary> /// <returns>The close frame.</returns> public static WebSocketFrame GetCloseFrame() { WebSocketHeader header = new WebSocketHeader(); header.Fin = true; header.Masked = false; header.Opcode = HeaderOpcode.CloseConnectionFrame; header.PayloadSize = 0; return new WebSocketFrame(header, new byte[0]); }
/// <summary> /// Generate a websocket frame for the given text payload /// </summary> /// <returns>The text frame.</returns> /// <param name="payload">Payload.</param> public static WebSocketFrame GetTextFrame(byte[] payload) { WebSocketHeader header = new WebSocketHeader(); header.Fin = true; header.Masked = false; header.Opcode = HeaderOpcode.TextFrame; header.PayloadSize = payload.Length; return new WebSocketFrame(header, payload); }
/// <summary> /// Initializes a new instance of the <see cref="MyWebSocket.WebSocketFrame"/> class. /// </summary> /// <param name="header">A preparsed header object</param> /// <param name="frameOrPayload">Full frame data or just the payload (leave masked)</param> public WebSocketFrame(WebSocketHeader header, byte[] frameOrPayload) { Header = header; //Set the payload data bytes based on the length of the given byte array. if (frameOrPayload.Length == header.PayloadSize) PayloadData = frameOrPayload; else if (frameOrPayload.Length == header.FrameSize) PayloadData = frameOrPayload.Skip(header.HeaderSize).Take(header.PayloadSize).ToArray(); else PayloadData = new byte[1]; //Now let's just unmask the data and finally get the hell outta dodge. if (Header.Masked) ToggleMask(); }
/// <summary> /// Initialize an empty (invalid) frame. /// </summary> public WebSocketFrame() { Header = new WebSocketHeader(); PayloadData = new byte[1]; }
/// <summary> /// Attempt to parse a series of ordered bytes into a WebSocketHeader. Bytes should be taken directly /// from whatever network stream you're using. /// </summary> /// <returns><c>true</c>, if parsed correctly, <c>false</c> otherwise.</returns> /// <param name="bytes">Header bytes</param> /// <param name="result">Parsed header information</param> public static bool TryParse(byte[] bytes, out WebSocketHeader result) { result = new WebSocketHeader(); int headerSize = FullHeaderSize(bytes); if (headerSize > bytes.Length) return false; //First byte encoding result.Fin = (bytes[0] & 128) > 0; result.RSV = (bytes[0] & 112) >> 4; result.OpcodeRaw = (bytes[0] & 15); //Second byte encoding result.Masked = (bytes[1] & 128) > 0; result.PayloadSize = (bytes[1] & 127); int maskByte = 2; //Get all the bytes of the payload if (result.PayloadSize == 126) { result.PayloadSize = bytes.Skip(2).Take(2).ParseInt(); maskByte += 2; } else if (result.PayloadSize == 127) { result.PayloadSize = bytes.Skip(2).Take(8).ParseInt(); maskByte += 8; } //Get all the bytes of the mask if (result.Masked) result.Mask = bytes.Skip(maskByte).Take(4).ToArray(); return true; }
/// <summary> /// Attempts to read an entire frame. Returns the frame if one was successfully read. /// </summary> /// <returns>The status of the read operation</returns> /// <param name="frame">The parsed frame (on success)</param> public DataStatus TryReadFrame(out WebSocketFrame frame) { frame = new WebSocketFrame(); //Pull a chunk of data (as much as we can) from the stream and store it in our internal buffer. DataStatus readStatus = GenericRead(); //If there was an error (anything other than "completion" or waiting), return the error. if (readStatus != DataStatus.Complete) return readStatus; //We MAY have read more than one frame at a time! Wowie... // while (messageBufferSize > 0) // { //We need at least 2 bytes to complete the header. if (messageBufferSize < 2) return DataStatus.WaitingOnData; byte[] message = messageBuffer.Take(messageBufferSize).ToArray(); //If the complete header hasn't been read yet, we're still waiting for it. if (messageBufferSize < WebSocketHeader.FullHeaderSize(message)) return DataStatus.WaitingOnData; WebSocketHeader header = new WebSocketHeader(); //If we can't parse the header at this point, we have some serious issues. if (!WebSocketHeader.TryParse(message, out header)) return DataStatus.InternalError; //Too much data if (header.FrameSize > MaxReceiveSize) { return DataStatus.OversizeError; } //We have the whole header, but do we have the whole message? if not, we're still waiting on data. if (messageBufferSize < header.FrameSize) return DataStatus.WaitingOnData; //Oh, we have the whole message. Uhh ok then, let's make sure the header fields are correct //before continuing. RSV needs to be 0 (may change later) and all client messages must be masked. if (!header.Masked || header.RSV != 0) return DataStatus.DataFormatError; //Oh is this... a binary frame? Dawg... don't gimme that crap. if (header.Opcode == HeaderOpcode.BinaryFrame) return DataStatus.UnsupportedError; //Initialize a frame with our newly parsed data frame = new WebSocketFrame(header, messageBuffer.Take(header.FrameSize).ToArray()); //Remove the message data from the buffer MessageBufferPop(header.FrameSize); // messageBuffer.TruncateBeginning(header.FrameSize, messageBufferSize); // messageBufferSize -= header.FrameSize; //} return DataStatus.Complete; }