public async Task ConnectAsync(string url) { Uri uri = new Uri(url); string query = uri.PathAndQuery; bool ssl = uri.Scheme.ToLower().StartsWith("wss"); int port = uri.Port > 0 ? uri.Port : (ssl ? 443 : 80); await client.ConnectAsync(uri.Host, port); ConnectionStream stream = new ConnectionStream(ref client, ssl); if (ssl) { await stream.Authenticate(ConnectionStream.AuthMode.Client, uri.Host); } if (!(await Handshake(stream, uri, port))) { state = WebsockState.Closed; throw new Exception("Failed connection at handshake"); } protocol = new WebsockProtocol(ref stream); state = WebsockState.Open; try { while (true) { await OnMessage(await protocol.GetMessage()); } } catch (WebsockCloseException ex) { await OnClose(ex.Code, ex.Reason); } finally { protocol.Dispose(); } }
// Deny client with http error message private async Task <bool> RejectClient(ConnectionStream stream, string errorMessage) { byte[] errorData = Encoding.UTF8.GetBytes(HttpErrorTemplate .Replace("{Content}", errorMessage) .Replace("{ContentType}", "text/plain") .Replace("{ContentLength}", errorMessage.Length.ToString())); await stream.WriteAsync(errorData, errorData.Length); stream.Dispose(); return(false); }
// handle incoming clients private async Task HandleClient(ConnectionStream stream) { if (!(await HandshakeClient(stream))) { return; } WebsockServerClient serverClient = new WebsockServerClient(this, ref stream); clients.Add(serverClient); await serverClient.StartAsync(); }
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 WebsockProtocol(ref ConnectionStream stream) { this.stream = stream; dataBuilder = new MemoryStream(); callbacks = new Queue <Func <byte[], Task> >(); }
public WebsockServerClient(WebsockServer server, ref ConnectionStream stream) { this.server = server; this.protocol = new WebsockProtocol(ref stream); }