/// <summary> /// Establishes a new send-side HybridConnection and returns the Stream. /// </summary> public async Task <HybridConnectionStream> CreateConnectionAsync() { TrackingContext trackingContext = CreateTrackingContext(this.Address); string traceSource = this.GetType().Name + "(" + trackingContext + ")"; var timeoutHelper = new TimeoutHelper(this.OperationTimeout); RelayEventSource.Log.RelayClientConnectStart(traceSource); try { var webSocket = new ClientWebSocket45(); webSocket.Options.Proxy = this.Proxy; webSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval; webSocket.Options.SetBuffer(this.ConnectionBufferSize, this.ConnectionBufferSize); if (this.TokenProvider != null) { RelayEventSource.Log.GetTokenStart(traceSource); var token = await this.TokenProvider.GetTokenAsync( this.Address.GetLeftPart(UriPartial.Path), TokenProvider.DefaultTokenTimeout).ConfigureAwait(false); RelayEventSource.Log.GetTokenStop(token.ExpiresAtUtc); webSocket.Options.SetRequestHeader(RelayConstants.ServiceBusAuthorizationHeaderName, token.TokenString); } // Build the websocket uri, e.g. "wss://contoso.servicebus.windows.net:443/$hc/endpoint1?sb-hc-action=connect&sb-hc-id=E2E_TRACKING_ID" Uri webSocketUri = HybridConnectionUtility.BuildUri( this.Address.Host, this.Address.Port, this.Address.AbsolutePath, this.Address.Query, HybridConnectionConstants.Actions.Connect, trackingContext.TrackingId); using (var cancelSource = new CancellationTokenSource(timeoutHelper.RemainingTime())) { await webSocket.ConnectAsync(webSocketUri, cancelSource.Token).ConfigureAwait(false); } var trackingId = webSocket.ResponseHeaders[TrackingContext.TrackingIdName]; if (!string.IsNullOrEmpty(trackingId)) { // Update to the flown trackingId (which has _GX suffix) trackingContext = TrackingContext.Create(trackingId, trackingContext.SubsystemId); traceSource = this.GetType().Name + "(" + trackingContext + ")"; } return(new WebSocketStream(webSocket, trackingContext)); } catch (WebSocketException wsException) { throw RelayEventSource.Log.ThrowingException(WebSocketExceptionHelper.ConvertToRelayContract(wsException), traceSource); } finally { RelayEventSource.Log.RelayClientConnectStop(traceSource); } }
async Task <WebSocket> ConnectAsync(CancellationToken cancellationToken) { Fx.Assert(!this.closeCalled, "Shouldn't call ConnectWebSocketAsync if CloseAsync was called."); try { var connectDelay = ConnectDelayIntervals[this.connectDelayIndex]; if (connectDelay != TimeSpan.Zero) { await Task.Delay(connectDelay, cancellationToken).ConfigureAwait(false); } RelayEventSource.Log.RelayClientConnectStart(this.listener); var webSocket = new ClientWebSocket45(); webSocket.Options.SetBuffer(this.bufferSize, this.bufferSize); webSocket.Options.Proxy = this.listener.Proxy; webSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval; webSocket.Options.UserAgent = "ServiceBus/" + ClientAgentFileVersion; var token = await this.tokenRenewer.GetTokenAsync().ConfigureAwait(false); webSocket.Options.SetRequestHeader(RelayConstants.ServiceBusAuthorizationHeaderName, token.TokenString); // When we reconnect we need to remove the "_GXX" suffix otherwise trackingId gets longer after each reconnect string trackingId = TrackingContext.RemoveSuffix(this.listener.TrackingContext.TrackingId); // Build the websocket uri, e.g. "wss://contoso.servicebus.windows.net:443/$hc/endpoint1?sb-hc-action=listen&sb-hc-id=E2E_TRACKING_ID" var webSocketUri = HybridConnectionUtility.BuildUri( this.address.Host, this.address.Port, this.address.AbsolutePath, this.address.Query, HybridConnectionConstants.Actions.Listen, trackingId); await webSocket.ConnectAsync(webSocketUri, cancellationToken).ConfigureAwait(false); trackingId = webSocket.ResponseHeaders[TrackingContext.TrackingIdName]; if (!string.IsNullOrEmpty(trackingId)) { // Update to the flown trackingId (which has _GX suffix) this.listener.TrackingContext = TrackingContext.Create(trackingId, this.listener.TrackingContext.SubsystemId); } this.OnOnline(); return(webSocket); } catch (WebSocketException wsException) { throw RelayEventSource.Log.ThrowingException(WebSocketExceptionHelper.ConvertToRelayContract(wsException), this.listener); } finally { RelayEventSource.Log.RelayClientConnectStop(this.listener); } }
public async Task AcceptConnectionAsync() { try { // Performance: Address Resolution (ARP) work-around: When we receive the control message from a TCP connection which hasn't had any // outbound traffic for 2 minutes the ARP cache no longer has the MAC address required to ACK the control message. If we also begin // connecting a new socket at exactly the same time there's a known race condition (insert link here) where ARP can only resolve one // address at a time, which causes the loser of the race to have to retry after 3000ms. To avoid the 3000ms delay we just pause for // a few ms here instead. await Task.Delay(TimeSpan.FromMilliseconds(2)).ConfigureAwait(false); var timeoutHelper = new TimeoutHelper(AcceptTimeout); var clientWebSocket = new ClientWebSocket45(); clientWebSocket.Options.SetBuffer(this.bufferSize, this.bufferSize); clientWebSocket.Options.Host = this.Address.Host; clientWebSocket.Options.Proxy = this.listener.Proxy; clientWebSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval; using (var cancelSource = new CancellationTokenSource(timeoutHelper.RemainingTime())) { await clientWebSocket.ConnectAsync(this.rendezvousAddress, cancelSource.Token).ConfigureAwait(false); } var webSocketStream = new WebSocketStream(clientWebSocket, this.TrackingContext); this.AcceptSucceeded(webSocketStream); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } this.AcceptFailed(exception); } }