private async Task <bool> OpenHandshake() { bool handshakeResult = false; try { int terminatorIndex = -1; while (!WebSocketHelpers.FindHeaderTerminator(_receiveBuffer, _receiveBufferOffset, out terminatorIndex)) { int receiveCount = await _stream.ReadAsync(_receiveBuffer, _receiveBufferOffset, _receiveBuffer.Length - _receiveBufferOffset); if (receiveCount == 0) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to receive zero bytes.", RemoteEndPoint)); } BufferDeflector.ReplaceBuffer(_bufferManager, ref _receiveBuffer, ref _receiveBufferOffset, receiveCount); if (_receiveBufferOffset > 2048) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to receive weird stream.", RemoteEndPoint)); } } string secWebSocketKey = string.Empty; string path = string.Empty; string query = string.Empty; handshakeResult = WebSocketServerHandshaker.HandleOpenningHandshakeRequest(this, _receiveBuffer, 0, terminatorIndex + Consts.HeaderTerminator.Length, out secWebSocketKey, out path, out query); _module = _routeResolver.Resolve(path, query); if (_module == null) { throw new WebSocketHandshakeException(string.Format( "Handshake with remote [{0}] failed due to cannot identify the resource name [{1}{2}].", RemoteEndPoint, path, query)); } if (handshakeResult) { var responseBuffer = WebSocketServerHandshaker.CreateOpenningHandshakeResponse(this, secWebSocketKey); await _stream.WriteAsync(responseBuffer, 0, responseBuffer.Length); } BufferDeflector.ShiftBuffer(_bufferManager, terminatorIndex + Consts.HeaderTerminator.Length, ref _receiveBuffer, ref _receiveBufferOffset); } catch (ArgumentOutOfRangeException) { handshakeResult = false; } catch (WebSocketHandshakeException ex) { _log.Error(string.Format("Session [{0}] exception occurred, [{1}].", this, ex.Message), ex); handshakeResult = false; } return(handshakeResult); }
internal async Task Start() { int origin = Interlocked.CompareExchange(ref _state, _connecting, _none); if (origin == _disposed) { throw new ObjectDisposedException("This websocket session has been disposed when connecting."); } else if (origin != _none) { throw new InvalidOperationException("This websocket session is in invalid state when connecting."); } try { ResetKeepAlive(); ConfigureClient(); var negotiator = NegotiateStream(_tcpClient.GetStream()); if (!negotiator.Wait(ConnectTimeout)) { await Close(WebSocketCloseCode.TlsHandshakeFailed, "SSL/TLS handshake timeout."); throw new TimeoutException(string.Format( "Negotiate SSL/TSL with remote [{0}] timeout [{1}].", this.RemoteEndPoint, ConnectTimeout)); } _stream = negotiator.Result; _receiveBuffer = _bufferManager.BorrowBuffer(); _receiveBufferOffset = 0; var handshaker = OpenHandshake(); if (!handshaker.Wait(ConnectTimeout)) { throw new TimeoutException(string.Format( "Handshake with remote [{0}] timeout [{1}].", this.RemoteEndPoint, ConnectTimeout)); } if (!handshaker.Result) { var responseBuffer = WebSocketServerHandshaker.CreateOpenningHandshakeBadRequestResponse(this); await _stream.WriteAsync(responseBuffer, 0, responseBuffer.Length); throw new WebSocketException(string.Format( "Handshake with remote [{0}] failed.", this.RemoteEndPoint)); } if (Interlocked.CompareExchange(ref _state, _connected, _connecting) != _connecting) { await InternalClose(false); // connected with wrong state throw new ObjectDisposedException("This websocket session has been disposed after connected."); } _log.DebugFormat("Session started for [{0}] on [{1}] in module [{2}] with session count [{3}].", this.RemoteEndPoint, this.StartTime.ToString(@"yyyy-MM-dd HH:mm:ss.fffffff"), _module.GetType().Name, this.Server.SessionCount); bool isErrorOccurredInUserSide = false; try { await _module.OnSessionStarted(this); } catch (Exception ex) { isErrorOccurredInUserSide = true; await HandleUserSideError(ex); } if (!isErrorOccurredInUserSide) { _keepAliveTracker.StartTimer(); await Process(); } else { await InternalClose(true); // user side handle tcp connection error occurred } } catch (Exception ex) when(ex is TimeoutException || ex is WebSocketException) { _log.Error(string.Format("Session [{0}] exception occurred, [{1}].", this, ex.Message), ex); await InternalClose(true); // handle tcp connection error occurred throw; } }