private async Task <bool> Handshake(ConnectionStream stream, Uri uri, int port) { state = WebsockState.Connecting; string handshakeData = HttpHandshakeData .Replace("{Path}", uri.PathAndQuery) .Replace("{Host}", uri.Host) .Replace("{Scheme}", uri.Scheme) .Replace("{Port}", port.ToString()) .Replace("{Key}", GenerateKey()); await stream.WriteAsync(handshakeData); string response = Encoding.UTF8.GetString(await stream.ReadAsync()); return(response.Split('\n')[0].Split(' ')[1] == "101"); }
// Perform websocket handshake with client private async Task <bool> HandshakeClient(ConnectionStream stream) { // read and parse http request data byte[] httpData = await stream.ReadAsync(); HttpPacket packet = new HttpPacket(httpData); // client requests checks if (!packet.Method.ToLower().StartsWith("get")) { return(await RejectClient(stream, "Only allows GET Requests")); } if (!packet.Headers.ContainsKey("Sec-WebSocket-Key")) { return(await RejectClient(stream, "No WebSocket-Key found")); } if (!packet.Headers.ContainsKey("Upgrade")) { return(await RejectClient(stream, "Upgrade header not set")); } else if (!packet.Headers["Upgrade"].ToLower().StartsWith("websocket")) { return(await RejectClient(stream, "Upgrade header not websocket")); } if (!packet.Headers.ContainsKey("Connection")) { return(await RejectClient(stream, "Connection header not set")); } else if (!packet.Headers["Connection"].ToLower().StartsWith("upgrade")) { return(await RejectClient(stream, "Connection header not upgrade")); } // generate websocket key, send response to client and complete handshake httpData = Encoding.UTF8.GetBytes(HttpHandshakeSucces.Replace( "{WebsockKey}", GenerateKey(packet.Headers["Sec-WebSocket-Key"]))); await stream.WriteAsync(httpData, httpData.Length); return(true); }
public async Task <byte[]> GetMessage() { int size = 0; byte[] buffer = new byte[2]; WebsockFrame frame = new WebsockFrame(); // read first byte of data buffer = await stream.ReadAsync(buffer.Length); frame.Fin = (buffer[0] & 0x80) != 0; // first bit frame.Rsv1 = (buffer[0] & 0x40) != 0; // second bit frame.Rsv2 = (buffer[0] & 0x20) != 0; // thrid bit frame.Rsv3 = (buffer[0] & 0x10) != 0; // fourth bit frame.Opcode = (WebsockOpCode)(buffer[0] & 0x0f); // fifth to eigth bits // read second byte of data frame.Masked = (buffer[1] & 0x80) != 0; // set second byte first bit size = (int)(buffer[1] & (~0x80)); // get deciding size // payload size is 64 bits long if (size == 127) { size = 0; buffer = new byte[8]; buffer = await stream.ReadAsync(buffer.Length); size |= (buffer[0] & 0xff) << 56; size |= (buffer[1] & 0xff) << 48; size |= (buffer[2] & 0xff) << 40; size |= (buffer[3] & 0xff) << 32; size |= (buffer[4] & 0xff) << 24; size |= (buffer[5] & 0xff) << 16; size |= (buffer[6] & 0xff) << 8; size |= (buffer[7] & 0xff) << 0; // payload size is 16 bits long } else if (size == 126) { size = 0; buffer = new byte[2]; buffer = await stream.ReadAsync(buffer.Length); size |= (buffer[0] & 0xff) << 8; size |= (buffer[1] & 0xff) << 0; } // read mask data if (frame.Masked) { frame.MaskingKey = new byte[4]; frame.MaskingKey = await stream.ReadAsync(frame.MaskingKey.Length); } // read payload data frame.Data = new byte[size]; frame.Data = await stream.ReadAsync(size); if (frame.Masked) { for (int i = 0; i < size; i++) { frame.Data[i] ^= frame.MaskingKey[i % 4]; } } // combine with continued data if (dataBuilder.Length > 0) { byte[] continued = dataBuilder.ToArray(); dataBuilder.SetLength(0); byte[] combined = new byte[continued.Length + frame.Data.Length]; Buffer.BlockCopy(continued, 0, combined, 0, continued.Length); Buffer.BlockCopy(frame.Data, 0, continued, continued.Length, frame.Data.Length); frame.Data = combined; } // build up fragmented frame & try again if (frame.Opcode == WebsockOpCode.Continue) { dataBuilder.Write(frame.Data, 0, frame.Data.Length); return(await GetMessage()); // echo back close data and close connection } else if (frame.Opcode == WebsockOpCode.Close) { await SendAsync(frame.Data, WebsockOpCode.Close); throw new WebsockCloseException(frame.Data); // perform ping callback that was queued up & try again } else if (frame.Opcode == WebsockOpCode.Pong) { await callbacks.Dequeue()(frame.Data); return(await GetMessage()); // frame is either Text or Binary, return data } else { return(frame.Data); } }