/// <summary> /// Handles the connection and reads received HMQ messages /// </summary> public async Task HandleConnection(IConnectionInfo info, ProtocolHandshakeResult handshakeResult) { //if user makes a mistake in ready method, we should not interrupt connection handling try { await _handler.Ready(_server, (HorseServerSocket)handshakeResult.Socket); } catch (Exception e) { if (_server.Logger != null) { _server.Logger.LogException("Unhandled Exception", e); } } HmqReader reader = new HmqReader(); while (info.Client != null && info.Client.Connected) { HorseMessage message = await reader.Read(info.GetStream()); if (message == null) { info.Close(); return; } await ProcessMessage(info, message, (HorseServerSocket)handshakeResult.Socket); } }
/// <summary> /// Checks if received data is a TMQ protocol message /// </summary> public async Task <ProtocolHandshakeResult> Handshake(IConnectionInfo info, byte[] data) { ProtocolHandshakeResult result = new ProtocolHandshakeResult(); if (data.Length < 8) { return(await Task.FromResult(result)); } result.Accepted = CheckProtocol(data); if (!result.Accepted) { return(result); } TmqReader reader = new TmqReader(); TmqMessage message = await reader.Read(info.GetStream()); //sends protocol message await info.GetStream().WriteAsync(PredefinedMessages.PROTOCOL_BYTES); bool alive = await ProcessFirstMessage(message, info, result); if (!alive) { return(result); } result.PipeConnection = true; info.State = ConnectionStates.Pipe; info.Protocol = this; return(result); }
/// <summary> /// After protocol handshake is completed, this method is called to handle events for the specified client /// </summary> public async Task HandleConnection(IConnectionInfo info, ProtocolHandshakeResult handshakeResult) { //if user makes a mistake in ready method, we should not interrupt connection handling try { await _handler.Ready(_server, (WsServerSocket)handshakeResult.Socket); } catch (Exception e) { if (_server.Logger != null) { _server.Logger.LogException("Unhandled Exception", e); } } WebSocketReader reader = new WebSocketReader(); Stream stream = info.GetStream(); while (info.Socket != null && info.Socket.IsConnected) { WebSocketMessage message = await reader.Read(stream); if (message == null) { info.Close(); return; } handshakeResult.Socket.KeepAlive(); await ProcessMessage(info, handshakeResult.Socket, message); } }
/// <summary> /// Checks if data is belong this protocol. /// </summary> /// <param name="info">Connection information</param> /// <param name="data">Data is first 8 bytes of the first received message from the client</param> /// <returns></returns> public async Task <ProtocolHandshakeResult> Handshake(IConnectionInfo info, byte[] data) { ProtocolHandshakeResult result = new ProtocolHandshakeResult(); result.Accepted = CheckProtocol(data); if (result.Accepted) { result.ReadAfter = true; } info.State = ConnectionStates.Http; return(await Task.FromResult(result)); }
/// <summary> /// After protocol handshake is completed, this method is called to handle events for the specified client /// </summary> public async Task HandleConnection(IConnectionInfo info, ProtocolHandshakeResult handshakeResult) { //if user makes a mistake in ready method, we should not interrupt connection handling try { await _handler.Ready(_server, handshakeResult.Socket); } catch (Exception e) { if (_server.Logger != null) { _server.Logger.LogException("Unhandled Exception", e); } } HttpReader reader = new HttpReader(Options); HttpWriter writer = new HttpWriter(Options); reader.HandshakeResult = handshakeResult; HandleStatus status; do { HttpMessage message = await reader.Read(info.GetStream()); if (message.Request != null) { message.Request.IpAddress = FindIPAddress(info.Client); } status = await ProcessMessage(info, writer, message, reader.ContentLength); if (status == HandleStatus.ReadAgain) { reader.Reset(); } } while (status == HandleStatus.ReadAgain); if (status == HandleStatus.Close) { info.Close(); } }
/// <summary> /// When protocol is switched to this protocol from another protocol /// </summary> public async Task <ProtocolHandshakeResult> SwitchTo(IConnectionInfo info, ConnectionData data) { if (!info.Protocol.Name.Equals("http", StringComparison.InvariantCultureIgnoreCase)) { return(await Task.FromResult(new ProtocolHandshakeResult())); } string key; bool hasKey = data.Properties.TryGetValue(PredefinedMessages.WEBSOCKET_KEY, out key); if (!hasKey) { return(await Task.FromResult(new ProtocolHandshakeResult())); } ProtocolHandshakeResult result = new ProtocolHandshakeResult(); result.PipeConnection = true; result.Accepted = true; result.ReadAfter = false; result.PreviouslyRead = null; result.Response = await CreateWebSocketHandshakeResponse(key); WsServerSocket socket = await _handler.Connected(_server, info, data); if (socket == null) { return(await Task.FromResult(new ProtocolHandshakeResult())); } info.State = ConnectionStates.Pipe; result.Socket = socket; _server.Pinger.Add(socket); socket.SetCleanupAction(s => { _server.Pinger.Remove(socket); _handler.Disconnected(_server, s); }); return(result); }
/// <summary> /// Switches client's protocol to new protocol (finds by name) /// </summary> public async Task SwitchProtocol(IConnectionInfo info, string newProtocolName, ConnectionData data) { foreach (ITwinoProtocol protocol in Protocols) { if (protocol.Name.Equals(newProtocolName, StringComparison.InvariantCultureIgnoreCase)) { ProtocolHandshakeResult hsresult = await protocol.SwitchTo(info, data); if (!hsresult.Accepted) { info.Close(); return; } ITwinoProtocol previous = info.Protocol; info.Protocol = protocol; info.Socket = hsresult.Socket; if (info.Socket != null) { info.Socket.SetOnConnected(); } if (hsresult.Response != null) { await info.GetStream().WriteAsync(hsresult.Response); } if (info.Socket != null) { info.Socket.SetOnProtocolSwitched(previous, info.Protocol); } await protocol.HandleConnection(info, hsresult); return; } } }
/// <summary> /// Reads first Hello message from client /// </summary> private async Task <bool> ProcessFirstMessage(HorseMessage message, IConnectionInfo info, ProtocolHandshakeResult handshakeResult) { if (message.Type != MessageType.Server || message.ContentType != KnownContentTypes.Hello) { return(false); } ConnectionData connectionData = new ConnectionData(); message.Content.Position = 0; await connectionData.ReadFromStream(message.Content); HorseServerSocket socket = await _handler.Connected(_server, info, connectionData); if (socket == null) { info.Close(); return(false); } info.State = ConnectionStates.Pipe; handshakeResult.Socket = socket; _server.HeartbeatManager.Add(socket); socket.SetCleanupAction(s => { _server.HeartbeatManager.Remove(socket); _handler.Disconnected(_server, s); }); return(true); }
/// <summary> /// After the client connection request is accepted. /// Completes first operations for the client /// such as firewall authority, SSL authentication, WebSocket handshaking /// </summary> private async Task AcceptClient(TcpClient tcp) { ConnectionInfo info = null; try { if (_listener == null) { return; } info = new ConnectionInfo(tcp, _listener) { State = ConnectionStates.Pending, MaxAlive = DateTime.UtcNow + TimeSpan.FromSeconds(_server.Options.RequestTimeout) }; _listener.KeepAliveManager.Add(info); //ssl handshaking if (_listener.Options.SslEnabled) { SslStream sslStream = _listener.Options.BypassSslValidation ? new SslStream(tcp.GetStream(), true, (a, b, c, d) => true) : new SslStream(tcp.GetStream(), true); info.SslStream = sslStream; SslProtocols protocol = GetProtocol(_listener); info.IsSsl = true; await sslStream.AuthenticateAsServerAsync(_listener.Certificate, false, protocol, false); } //read one byte and recognize the protocol byte[] pbytes = new byte[8]; int rc = await info.GetStream().ReadAsync(pbytes, 0, pbytes.Length); if (rc == 0) { info.Close(); return; } //find matched protocol with client protocol foreach (IHorseProtocol protocol in _server.Protocols) { ProtocolHandshakeResult hsresult = await protocol.Handshake(info, pbytes); //matched if (hsresult.Accepted) { hsresult.PreviouslyRead = pbytes; info.Protocol = protocol; info.Socket = hsresult.Socket; if (info.Socket != null) { info.Socket.SetOnConnected(); } //if protocol required to send protocol message from server to client, send it if (hsresult.Response != null) { await info.GetStream().WriteAsync(hsresult.Response); } //handle connection events for the connection await protocol.HandleConnection(info, hsresult); return; } } info.Close(); } catch (Exception ex) { info?.Close(); _server.RaiseException(ex); } }