Task OnAcceptClientCommandAsync(ListenerCommand.AcceptCommand acceptCommand) { string id = acceptCommand.Id; var trackingContext = TrackingContext.Create(id, this.Address); #if DEBUG // TestHook: In DEBUG builds if the trackingId is Guid.Empty don't accept the rendezvous if (trackingContext.TrackingId.StartsWith(Guid.Empty.ToString(), StringComparison.Ordinal)) { return(TaskEx.CompletedTask); } #endif RelayEventSource.Log.RelayListenerRendezvousStart(this.ToString(), trackingContext.TrackingId, acceptCommand.Address); DataConnection clientConnection; lock (this.ThisLock) { if (this.closeCalled) { RelayEventSource.Log.RelayListenerRendezvousFailed(this.ToString(), trackingContext.TrackingId, SR.ObjectClosedOrAborted); return(TaskEx.CompletedTask); } else if (this.clientConnections.ContainsKey(id)) { RelayEventSource.Log.RelayListenerRendezvousFailed(this.ToString(), trackingContext.TrackingId, SR.DuplicateConnectionId); return(TaskEx.CompletedTask); } clientConnection = new DataConnection(this, acceptCommand, trackingContext); this.clientConnections.Add(id, clientConnection); } return(clientConnection.AcceptConnectionAsync()); }
TrackingContext GetTrackingContext() { var queryParameters = HybridConnectionUtility.ParseQueryString(this.rendezvousAddress.Query); string trackingId = queryParameters[HybridConnectionConstants.Id]; return(TrackingContext.Create(trackingId, this.rendezvousAddress)); }
/// <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(); } }
internal RelayedHttpListenerContext(HybridConnectionListener listener, Uri requestUri, string trackingId, string method, IDictionary <string, string> requestHeaders) { this.Listener = listener; this.TrackingContext = TrackingContext.Create(trackingId, requestUri); this.Request = new RelayedHttpListenerRequest(requestUri, method, requestHeaders); this.Response = new RelayedHttpListenerResponse(this); this.FlowSubProtocol(); }
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(); } }
internal RelayedHttpListenerContext(HybridConnectionListener listener, ListenerCommand.AcceptCommand acceptCommand) { this.Listener = listener; this.wssRendezvousAddress = new Uri(acceptCommand.Address); Uri requestUri = this.GenerateRequestUri(); this.TrackingContext = TrackingContext.Create(acceptCommand.Id, requestUri); this.Request = new RelayedHttpListenerRequest(requestUri, acceptCommand); this.Response = new RelayedHttpListenerResponse(this); this.FlowSubProtocol(); }
// This private .ctor handles both of the public overloads which take connectionString HybridConnectionListener(string connectionString, string path, bool pathFromConnectionString) { if (string.IsNullOrWhiteSpace(connectionString)) { throw RelayEventSource.Log.ArgumentNull(nameof(connectionString), this); } var builder = new RelayConnectionStringBuilder(connectionString); builder.Validate(); if (pathFromConnectionString) { if (string.IsNullOrWhiteSpace(builder.EntityPath)) { // connectionString did not have required EntityPath throw RelayEventSource.Log.Argument(nameof(connectionString), SR.GetString(SR.ConnectionStringMustIncludeEntityPath, nameof(HybridConnectionClient)), this); } } else { if (string.IsNullOrWhiteSpace(path)) { // path parameter is required throw RelayEventSource.Log.ArgumentNull(nameof(path), this); } else if (!string.IsNullOrWhiteSpace(builder.EntityPath)) { // EntityPath must not appear in connectionString throw RelayEventSource.Log.Argument(nameof(connectionString), SR.GetString(SR.ConnectionStringMustNotIncludeEntityPath, nameof(HybridConnectionListener)), this); } builder.EntityPath = path; } this.Address = new Uri(builder.Endpoint, builder.EntityPath); this.ConnectionBufferSize = DefaultConnectionBufferSize; this.OperationTimeout = builder.OperationTimeout; this.proxy = DefaultWebProxy.Instance; this.TrackingContext = TrackingContext.Create(this.Address); this.connectionInputQueue = new InputQueue <HybridConnectionStream>(); this.controlConnection = new ControlConnection(this); this.useBuiltInClientWebSocket = HybridConnectionConstants.DefaultUseBuiltInClientWebSocket; this.ClientWebSocketFactory = Microsoft.Azure.Relay.ClientWebSocketFactory.Default; this.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval; this.TokenProvider = builder.CreateTokenProvider(); if (this.TokenProvider == null) { throw RelayEventSource.Log.Argument(nameof(connectionString), SR.CannotCreateTokenProviderFromConnectionString, this); } }
// This private .ctor handles both of the public overloads which take connectionString HybridConnectionListener(string connectionString, string path, bool pathFromConnectionString) { if (string.IsNullOrWhiteSpace(connectionString)) { throw RelayEventSource.Log.ArgumentNull(nameof(connectionString), this); } var builder = new RelayConnectionStringBuilder(connectionString); builder.Validate(); if (pathFromConnectionString) { if (string.IsNullOrWhiteSpace(builder.EntityPath)) { // connectionString did not have required EntityPath throw RelayEventSource.Log.Argument(nameof(connectionString), SR.GetString(SR.ConnectionStringMustIncludeEntityPath, nameof(HybridConnectionClient)), this); } } else { if (string.IsNullOrWhiteSpace(path)) { // path parameter is required throw RelayEventSource.Log.ArgumentNull(nameof(path), this); } else if (!string.IsNullOrWhiteSpace(builder.EntityPath)) { // EntityPath must not appear in connectionString throw RelayEventSource.Log.Argument(nameof(connectionString), SR.GetString(SR.ConnectionStringMustNotIncludeEntityPath, nameof(HybridConnectionListener)), this); } builder.EntityPath = path; } this.Address = new Uri(builder.Endpoint, builder.EntityPath); this.TokenProvider = builder.CreateTokenProvider(); this.ConnectionBufferSize = DefaultConnectionBufferSize; this.OperationTimeout = builder.OperationTimeout; this.proxy = WebRequest.DefaultWebProxy; this.TrackingContext = TrackingContext.Create(this.Address); this.clientConnections = new Dictionary <string, DataConnection>(); this.connectionInputQueue = new InputQueue <HybridConnectionStream>(); this.controlConnection = new ControlConnection(this); }
static TrackingContext CreateTrackingContext(Uri address) { #if DEBUG // In DEBUG builds allow setting the trackingId via query string: "?id=00000000-0000-0000-0000-000000000000" if (!string.IsNullOrEmpty(address.Query)) { string[] kvps = address.Query.TrimStart('?').Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries); foreach (string kvp in kvps) { if (kvp.StartsWith("id=", StringComparison.Ordinal)) { return(TrackingContext.Create(kvp.Substring(3), address)); } } } #endif // DEBUG return(TrackingContext.Create(address)); }
/// <summary> /// Create a new HybridConnectionListener instance for accepting HybridConnections. /// </summary> /// <param name="address">The address on which to listen for HybridConnections. This address should /// be of the format "sb://contoso.servicebus.windows.net/yourhybridconnection".</param> /// <param name="tokenProvider">The TokenProvider for connecting this listener to ServiceBus.</param> public HybridConnectionListener(Uri address, TokenProvider tokenProvider) { if (address == null || tokenProvider == null) { throw RelayEventSource.Log.ThrowingException(new ArgumentNullException(address == null ? nameof(address) : nameof(tokenProvider)), this); } else if (address.Scheme != RelayConstants.HybridConnectionScheme) { throw RelayEventSource.Log.ThrowingException( new ArgumentException(SR.InvalidUriScheme.FormatInvariant(address.Scheme, RelayConstants.HybridConnectionScheme), nameof(address)), this); } this.Address = address; this.TokenProvider = tokenProvider; this.ConnectionBufferSize = DefaultConnectionBufferSize; this.OperationTimeout = RelayConstants.DefaultOperationTimeout; this.proxy = WebRequest.DefaultWebProxy; this.TrackingContext = TrackingContext.Create(this.Address); this.connectionInputQueue = new InputQueue <HybridConnectionStream>(); this.controlConnection = new ControlConnection(this); }
TrackingContext GetTrackingContext() { var queryParameters = HybridConnectionUtility.ParseQueryString(this.rendezvousAddress.Query); string trackingId = queryParameters[HybridConnectionConstants.Id]; string path = this.rendezvousAddress.LocalPath; if (path.StartsWith(HybridConnectionConstants.HybridConnectionRequestUri, StringComparison.OrdinalIgnoreCase)) { path = path.Substring(HybridConnectionConstants.HybridConnectionRequestUri.Length); } Uri logicalAddress = new UriBuilder() { Scheme = Uri.UriSchemeHttps, Host = this.listener.Address.Host, Path = path, }.Uri; return(TrackingContext.Create(trackingId, logicalAddress)); }
/// <summary> /// Create a new HybridConnectionListener instance for accepting HybridConnections. /// </summary> /// <param name="address">The address on which to listen for HybridConnections. This address should /// be of the format "sb://contoso.servicebus.windows.net/yourhybridconnection".</param> /// <param name="tokenProvider">The TokenProvider for connecting this listener to ServiceBus.</param> public HybridConnectionListener(Uri address, TokenProvider tokenProvider) { if (address == null || tokenProvider == null) { throw RelayEventSource.Log.ThrowingException(new ArgumentNullException(address == null ? nameof(address) : nameof(tokenProvider)), this); } else if (address.Scheme != RelayConstants.HybridConnectionScheme) { throw RelayEventSource.Log.ThrowingException( new ArgumentException(SR.InvalidUriScheme.FormatInvariant(address.Scheme, RelayConstants.HybridConnectionScheme), nameof(address)), this); } this.Address = address; this.TokenProvider = tokenProvider; this.ConnectionBufferSize = DefaultConnectionBufferSize; this.OperationTimeout = RelayConstants.DefaultOperationTimeout; this.proxy = DefaultWebProxy.Instance; this.TrackingContext = TrackingContext.Create(this.Address); this.connectionInputQueue = new InputQueue <HybridConnectionStream>(); this.controlConnection = new ControlConnection(this); this.useBuiltInClientWebSocket = HybridConnectionConstants.DefaultUseBuiltInClientWebSocket; this.ClientWebSocketFactory = Microsoft.Azure.Relay.ClientWebSocketFactory.Default; this.KeepAliveInterval = HybridConnectionConstants.KeepAliveInterval; }