public async Task BeforeSetContinuationTest(int subscribers) { var condition = new AsyncConditionSource(isSet: true); var hits = 0; var parallelLoopResult = Parallel.For(0, subscribers, i => { condition.GetAwaiter().OnCompleted(() => Interlocked.Increment(ref hits)); }); while (parallelLoopResult.IsCompleted == false) { await Task.Delay(10).ConfigureAwait(false); } var sw = Stopwatch.StartNew(); while (sw.ElapsedMilliseconds < 1000 && subscribers != hits) { Thread.Sleep(10); } this.logger.Debug($"[TEST] subscribers: {subscribers}, hits: {hits}."); Assert.Equal(subscribers, hits); }
public WebSocketClient([NotNull] WebSocketListenerOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (options.Standards.Count == 0) { throw new ArgumentException("Empty list of WebSocket standards.", nameof(options)); } options.CheckCoherence(); this.options = options.Clone(); this.options.SetUsed(true); if (this.options.NegotiationTimeout > TimeSpan.Zero) { this.negotiationsTimeoutQueue = new CancellationQueue(this.options.NegotiationTimeout); } if (this.options.PingMode != PingMode.Manual) { this.pingQueue = new PingQueue(options.PingInterval); } this.log = this.options.Logger; this.closeEvent = new AsyncConditionSource(isSet: true) { ContinueOnCapturedContext = false }; this.workCancellationSource = new CancellationTokenSource(); this.pendingRequests = new ConcurrentDictionary <WebSocketHandshake, Task <WebSocket> >(); if (this.options.BufferManager == null) { this.options.BufferManager = BufferManager.CreateBufferManager(100, this.options.SendBufferSize * 2); // create small buffer pool if not configured } if (this.options.CertificateValidationHandler == null) { this.options.CertificateValidationHandler = this.ValidateRemoteCertificate; } }
/// <inheritdoc /> internal override async Task <NetworkConnection> ConnectAsync(Uri address, WebSocketListenerOptions options, CancellationToken cancellation) { if (address == null) { throw new ArgumentNullException(nameof(address)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } var remoteEndPoint = this.GetRemoteEndPoint(address); var protocolType = this.GetProtocolType(address, remoteEndPoint); // prepare socket var socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Stream, protocolType); this.SetupClientSocket(socket, remoteEndPoint); try { // prepare connection var socketConnectedCondition = new AsyncConditionSource { ContinueOnCapturedContext = false }; var socketAsyncEventArgs = new SocketAsyncEventArgs { RemoteEndPoint = remoteEndPoint, UserToken = socketConnectedCondition }; // connect socketAsyncEventArgs.Completed += (_, e) => ((AsyncConditionSource)e.UserToken).Set(); // interrupt connection when cancellation token is set var connectInterruptRegistration = cancellation.CanBeCanceled ? cancellation.Register(s => ((AsyncConditionSource)s).Interrupt(new OperationCanceledException()), socketConnectedCondition) : default(CancellationTokenRegistration); using (connectInterruptRegistration) { if (socket.ConnectAsync(socketAsyncEventArgs) == false) { socketConnectedCondition.Set(); } await socketConnectedCondition; } cancellation.ThrowIfCancellationRequested(); // check connection result if (socketAsyncEventArgs.ConnectByNameError != null) { throw socketAsyncEventArgs.ConnectByNameError; } if (socketAsyncEventArgs.SocketError != SocketError.Success) { throw new WebSocketException($"Failed to open socket to '{address}' due error '{socketAsyncEventArgs.SocketError}'.", new SocketException((int)socketAsyncEventArgs.SocketError)); } var localEndPoint = default(EndPoint); try { localEndPoint = socket.LocalEndPoint; } catch { if (UnixSocketTransport.IsUnixEndPoint(remoteEndPoint)) { localEndPoint = remoteEndPoint; } } var connection = new SocketConnection(socket, localEndPoint); socket = null; return(connection); } finally { if (socket != null) { SafeEnd.Dispose(socket, options.Logger); } } }
public async Task StartAsync() { if (this.options.Standards.Count <= 0) { throw new WebSocketException($"There are no WebSocket standards. Please, register standards using {nameof(WebSocketListenerOptions)}.{nameof(WebSocketListenerOptions.Standards)}."); } if (this.options.Transports.Count <= 0) { throw new WebSocketException($"There are no WebSocket transports. Please, register transports using {nameof(WebSocketListenerOptions)}.{nameof(WebSocketListenerOptions.Transports)}."); } if (Interlocked.CompareExchange(ref state, STATE_STARTING, STATE_STOPPED) != STATE_STOPPED) { throw new WebSocketException("Failed to start listener from current state. Maybe it is disposed or already started."); } this.options.SetUsed(true); var listeners = default(Listener[]); try { if (this.log.IsDebugEnabled) { this.log.Debug($"{nameof(WebSocketListener)} is starting."); } var endPoints = new Tuple <Uri, WebSocketTransport> [this.listenEndPoints.Length]; for (var i = 0; i < this.listenEndPoints.Length; i++) { var listenEndPoint = this.listenEndPoints[i]; var transport = default(WebSocketTransport); if (this.options.Transports.TryGetWebSocketTransport(listenEndPoint, out transport) == false) { throw new WebSocketException($"Unable to find transport for '{listenEndPoint}'. Available transports are: {string.Join(", ", this.options.Transports.SelectMany(t => t.Schemes).Distinct())}."); } endPoints[i] = Tuple.Create(listenEndPoint, transport); } listeners = new Listener[endPoints.Length]; for (var i = 0; i < endPoints.Length; i++) { listeners[i] = await endPoints[i].Item2.ListenAsync(endPoints[i].Item1, this.options).ConfigureAwait(false); } this.listeners = listeners; this.localEndPoints = this.listeners.SelectMany(l => l.LocalEndpoints).ToArray(); this.stopConditionSource = new AsyncConditionSource(isSet: true) { ContinueOnCapturedContext = false }; if (Interlocked.CompareExchange(ref state, STATE_STARTED, STATE_STARTING) != STATE_STARTING) { throw new WebSocketException("Failed to start listener from current state. Maybe it is disposed."); } this.AcceptConnectionsAsync().LogFault(this.log); if (this.log.IsDebugEnabled) { this.log.Debug($"{nameof(WebSocketListener)} is started."); } listeners = null; } catch { this.options.SetUsed(false); throw; } finally { // try to revert from starting state to stopped state Interlocked.CompareExchange(ref state, STATE_STOPPED, STATE_STARTING); if (listeners != null) { foreach (var listener in listeners) { SafeEnd.Dispose(listener); } this.listeners = EmptyListeners; this.localEndPoints = EmptyEndPoints; this.stopConditionSource = null; } } }