示例#1
0
        private static void OnAcceptCompleted(object _, SocketAsyncEventArgs socketAsyncEventArgs)
        {
            if (socketAsyncEventArgs == null)
            {
                throw new ArgumentNullException(nameof(socketAsyncEventArgs));
            }

            var acceptCompletionSource = (TaskCompletionSource <Socket>)socketAsyncEventArgs.UserToken;

            socketAsyncEventArgs.UserToken = null;

            if (socketAsyncEventArgs.ConnectByNameError != null)
            {
                acceptCompletionSource.TrySetException(socketAsyncEventArgs.ConnectByNameError);
            }
            else if (socketAsyncEventArgs.SocketError != SocketError.Success)
            {
                acceptCompletionSource.TrySetException(new SocketException((int)socketAsyncEventArgs.SocketError));
            }
            else
            {
                var socket = socketAsyncEventArgs.AcceptSocket;
                if (acceptCompletionSource.TrySetResult(socket) == false)
                {
                    SafeEnd.Dispose(socket);
                }
            }
        }
示例#2
0
        private async Task NegotiateWebSocket(Socket client)
        {
            await Task.Yield();

            ConfigureSocket(client);

            WebSocketNegotiationResult result;

            try
            {
                var timeoutTask = Task.Delay(_configuration.Options.NegotiationTimeout);
                var stream      = await NegotiateStreamAsync(client, timeoutTask).ConfigureAwait(false);

                var handshake = await HandshakeAsync(stream, timeoutTask).ConfigureAwait(false);

                if (handshake.IsValid)
                {
                    var ws = handshake.Factory.CreateWebSocket(stream, client, _configuration.Options, handshake);
                    result = new WebSocketNegotiationResult(ws);
                }
                else
                {
                    SafeEnd.Dispose(client);
                    result = new WebSocketNegotiationResult(handshake.Error);
                }
            }
            catch (Exception ex)
            {
                SafeEnd.Dispose(client);
                result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(ex));
            }

            await DeliverResultAsync(result).ConfigureAwait(false);
        }
示例#3
0
        public async Task CloseAsync()
        {
            var clients         = this.connectedClients.ToArray();
            var disconnectTasks = new Task[clients.Length];

            for (var i = 0; i < clients.Length; i++)
            {
                try
                {
                    disconnectTasks[i] = clients[i].CloseAsync().ContinueWith(
                        (t, s) => SafeEnd.Dispose((IDisposable)s, this.log),
                        clients[i],
                        CancellationToken.None,
                        TaskContinuationOptions.ExecuteSynchronously,
                        TaskScheduler.Default
                        );
                }
                catch (Exception error) when(error is ThreadAbortException == false)
                {
                    disconnectTasks[i] = TaskHelper.FailedTask(error);
                    lock (this.DetailedErrors)
                        this.DetailedErrors.Add(error.Unwrap());
                    Interlocked.Decrement(ref this.Errors);
                }
            }

            await Task.WhenAll(disconnectTasks).ConfigureAwait(false);

            await this.client.CloseAsync().ConfigureAwait(false);
        }
示例#4
0
        private NetworkConnection AcceptSocketAsConnection(Task <Socket> acceptTask, EndPoint acceptEndPoint)
        {
            var error = acceptTask.Exception.Unwrap();

            if (acceptTask.Status != TaskStatus.RanToCompletion)
            {
                if (this.log.IsDebugEnabled && error != null && error is OperationCanceledException == false && this.state == STATE_ACCEPTING)
                {
                    this.log.Debug($"Accept on '{acceptEndPoint}' has failed.", error);
                }
                return(null);
            }

            var socket = acceptTask.Result;

            if (this.log.IsDebugEnabled)
            {
                this.log.Debug($"New socket accepted. Remote address: '{socket.RemoteEndPoint}', Local address: {socket.LocalEndPoint}.");
            }

            try { return(this.CreateConnection(socket)); }
            catch
            {
                SafeEnd.Dispose(socket, this.log);
                throw;
            }
        }
