private async Task ParseWebSocketAsync( byte[] b, HttpParserDelegate parserDelegate, HttpCombinedParser parserHandler, IEnumerable <string> subProtocols, IObserver <string> obs) { switch (_dataReceiveState) { case DataReceiveState.IsListeningForHandShake: _handshakeParser.Parse(b, parserDelegate, parserHandler); HandshakeController(parserDelegate, subProtocols); break; case DataReceiveState.IsListening: await _textDataParser.ParseAsync(_tcpStream, b[0], ExcludeZeroApplicationDataInPong); if (_textDataParser.IsCloseReceived) { StopReceivingData(); } if (_textDataParser.HasNewMessage) { obs.OnNext(_textDataParser.NewMessage); } break; } }
private async Task <IObservable <IHttpRequestReponse> > GetTcpRequestResponseObservable( int port, ICommunicationInterface communicationInterface = null, bool allowMultipleBindToSamePort = false) { var tcpListener = new TcpSocketListener(); var observeTcpRequest = await tcpListener.CreateObservableListener( port, communicationInterface, allowMultipleBindToSamePort); var observable = Observable.Create <IHttpRequestReponse>( obs => { var disp = observeTcpRequest.Subscribe( tcpSocket => { var stream = tcpSocket.ReadStream; var requestHandler = new HttpParserDelegate { HttpRequestReponse = { RemoteAddress = tcpSocket.RemoteAddress, RemotePort = tcpSocket.RemotePort, TcpSocketClient = tcpSocket, RequestType = RequestType.TCP } }; var result = _httpStreamParser.Parse(requestHandler, stream, Timeout); obs.OnNext(result); }, ex => { Cleanup(); obs.OnError(ex); }, () => { Cleanup(); obs.OnCompleted(); }); return(disp); void Cleanup() { _tcpListenerPortToObservable.Remove(port); tcpListener.Dispose(); } }); return(observable); }
private async Task <IObservable <IHttpRequestReponse> > GetUdpRequestResponseObservable( int port, ICommunicationInterface communicationInterface = null, bool allowMultipleBindToSamePort = false) { IUdpSocketReceiver udpListener = new UdpSocketReceiver(); var observeUdpRequest = await udpListener.ObservableUnicastListener( port, communicationInterface, allowMultipleBindToSamePort); var observable = Observable.Create <IHttpRequestReponse>( obs => { var disp = observeUdpRequest.Subscribe( udpSocket => { var stream = new MemoryStream(udpSocket.ByteData); var requestHandler = new HttpParserDelegate { HttpRequestReponse = { RemoteAddress = udpSocket.RemoteAddress, RemotePort = int.Parse(udpSocket.RemotePort), RequestType = RequestType.UDP } }; var result = _httpStreamParser.Parse(requestHandler, stream, Timeout); obs.OnNext(result); }, ex => { Cleanup(); obs.OnError(ex); }, () => { Cleanup(); obs.OnCompleted(); }); return(disp); void Cleanup() { _udpReceiverPortToObservable.Remove(port); udpListener.Dispose(); } }); return(observable); }
private void HandshakeController(HttpParserDelegate parserDelegate, IEnumerable <string> subProtocols) { if (parserDelegate.HttpRequestReponse.IsEndOfMessage) { if (parserDelegate.HttpRequestReponse.StatusCode == 101) { if (subProtocols != null) { SubprotocolAccepted = parserDelegate?.HttpRequestReponse?.Headers?.ContainsKey( "SEC-WEBSOCKET-PROTOCOL") ?? false; if (SubprotocolAccepted) { SubprotocolAcceptedName = parserDelegate?.HttpRequestReponse?.Headers?["SEC-WEBSOCKET-PROTOCOL"]; if (!string.IsNullOrEmpty(SubprotocolAcceptedName)) { Success(); } else { _subjectConnectionStatus.OnNext(ConnectionStatus.Aborted); throw new WebsocketClientLiteException("Server responded with blank Sub Protocol name"); } } else { _subjectConnectionStatus.OnNext(ConnectionStatus.Aborted); throw new WebsocketClientLiteException("Server did not support any of the needed Sub Protocols"); } } else { Success(); } void Success() { _subjectConnectionStatus.OnNext(ConnectionStatus.Connected); System.Diagnostics.Debug.WriteLine("HandShake completed"); DataReceiveMode = DataReceiveMode.IsListeningForTextData; IsConnected = true; _isHandshaking = false; } } else { throw new WebsocketClientLiteException($"Unable to connect to websocket Server. " + $"Error code: {parserDelegate.HttpRequestReponse.StatusCode}, " + $"Error reason: {parserDelegate.HttpRequestReponse.ResponseReason}"); } } }
internal IObservable <string> CreateWebsocketListenerObservable( Stream tcpStream, IEnumerable <string> subProtocols = null) { ParserDelegate = new HttpParserDelegate(); var parserHandler = new HttpCombinedParser(ParserDelegate); _textDataParser.Reinitialize(); _tcpStream = tcpStream; _observerDataReceiveMode.OnNext(DataReceiveState.IsListeningForHandShake); _dataReceiveState = DataReceiveState.IsListeningForHandShake; var listenerObservable = Observable.Create <string>( obs => { var disposableReceiveState = DataReceiveStateObservable.Subscribe(s => { _dataReceiveState = s; }, obs.OnError, () => { Debug.WriteLine("DataReceiveObservable completed"); }); var disposableStreamListener = Observable.While( () => _dataReceiveState == DataReceiveState.IsListeningForHandShake || _dataReceiveState == DataReceiveState.IsListening, Observable.FromAsync(() => ReadOneByteAtTheTimeAsync(tcpStream))) .Select(b => Observable.FromAsync(() => ParseWebSocketAsync(b, ParserDelegate, parserHandler, subProtocols, obs))) .Concat() .Subscribe( _ => { if (_textDataParser.IsCloseReceived) { _observerDataReceiveMode.OnNext(DataReceiveState.Exiting); _observerDataReceiveMode.OnCompleted(); } }, obs.OnError, obs.OnCompleted); return(new CompositeDisposable(disposableReceiveState, disposableStreamListener)); }); return(listenerObservable); }
private static async Task <IHttpRequestResponse> ParseAsync( HttpRequestResponse requestResponseObj, CancellationToken ct, params ErrorCorrection[] errorCorrections) { using (var requestHandler = new HttpParserDelegate(requestResponseObj)) using (var httpStreamParser = new HttpStreamParser(requestHandler, errorCorrections)) { var result = await httpStreamParser.ParseAsync(requestResponseObj.ResponseStream, ct); if (httpStreamParser.HasParsingError) { ((HttpRequestResponse)result).HasParsingErrors = httpStreamParser.HasParsingError; } return(result); } }
private async void WatchHandshakeForTimeout(HttpParserDelegate parserDelegate, CancellationTokenSource cancellationTokenSource) { var handshakeTimer = Task.Run(async() => { while (!parserDelegate.HttpRequestReponse.IsEndOfMessage && !parserDelegate.HttpRequestReponse.IsRequestTimedOut && !parserDelegate.HttpRequestReponse.IsUnableToParseHttp) { await Task.Delay(TimeSpan.FromMilliseconds(10)); } }, cancellationTokenSource.Token); var timeout = Task.Delay(TimeSpan.FromSeconds(10), cancellationTokenSource.Token); var taskRetun = await Task.WhenAny(handshakeTimer, timeout); if (taskRetun == timeout) { _hasHandshakeTimedout = true; } }
internal IObservable <string> CreateObservableListener( CancellationTokenSource innerCancellationTokenSource, ITcpSocketClient tcpSocketClient, IEnumerable <string> subProtocols = null) { var parserDelegate = new HttpParserDelegate(); var parserHandler = new HttpCombinedParser(parserDelegate); TextDataParser.Reinitialize(); _innerCancellationTokenSource = innerCancellationTokenSource; _tcpSocketClient = tcpSocketClient; DataReceiveMode = DataReceiveMode.IsListeningForHandShake; IsConnected = false; _isHandshaking = true; WatchHandshakeForTimeout(parserDelegate, _innerCancellationTokenSource); var observable = Observable.Create <string>( obs => { var disp = _tcpSocketClient.ReadStream.ReadOneByteAtTheTimeObservable(innerCancellationTokenSource, isConnectionOpen: IsConnected || _isHandshaking) .Subscribe( b => { if (TextDataParser.IsCloseRecieved) { return; } if (_hasHandshakeTimedout) { _subjectConnectionStatus.OnNext(ConnectionStatus.Aborted); throw new WebsocketClientLiteException("Connection request to server timed out"); } switch (DataReceiveMode) { case DataReceiveMode.IsListeningForHandShake: _handshakeParser.Parse(b, parserDelegate, parserHandler); HandshakeController(parserDelegate, subProtocols); break; case DataReceiveMode.IsListeningForTextData: TextDataParser.Parse(_tcpSocketClient, b[0], ExcludeZeroApplicationDataInPong); if (TextDataParser.IsCloseRecieved) { StopReceivingData(); } if (TextDataParser.HasNewMessage) { obs.OnNext(TextDataParser.NewMessage); } break; } }, ex => { StopReceivingData(); throw ex; }, () => { // ReSharper disable once ConvertClosureToMethodGroup StopReceivingData(); } ); HasReceivedCloseFromServer = false; return(disp); }); return(observable); }