示例#1
0
        /// <summary>
        /// Establishes a new send-side HybridConnection and returns the Stream.
        /// </summary>
        public async Task <HybridConnectionStream> CreateConnectionAsync()
        {
            TrackingContext trackingContext = CreateTrackingContext(this.Address);
            string          traceSource     = nameof(HybridConnectionClient) + "(" + trackingContext.ToString() + ")";
            var             timeoutHelper   = new TimeoutHelper(this.OperationTimeout);

            RelayEventSource.Log.RelayClientConnectStart(traceSource);
            try
            {
                var webSocket = new ClientWebSocket();
                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);
                    string audience = this.Address.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped);
                    var    token    = await this.TokenProvider.GetTokenAsync(audience, 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);
                }

#if NET45 // TODO: Flow Response Headers in NETSTANDARD ClientWebSocket
                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     = nameof(HybridConnectionClient) + "(" + trackingContext.ToString() + ")";
                }
#endif

                return(new WebSocketStream(webSocket, trackingContext));
            }
            catch (WebSocketException wsException)
            {
                throw RelayEventSource.Log.ThrowingException(WebSocketExceptionHelper.ConvertToRelayContract(wsException), traceSource);
            }
            finally
            {
                RelayEventSource.Log.RelayClientConnectStop();
            }
        }
示例#2
0
            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 ClientWebSocket();
                    webSocket.Options.SetBuffer(this.bufferSize, this.bufferSize);
                    webSocket.Options.Proxy             = this.listener.Proxy;
                    webSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval;
                    webSocket.Options.SetRequestHeader("User-Agent", "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);

#if NET45 // TODO: Flow Response Headers in NETSTANDARD ClientWebSocket
                    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);
                    }
#endif

                    this.OnOnline();
                    return(webSocket);
                }
                catch (WebSocketException wsException)
                {
                    throw RelayEventSource.Log.ThrowingException(WebSocketExceptionHelper.ConvertToRelayContract(wsException), this.listener);
                }
                finally
                {
                    RelayEventSource.Log.RelayClientConnectStop();
                }
            }
 async Task EnsureRendezvousAsync(CancellationToken cancelToken)
 {
     if (this.rendezvousWebSocket == null)
     {
         RelayEventSource.Log.HybridHttpCreatingRendezvousConnection(this.TrackingContext);
         this.rendezvousWebSocket = new ClientWebSocket();
         await this.rendezvousWebSocket.ConnectAsync(this.rendezvousAddress, cancelToken).ConfigureAwait(false);
     }
 }
示例#4
0
        ClientWebSocket CreateWebSocket()
        {
            var clientWebSocket = new ClientWebSocket();

            clientWebSocket.Options.SetBuffer(this.Listener.ConnectionBufferSize, this.Listener.ConnectionBufferSize);
            clientWebSocket.Options.SetRequestHeader("Host", this.Listener.Address.Host);
            clientWebSocket.Options.Proxy             = this.Listener.Proxy;
            clientWebSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval;
            return(clientWebSocket);
        }
示例#5
0
        ClientWebSocket CreateWebSocket()
        {
            var clientWebSocket = new ClientWebSocket();

            clientWebSocket.Options.SetBuffer(this.Listener.ConnectionBufferSize, this.Listener.ConnectionBufferSize);
            clientWebSocket.Options.Proxy             = this.Listener.Proxy;
            clientWebSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval;
#if CUSTOM_CLIENTWEBSOCKET
            // The .NET Framework ClientWebSocket throws when setting the Host header, but it works in .NET Core
            clientWebSocket.Options.SetRequestHeader("Host", this.Listener.Address.Host);
#endif
            return(clientWebSocket);
        }
示例#6
0
        internal async Task RejectAsync()
        {
            ClientWebSocket clientWebSocket = null;

            try
            {
                if (this.Response.StatusCode == HttpStatusCode.Continue)
                {
                    this.Response.StatusCode        = HttpStatusCode.BadRequest;
                    this.Response.StatusDescription = "Rejected by user code";
                }

                // Add the status code/description to the URI query string
                int requiredCapacity = this.wssRendezvousAddress.OriginalString.Length + 50 + this.Response.StatusDescription.Length;
                var stringBuilder    = new StringBuilder(this.wssRendezvousAddress.OriginalString, requiredCapacity);
                stringBuilder.AppendFormat("&{0}={1}", HybridConnectionConstants.StatusCode, (int)this.Response.StatusCode);
                stringBuilder.AppendFormat("&{0}={1}", HybridConnectionConstants.StatusDescription, WebUtility.UrlEncode(this.Response.StatusDescription));
                Uri rejectUri = new Uri(stringBuilder.ToString());

                clientWebSocket = this.CreateWebSocket();
                using (var cancelSource = new CancellationTokenSource(AcceptTimeout))
                {
                    await clientWebSocket.ConnectAsync(rejectUri, cancelSource.Token).ConfigureAwait(false);
                }
            }
            catch (Exception e) when(!Fx.IsFatal(e))
            {
                WebException    webException;
                HttpWebResponse httpWebResponse;

                if (e is WebSocketException &&
                    (webException = e.InnerException as WebException) != null &&
                    (httpWebResponse = webException.Response as HttpWebResponse) != null &&
                    httpWebResponse.StatusCode == HttpStatusCode.Gone)
                {
                    // status code of "Gone" is expected when rejecting a client request
                    return;
                }

                RelayEventSource.Log.HandledExceptionAsWarning(this, e);
            }
            finally
            {
                clientWebSocket?.Abort();
            }
        }
示例#7
0
            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.ObjectConnecting(this.listener);
                    var webSocket = new ClientWebSocket();
                    webSocket.Options.SetBuffer(this.bufferSize, this.bufferSize);
                    webSocket.Options.Proxy             = this.listener.Proxy;
                    webSocket.Options.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval;
                    webSocket.Options.SetRequestHeader(HybridConnectionConstants.Headers.RelayUserAgent, HybridConnectionConstants.ClientAgent);

                    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);

                    this.OnOnline();
                    RelayEventSource.Log.ObjectConnected(this.listener);
                    return(webSocket);
                }
                catch (WebSocketException wsException)
                {
                    throw RelayEventSource.Log.ThrowingException(WebSocketExceptionHelper.ConvertToRelayContract(wsException), this.listener);
                }
            }