示例#5
0
            public override async Task PingAsync()
            {
                if (this.connection.IsClosed)
                {
                    return;
                }

                var elapsedTime = TimestampToTimeSpan(Stopwatch.GetTimestamp()) - this.lastActivityTime;

                if (elapsedTime > this.pingTimeout)
                {
                    SafeEnd.Dispose(this.connection);

                    if (this.connection.log.IsDebugEnabled)
                    {
                        this.connection.log.Debug($"WebSocket connection ({this.connection.GetHashCode():X}) has been closed due ping timeout. Time elapsed: {elapsedTime}, timeout: {this.pingTimeout}.");
                    }

                    return;
                }

                var messageType = (WebSocketMessageType)WebSocketFrameOption.Ping;
                var count       = this.pingBuffer.Array[this.pingBuffer.Offset];
                var payload     = this.pingBuffer.Skip(1);

                // manual pinging is always enforces sending ping frames
                var pingFrame = this.connection.PrepareFrame(payload, count, true, false, messageType, WebSocketExtensionFlags.None);

                await this.connection.SendFrameAsync(pingFrame, Timeout.InfiniteTimeSpan, SendOptions.NoErrors, CancellationToken.None).ConfigureAwait(false);
            }
 public void Queue(Socket socket)
 {
     if (!_sockets.Post(socket))
     {
         SafeEnd.Dispose(socket);
     }
 }
示例#7
0
        /// <inheritdoc />
        protected override void Dispose(bool disposed)
        {
            if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED)
            {
                return;
            }

            foreach (var socket in this.sockets)
            {
                SafeEnd.Dispose(socket, this.log);
            }

            foreach (var acceptEvent in this.activeAcceptEvents.Concat(this.availableAcceptEvents))
            {
                var acceptCompletion = (TaskCompletionSource <Socket>)acceptEvent.UserToken;
                if (acceptCompletion != null)
                {
                    acceptCompletion.TrySetCanceled();
                    if (acceptCompletion.Task.Status == TaskStatus.RanToCompletion)
                    {
                        SafeEnd.Dispose(acceptCompletion.Task.Result, this.log);
                    }
                }
                SafeEnd.Dispose(acceptEvent, this.log);
            }
        }
        private async Task NegotiateWebSocket(Socket client)
        {
            WebSocketNegotiationResult result;

            try
            {
                var timeoutTask = Task.Delay(_options.NegotiationTimeout);
#if (NET45 || NET451 || NET452 || NET46)
                Stream stream = new NetworkStream(client, FileAccess.ReadWrite, true);
#elif (DNX451 || DNX452 || DNX46 || NETSTANDARD || UAP10_0 || DOTNET5_4 || NETSTANDARDAPP1_5)
                Stream stream = new NetworkStream(client);
#endif
                foreach (var conExt in _extensions)
                {
                    var extTask = conExt.ExtendConnectionAsync(stream);
                    await Task.WhenAny(timeoutTask, extTask).ConfigureAwait(false);

                    if (timeoutTask.IsCompleted)
                    {
                        throw new WebSocketException("Negotiation timeout (Extension: " + conExt.GetType().Name + ")");
                    }

                    stream = await extTask;
                }

                var handshakeTask = _handShaker.HandshakeAsync(stream);
                await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false);

                if (timeoutTask.IsCompleted)
                {
                    throw new WebSocketException("Negotiation timeout");
                }

                var handshake = await handshakeTask;

                if (handshake.IsValid)
                {
                    result = new WebSocketNegotiationResult(handshake.Factory.CreateWebSocket(stream, _options, (IPEndPoint)client.LocalEndPoint, (IPEndPoint)client.RemoteEndPoint, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions));
                }
                else
                {
                    SafeEnd.Dispose(client);
                    result = new WebSocketNegotiationResult(handshake.Error);
                }
            }
            catch (Exception ex)
            {
                SafeEnd.Dispose(client);
                result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(ex));
            }

            try
            {
                await _negotiations.SendAsync(result, _cancel.Token).ConfigureAwait(false);
            }
            finally
            {
                _semaphore.Release();
            }
        }
        /// <inheritdoc />
        protected override void Dispose(bool disposed)
        {
            if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED)
            {
                return;
            }

            SafeEnd.Dispose(this.server, this.log);
        }
        /// <inheritdoc />
        protected override void Dispose(bool disposing)
        {
            if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED)
            {
                return;
            }

            SafeEnd.Dispose(this.deflateStream);
            SafeEnd.Dispose(this.innerStream);
        }
        public void Dispose()
        {
            SafeEnd.Dispose(_semaphore);

            if (_cancel != null)
            {
                _cancel.Cancel();
                _cancel.Dispose();
            }
        }
        protected override void Dispose(bool disposing)
        {
            if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED)
            {
                return;
            }

            SafeEnd.Dispose(this.innerStream);

            this.bufferManager.ReturnBuffer(this.inflaterBuffer);
        }
