private DecodeResult TryDecodeHandshakeData(ConnectionToken token, out ProtocolFramework.Buffer decodedBytes, out ProtocolFramework.Buffer outputBytes) { decodedBytes = null; outputBytes = null; char endChar = (char)token.PendingData.Data[token.PendingData.Size - 1]; if (endChar != '\n') { return(DecodeResult.WantMoreData); } if (this.IsServerSide) { string header = Encoding.UTF8.GetString(token.PendingData.Data, 0, token.PendingData.Size); Regex webSocketKeyRegex = new Regex("Sec-WebSocket-Key: (.*)"); Regex webSocketVersionRegex = new Regex("Sec-WebSocket-Version: (.*)"); // check the version. Support version 13 and above const int WebSocketVersion = 13; int secWebSocketVersion = Convert.ToInt32(webSocketVersionRegex.Match(header).Groups[1].Value.Trim()); if (secWebSocketVersion < WebSocketVersion) { return(DecodeResult.Failure); } string secWebSocketKey = webSocketKeyRegex.Match(header).Groups[1].Value.Trim(); string setWebSocketAccept = this.ComputeSocketAcceptString(secWebSocketKey); string response = ("HTTP/1.1 101 Switching Protocols" + Environment.NewLine + "Connection: Upgrade" + Environment.NewLine + "Upgrade: websocket" + Environment.NewLine + "Sec-WebSocket-Accept: " + setWebSocketAccept) + "\r\n" + "\r\n"; /* + Environment.NewLine + Environment.NewLine;*/ byte[] encodedResponse = Encoding.UTF8.GetBytes(response); outputBytes = new ProtocolFramework.Buffer(encodedResponse, encodedResponse.Length); token.PendingData.Clear(); token.IsNegociationEnded = true; return(DecodeResult.Success); } else { //Make sure the server has accepted the handshake request. token.PendingData.Clear(); token.IsNegociationEnded = true; return(DecodeResult.Success); } }
public override bool ReadBytes(ProtocolFramework.Buffer incomingBytes, object connectionToken) { ConnectionToken token = (ConnectionToken)connectionToken; // TODO. Improve. if (token.PendingData.RemainingCapacity < incomingBytes.Size) { Console.WriteLine("buffered data exceeded 64 KB"); return(false); } token.PendingData.Append(incomingBytes); return(true); }
public override void StartProtocolNegociation(object connectionToken, out ProtocolFramework.Buffer outputBytes) { ConnectionToken token = (ConnectionToken)connectionToken; if (this.IsServerSide) { // We should just for client. outputBytes = null; return; } else { string handshakeRequest = "HTTP/1.1 101 Switching Protocols\r\n"; handshakeRequest += "Sec-WebSocket-Version: 13\r\n"; handshakeRequest += "Sec-WebSocket-Key: uikmSAU+xlcxDKO4grfBRA==\r\n"; handshakeRequest += "Upgrade: websocket\r\n"; handshakeRequest += "\r\n"; byte[] buffer = System.Text.Encoding.UTF8.GetBytes(handshakeRequest); outputBytes = new ProtocolFramework.Buffer(buffer, buffer.Length); } }
public override EncodeResult Encode(object connectionToken, ProtocolFramework.Buffer inputBuffer, out ProtocolFramework.Buffer output) { ConnectionToken token = (ConnectionToken)connectionToken; return(this.EncodeFrame(inputBuffer, out output, token.LastReceivedOpCode)); }
public override bool IsNegociationEnded(object connectionToken) { ConnectionToken token = (ConnectionToken)connectionToken; return(token.IsNegociationEnded); }
public override DecodeResult TryDecode(object connectionToken, out ProtocolFramework.Buffer decodedBytes, out ProtocolFramework.Buffer outputBytes) { decodedBytes = null; outputBytes = null; ConnectionToken token = (ConnectionToken)connectionToken; if (token.PendingData.Empty()) { return(DecodeResult.WantMoreData); } if (!token.IsNegociationEnded) { return(this.TryDecodeHandshakeData(token, out decodedBytes, out outputBytes)); } // We start interpreting two bytes. int headerSize = 2; if (token.PendingData.Size < headerSize) { return(DecodeResult.WantMoreData); } // First byte = Fin (1 bit) + Flags (3 bits) + opcodes (4 bits): byte byte1 = token.PendingData.Data[0]; const byte finBitFlag = 0x80; const byte opCodeFlag = 0x0F; const byte reservedBitsFlag = 0x70; bool isFinBitSet = (byte1 & finBitFlag) == finBitFlag; int reservedBits = (byte1 & reservedBitsFlag); if (reservedBits != 0) { Console.WriteLine("Reserved bits not zeros"); return(DecodeResult.Failure); } WebSocketOpCode opCode = (WebSocketOpCode)(byte1 & opCodeFlag); if (!WebsocketProtocol.IsValidCode(opCode)) { Console.WriteLine("Invalid opCode: " + opCode); return(DecodeResult.Failure); } // Second byte is Mask (1 bit) + Payload Size (7 bits) byte byte2 = token.PendingData.Data[1]; const byte maskFlag = 0x80; bool isMaskBitSet = (byte2 & maskFlag) == maskFlag; const byte payloadLenFlag = 0x7F; uint len = (uint)(byte2 & payloadLenFlag); int payloadSize = 0; if (len <= 125) { payloadSize = (int)len; } if (len == 126) { headerSize += 2; if (token.PendingData.Size < headerSize) { return(DecodeResult.WantMoreData); } byte[] lenBuffer = new byte[2]; Array.Copy(token.PendingData.Data, 2, lenBuffer, 0, 2); Array.Reverse(lenBuffer); // big endian payloadSize = (int)BitConverter.ToUInt16(lenBuffer, 0); } else if (len == 127) { headerSize += 8; if (token.PendingData.Size < headerSize) { return(DecodeResult.WantMoreData); } byte[] lenBuffer = new byte[8]; Array.Copy(token.PendingData.Data, 2, lenBuffer, 0, 8); Array.Reverse(lenBuffer); // big endian payloadSize = (int)BitConverter.ToUInt64(lenBuffer, 0); } if (WebsocketProtocol.IsControlFrame(opCode) && payloadSize > 125) { Console.WriteLine("Large control frame payload"); return(DecodeResult.Failure); } int totalSize = headerSize + (isMaskBitSet ? 4 : 0) + (int)payloadSize; if (token.PendingData.Size < totalSize) { return(DecodeResult.WantMoreData); } ProtocolFramework.Buffer payloadBuffer = new ProtocolFramework.Buffer(payloadSize); int payloadOffset = headerSize + (isMaskBitSet ? 4 : 0); payloadBuffer.Append(token.PendingData.Data, payloadOffset, (int)payloadSize); if (isMaskBitSet) { const int maskKeyLen = 4; byte[] maskKey = new byte[4]; Array.Copy(token.PendingData.Data, headerSize, maskKey, 0, 4); // apply the mask key for (int i = 0; i < payloadBuffer.Size; i++) { payloadBuffer.Data[i] = (Byte)(payloadBuffer.Data[i] ^ maskKey[i % maskKeyLen]); } } token.PendingData.PopAndAdjust(payloadOffset + (int)payloadSize); if (opCode == WebSocketOpCode.ConnectionClose) { this.EncodeFrame(null, out outputBytes, WebSocketOpCode.ConnectionClose); return(DecodeResult.Failure); // TODO. } else if (opCode == WebSocketOpCode.Pong) { return(DecodeResult.Success); } else if (opCode == WebSocketOpCode.Ping) { this.EncodeFrame(payloadBuffer, out outputBytes, WebSocketOpCode.Pong); return(DecodeResult.Success); } else { token.LastReceivedOpCode = opCode; decodedBytes = payloadBuffer; return(DecodeResult.Success); } }