示例#13
0
        protected SocketListener(SocketTransport transport, EndPoint[] endPointsToListen, ProtocolType protocolType, WebSocketListenerOptions options)
        {
            if (endPointsToListen == null)
            {
                throw new ArgumentNullException(nameof(endPointsToListen));
            }
            if (endPointsToListen.Any(p => p == null))
            {
                throw new ArgumentException("Null objects passed in array.", nameof(endPointsToListen));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            this.log            = options.Logger;
            this.sockets        = EmptySockets;
            this.localEndPoints = EmptyEndPoints;

            var boundSockets    = new Socket[endPointsToListen.Length];
            var boundEndpoints  = new EndPoint[endPointsToListen.Length];
            var activeEvents    = new SocketAsyncEventArgs[endPointsToListen.Length];
            var availableEvents = new SocketAsyncEventArgs[endPointsToListen.Length];

            try
            {
                for (var i = 0; i < boundSockets.Length; i++)
                {
                    boundSockets[i] = new Socket(endPointsToListen[i].AddressFamily, SocketType.Stream, protocolType);
                    boundSockets[i].Bind(endPointsToListen[i]);
                    boundSockets[i].Listen(transport.BacklogSize);
                    boundEndpoints[i]  = boundSockets[i].LocalEndPoint;
                    activeEvents[i]    = CreateSocketAsyncEvent();
                    availableEvents[i] = CreateSocketAsyncEvent();
                }

                this.sockets               = boundSockets;
                this.localEndPoints        = boundEndpoints;
                this.acceptTasks           = new Task <Socket> [boundSockets.Length];
                this.availableAcceptEvents = activeEvents;
                this.activeAcceptEvents    = availableEvents;
                boundSockets               = null;
            }
            finally
            {
                if (boundSockets != null)
                {
                    foreach (var socket in boundSockets)
                    {
                        SafeEnd.Dispose(socket);
                    }
                }
            }
        }
        /// <inheritdoc />
        public override void Dispose(bool disposed)
        {
            if (Interlocked.Exchange(ref this.closeState, STATE_DISPOSED) == STATE_DISPOSED)
            {
                return;
            }

            SafeEnd.Dispose(this.networkStream);
            SafeEnd.Dispose(this.socket);

            foreach (var socketEvent in this.socketEvents)
            {
                SafeEnd.Dispose(socketEvent);
            }
        }
        public override async Task CloseAsync()
        {
            if (_isClosed)
            {
                return;
            }

            _isClosed = true;
            await _deflate.FlushAsync().ConfigureAwait(false);

            SafeEnd.Dispose(_deflate); // TODO DeflateStream cant async flush buffer so this will cause sync Write call and blocks one thread from pool
            await _inner.WriteAsync(BFINAL, 0, 1).ConfigureAwait(false);

            await _inner.CloseAsync().ConfigureAwait(false);
        }
示例#16
0
        public void Dispose()
        {
            if (Interlocked.Exchange(ref this.closeState, WS_STATE_DISPOSED) == WS_STATE_DISPOSED)
            {
                return;
            }

            this.latency = Timeout.InfiniteTimeSpan;

            SafeEnd.Dispose(this.networkConnection, this.log);
            SafeEnd.Dispose(this.writeSemaphore, this.log);

            this.options.BufferManager.ReturnBuffer(this.SendBuffer.Array);
            this.options.BufferManager.ReturnBuffer(this.headerBuffer.Array);
        }
示例#17
0
        public void Dispose()
        {
            this.CloseAsync(WebSocketCloseReasons.NormalClose).Wait();

            if (Interlocked.Exchange(ref this.closeState, CLOSE_STATE_DISPOSED) == CLOSE_STATE_DISPOSED)
            {
                return;
            }

            this.options.BufferManager.ReturnBuffer(this.SendBuffer.Array);
            this.options.BufferManager.ReturnBuffer(this.closeBuffer.Array);

            SafeEnd.Dispose(this.writeSemaphore, this.log);
            SafeEnd.Dispose(this.networkConnection, this.log);
        }
示例#18
0
        public void Dispose()
        {
            SafeEnd.Dispose(_semaphore, this.log);

            _cancel?.Cancel(throwOnFirstException: false);
            foreach (var connection in this._connections.TakeAllAndClose(closeError: new OperationCanceledException()))
            {
                SafeEnd.Dispose(connection, this.log);
            }
            foreach (var negotiation in this._negotiations.TakeAllAndClose())
            {
                SafeEnd.Dispose(negotiation.Result, this.log);
            }

            SafeEnd.Dispose(this.pingQueue, this.log);
        }
示例#19
0
        public void Queue(NetworkConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            if (!this._connections.TryEnqueue(connection))
            {
                if (this.log.IsWarningEnabled)
                {
                    this.log.Warning($"Negotiation queue is full and can't process new connection from '{connection.RemoteEndPoint}'. Connection will be closed.");
                }
                connection.CloseAsync().ContinueWith(_ => SafeEnd.Dispose(connection, this.log), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
            }
        }
 public void Dispose()
 {
     try
     {
         this.Close();
     }
     catch { }
     finally
     {
         if (_options != null && _options.BufferManager != null)
         {
             _options.BufferManager.ReturnBuffer(_buffer);
         }
     }
     SafeEnd.Dispose(_writeSemaphore);
     SafeEnd.Dispose(_clientStream);
 }
            public override async Task PingAsync()
            {
                if (this.connection.IsClosed)
                {
                    return;
                }

                var elapsedTime = TimestampToTimeSpan(Stopwatch.GetTimestamp()) - this.lastActivityTime;

                if (elapsedTime > this.pingTimeout)
                {
                    this.connection.latency = Timeout.InfiniteTimeSpan;
                    SafeEnd.Dispose(this.connection);

                    if (this.connection.log.IsDebugEnabled)
                    {
                        this.connection.log.Debug($"WebSocket connection ({this.connection.GetHashCode():X}) has been closed due ping timeout. Time elapsed: {elapsedTime}, timeout: {this.pingTimeout}, interval: {this.pingInterval}.");
                    }

                    return;
                }

                ((ulong)Stopwatch.GetTimestamp()).ToBytes(this.pingBuffer.Array, this.pingBuffer.Offset);
                var messageType = (WebSocketMessageType)WebSocketFrameOption.Ping;

                var pingFrame            = this.connection.PrepareFrame(this.pingBuffer, 8, true, false, messageType, WebSocketExtensionFlags.None);
                var pingFrameLockTimeout = elapsedTime < this.pingInterval ? TimeSpan.Zero : Timeout.InfiniteTimeSpan;

                //
                // ping_interval is 33% of ping_timeout time
                //
                // if elapsed_time < ping_interval then TRY to send ping frame
                // if elapsed_time > ping_interval then ENFORCE sending ping frame because ping_timeout is near
                //
                // pingFrameLockTimeout is controlling TRY/ENFORCE behaviour. Zero mean TRY to take write lock or skip. InfiniteTimeSpan mean wait indefinitely for write lock.
                //

                await this.connection.SendFrameAsync(pingFrame, pingFrameLockTimeout, SendOptions.NoErrors, CancellationToken.None).ConfigureAwait(false);
            }
        /// <inheritdoc />
        public override async Task CloseAsync()
        {
            if (Interlocked.CompareExchange(ref this.closeState, STATE_CLOSING, STATE_OPEN) != STATE_OPEN)
            {
                return;
            }

            // shutdown send
            try
            {
                if (this.socket.Connected)
                {
                    this.socket.Shutdown(SocketShutdown.Send);
                }
            }
            catch (Exception shutdownError) when(shutdownError is ThreadAbortException == false)
            {
                /* ignore shutdown errors */
            }

            // read and discard all remaining data
            if (this.socket.Connected || this.socket.Available > 0)
            {
                try
                {
                    var receiveCompletionSource = default(TaskCompletionSource <int>);
                    do
                    {
                        receiveCompletionSource = new TaskCompletionSource <int>();
                        Swap(ref this.socketEvents[EVENT_ACTIVE_RECEIVE], ref this.socketEvents[EVENT_PREVIOUS_RECEIVE]);

                        var receiveEvent = this.socketEvents[EVENT_ACTIVE_RECEIVE];
                        receiveEvent.UserToken = receiveCompletionSource;
                        receiveEvent.SetBuffer(JunkBytes, 0, JunkBytes.Length);

                        if (this.socket.ReceiveAsync(receiveEvent) == false)
                        {
                            this.OnSocketOperationCompleted(this.socket, receiveEvent);
                        }
                    } while (await receiveCompletionSource.Task.ConfigureAwait(false) > 0);
                }
                catch (Exception readError) when(readError is ThreadAbortException == false)
                {
                    /* ignore read errors */
                }
            }

            // close socket
            try
            {
                this.socket.Dispose();
            }
            catch (Exception closeError) when(closeError is ThreadAbortException == false)
            {
                /* ignore close errors */
            }

            Interlocked.CompareExchange(ref this.closeState, STATE_CLOSED, STATE_CLOSING);

            SafeEnd.Dispose(this);
        }
示例#23
0
        private async Task NegotiateWebSocket(NetworkConnection networkConnection)
        {
            if (networkConnection == null)
            {
                throw new ArgumentNullException(nameof(networkConnection));
            }

            await Task.Yield();

            WebSocketNegotiationResult result;

            try
            {
                var timeoutTask = Task.Delay(_options.NegotiationTimeout);

                foreach (var conExt in _extensions)
                {
                    var extTask = conExt.ExtendConnectionAsync(networkConnection);
                    await Task.WhenAny(timeoutTask, extTask).ConfigureAwait(false);

                    if (timeoutTask.IsCompleted)
                    {
#pragma warning disable 4014
                        extTask.IgnoreFaultOrCancellation(); // make connection exception observed
#pragma warning restore 4014
                        throw new WebSocketException($"Negotiation timeout (Extension: {conExt.GetType().Name})");
                    }

                    networkConnection = await extTask.ConfigureAwait(false);
                }

                var handshakeTask = _handShaker.HandshakeAsync(networkConnection);
                await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false);

                if (timeoutTask.IsCompleted)
                {
#pragma warning disable 4014
                    handshakeTask.IgnoreFaultOrCancellation(); // make connection exception observed
#pragma warning restore 4014
                    throw new WebSocketException("Negotiation timeout");
                }

                var handshake = await handshakeTask.ConfigureAwait(false);

                if (handshake.IsValidWebSocketRequest)
                {
                    result = new WebSocketNegotiationResult(handshake.Factory.CreateWebSocket(networkConnection, _options, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions));
                }
                else if (handshake.IsValidHttpRequest && _options.HttpFallback != null)
                {
                    _options.HttpFallback.Post(handshake.Request, networkConnection);
                    return;
                }
                else
                {
                    SafeEnd.Dispose(networkConnection, this.log);
                    result = new WebSocketNegotiationResult(handshake.Error);
                }

                var webSocket = result.Result;
                if (_negotiations.TryEnqueue(result) == false)
                {
                    SafeEnd.Dispose(webSocket);
                    return; // too many negotiations
                }

                if (webSocket != null)
                {
                    this.pingQueue?.GetSubscriptionList().Add(webSocket);
                }
            }
            catch (Exception negotiationError)
            {
                if (this.log.IsDebugEnabled)
                {
                    this.log.Debug("An error occurred while negotiating WebSocket request.", negotiationError);
                }

                SafeEnd.Dispose(networkConnection, this.log);
                result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(negotiationError));
            }
            finally
            {
                _semaphore.Release();
            }
        }
示例#24
0
 public override void Dispose()
 {
     SafeEnd.Dispose(Connection);
 }
 /// <inheritdoc />
 public override void Dispose(bool disposed)
 {
     SafeEnd.Dispose(this.pipeStream);
 }
        /// <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 override void Dispose()
 {
     SafeEnd.Dispose(this.Connection, this.log);
 }
 protected override void Dispose(Boolean disposing)
 {
     SafeEnd.Dispose(_deflate);
     SafeEnd.Dispose(_inner);
     base.Dispose(disposing);
 }