示例#1
0
        /// <summary>Completes the SocketAsyncEventArg's Task with the result of the send or receive, and returns it to the specified pool.</summary>
        private static void CompleteSendReceive(Socket s, TaskSocketAsyncEventArgs <int> saea, bool isReceive)
        {
            // Pull the relevant state off of the SAEA
            SocketError error                        = saea.SocketError;
            int         bytesTransferred             = saea.BytesTransferred;
            bool        wrapExceptionsInIOExceptions = saea._wrapExceptionsInIOExceptions;

            // Synchronize with the initiating thread. If the synchronous caller already got what
            // it needs from the SAEA, then we can return it to the pool now. Otherwise, it'll be
            // responsible for returning it once it's gotten what it needs from it.
            bool responsibleForReturningToPool;
            AsyncTaskMethodBuilder <int> builder = saea.GetCompletionResponsibility(out responsibleForReturningToPool);

            if (responsibleForReturningToPool)
            {
                s.ReturnSocketAsyncEventArgs(saea, isReceive);
            }

            // Complete the builder/task with the results.
            if (error == SocketError.Success)
            {
                builder.SetResult(bytesTransferred);
            }
            else
            {
                builder.SetException(GetException(error, wrapExceptionsInIOExceptions));
            }
        }
示例#2
0
        /// <summary>Completes the SocketAsyncEventArg's Task with the result of the send or receive, and returns it to the specified pool.</summary>
        private static void CompleteAccept(Socket s, TaskSocketAsyncEventArgs <Socket> saea)
        {
            // Pull the relevant state off of the SAEA
            SocketError error        = saea.SocketError;
            Socket?     acceptSocket = saea.AcceptSocket;

            // Synchronize with the initiating thread. If the synchronous caller already got what
            // it needs from the SAEA, then we can return it to the pool now. Otherwise, it'll be
            // responsible for returning it once it's gotten what it needs from it.
            bool responsibleForReturningToPool;
            AsyncTaskMethodBuilder <Socket> builder = saea.GetCompletionResponsibility(out responsibleForReturningToPool);

            if (responsibleForReturningToPool)
            {
                s.ReturnSocketAsyncEventArgs(saea);
            }

            // Complete the builder/task with the results.
            if (error == SocketError.Success)
            {
                builder.SetResult(acceptSocket !);
            }
            else
            {
                builder.SetException(GetException(error));
            }
        }
示例#3
0
        /// <summary>Returns a <see cref="TaskSocketAsyncEventArgs{TResult}"/> instance for reuse.</summary>
        /// <param name="saea">The instance to return.</param>
        /// <param name="isReceive">true if this instance is used for receives; false if used for sends.</param>
        private void ReturnSocketAsyncEventArgs(TaskSocketAsyncEventArgs <int> saea, bool isReceive)
        {
            // Reset state on the SAEA before returning it.  But do not reset buffer state.  That'll be done
            // if necessary by the consumer, but we want to keep the buffers due to likely subsequent reuse
            // and the costs associated with changing them.
            saea._accessed = false;
            saea._builder  = default;
            saea._wrapExceptionsInIOExceptions = false;

            // Write this instance back as a cached instance, only if there isn't currently one cached.
            ref TaskSocketAsyncEventArgs <int>?cache = ref isReceive ? ref _multiBufferReceiveEventArgs : ref _multiBufferSendEventArgs;
示例#4
0
        internal Task <Socket> AcceptAsync(Socket acceptSocket)
        {
            // Get any cached SocketAsyncEventArg we may have.
            TaskSocketAsyncEventArgs <Socket> saea = Interlocked.Exchange(ref LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs).Accept, s_rentedSocketSentinel);

            if (saea == s_rentedSocketSentinel)
            {
                // An instance was once created (or is currently being created elsewhere), but some other
                // concurrent operation is using it. Since we can store at most one, and since an individual
                // APM operation is less expensive than creating a new SAEA and using it only once, we simply
                // fall back to using an APM implementation.
                return(AcceptAsyncApm(acceptSocket));
            }
            else if (saea == null)
            {
                // No instance has been created yet, so create one.
                saea            = new TaskSocketAsyncEventArgs <Socket>();
                saea.Completed += AcceptCompletedHandler;
            }

            // Configure the SAEA.
            saea.AcceptSocket = acceptSocket;

            // Initiate the accept operation.
            Task <Socket> t;

            if (AcceptAsync(saea))
            {
                // The operation is completing asynchronously (it may have already completed).
                // Get the task for the operation, with appropriate synchronization to coordinate
                // with the async callback that'll be completing the task.
                bool responsibleForReturningToPool;
                t = saea.GetCompletionResponsibility(out responsibleForReturningToPool).Task;
                if (responsibleForReturningToPool)
                {
                    // We're responsible for returning it only if the callback has already been invoked
                    // and gotten what it needs from the SAEA; otherwise, the callback will return it.
                    ReturnSocketAsyncEventArgs(saea);
                }
            }
            else
            {
                // The operation completed synchronously.  Get a task for it.
                t = saea.SocketError == SocketError.Success ?
                    Task.FromResult(saea.AcceptSocket) :
                    Task.FromException <Socket>(GetException(saea.SocketError));

                // There won't be a callback, and we're done with the SAEA, so return it to the pool.
                ReturnSocketAsyncEventArgs(saea);
            }

            return(t);
        }
示例#5
0
        /// <summary>Gets a task to represent the operation.</summary>
        /// <param name="pending">true if the operation completes asynchronously; false if it completed synchronously.</param>
        /// <param name="saea">The event args instance used with the operation.</param>
        /// <param name="fromNetworkStream">
        /// true if the request is coming from NetworkStream, which has special semantics for
        /// exceptions and cached tasks; otherwise, false.
        /// </param>
        /// <param name="isReceive">true if this is a receive; false if this is a send.</param>
        private Task <int> GetTaskForSendReceive(bool pending, TaskSocketAsyncEventArgs <int> saea, bool fromNetworkStream, bool isReceive)
        {
            Task <int> t;

            if (pending)
            {
                // The operation is completing asynchronously (it may have already completed).
                // Get the task for the operation, with appropriate synchronization to coordinate
                // with the async callback that'll be completing the task.
                bool responsibleForReturningToPool;
                t = saea.GetCompletionResponsibility(out responsibleForReturningToPool).Task;
                if (responsibleForReturningToPool)
                {
                    // We're responsible for returning it only if the callback has already been invoked
                    // and gotten what it needs from the SAEA; otherwise, the callback will return it.
                    ReturnSocketAsyncEventArgs(saea, isReceive);
                }
            }
            else
            {
                // The operation completed synchronously.  Get a task for it.
                if (saea.SocketError == SocketError.Success)
                {
                    // Get the number of bytes successfully received/sent.
                    int bytesTransferred = saea.BytesTransferred;

                    // For zero bytes transferred, we can return our cached 0 task.
                    // We can also do so if the request came from network stream and is a send,
                    // as for that we can return any value because it returns a non-generic Task.
                    if (bytesTransferred == 0 || (fromNetworkStream & !isReceive))
                    {
                        t = s_zeroTask;
                    }
                    else
                    {
                        // Otherwise, create a new task for this result value.
                        t = Task.FromResult(bytesTransferred);
                    }
                }
                else
                {
                    t = Task.FromException <int>(GetException(saea.SocketError, wrapExceptionsInIOExceptions: fromNetworkStream));
                }

                // There won't be a callback, and we're done with the SAEA, so return it to the pool.
                ReturnSocketAsyncEventArgs(saea, isReceive);
            }

            return(t);
        }
        /// <summary>
        /// Establishes a new connection for a request.
        /// </summary>
        /// <param name="message">The request causing this connection to be established. Once connected, it may be reused for many subsequent requests.</param>
        /// <param name="endPoint">The EndPoint to connect to.</param>
        /// <param name="options">Properties, if any, that might change how the connection is made.</param>
        /// <param name="cancellationToken">A cancellation token for the asynchronous operation.</param>
        /// <returns>A new open connection.</returns>
        public virtual async ValueTask <Connection> EstablishConnectionAsync(HttpRequestMessage message, EndPoint?endPoint, IConnectionProperties options, CancellationToken cancellationToken)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (endPoint == null)
            {
                throw new ArgumentNullException(nameof(endPoint));
            }

            Socket socket = CreateSocket(message, endPoint, options);

            try
            {
                using var args      = new TaskSocketAsyncEventArgs();
                args.RemoteEndPoint = endPoint;

                if (socket.ConnectAsync(args))
                {
                    using (cancellationToken.UnsafeRegister(o => Socket.CancelConnectAsync((SocketAsyncEventArgs)o !), args))
                    {
                        await args.Task.ConfigureAwait(false);
                    }
                }

                if (args.SocketError != SocketError.Success)
                {
                    Exception ex = args.SocketError == SocketError.OperationAborted && cancellationToken.IsCancellationRequested
                        ? (Exception) new OperationCanceledException(cancellationToken)
                        : new SocketException((int)args.SocketError);

                    throw ex;
                }

                socket.NoDelay = true;
                return(new SocketConnection(socket));
            }
            catch (SocketException socketException)
            {
                socket.Dispose();
                throw NetworkErrorHelper.MapSocketException(socketException);
            }
            catch
            {
                socket.Dispose();
                throw;
            }
        }
示例#7
0
        internal Task <int> SendAsync(IList <ArraySegment <byte> > buffers, SocketFlags socketFlags)
        {
            ValidateBuffersList(buffers);

            TaskSocketAsyncEventArgs <int>?saea = Interlocked.Exchange(ref _multiBufferSendEventArgs, null);

            if (saea is null)
            {
                saea            = new TaskSocketAsyncEventArgs <int>();
                saea.Completed += (s, e) => CompleteSendReceive((Socket)s !, (TaskSocketAsyncEventArgs <int>)e, isReceive: false);
            }

            saea.BufferList  = buffers;
            saea.SocketFlags = socketFlags;
            return(GetTaskForSendReceive(SendAsync(saea), saea, fromNetworkStream: false, isReceive: false));
        }
示例#8
0
        /// <summary>Returns a <see cref="Int32TaskSocketAsyncEventArgs"/> instance for reuse.</summary>
        /// <param name="saea">The instance to return.</param>
        /// <param name="isReceive">true if this instance is used for receives; false if used for sends.</param>
        private void ReturnSocketAsyncEventArgs(TaskSocketAsyncEventArgs <Socket> saea)
        {
            Debug.Assert(_cachedTaskEventArgs != null, "Should have been initialized when renting");
            Debug.Assert(saea != s_rentedSocketSentinel);

            // Reset state on the SAEA before returning it.  But do not reset buffer state.  That'll be done
            // if necessary by the consumer, but we want to keep the buffers due to likely subsequent reuse
            // and the costs associated with changing them.
            saea.AcceptSocket = null;
            saea._accessed    = false;
            saea._builder     = default(AsyncTaskMethodBuilder <Socket>);

            // Write this instance back as a cached instance.  It should only ever be overwriting the sentinel,
            // never null or another instance.
            Debug.Assert(_cachedTaskEventArgs.Accept == s_rentedSocketSentinel);
            Volatile.Write(ref _cachedTaskEventArgs.Accept, saea);
        }
示例#9
0
        internal Task <Socket> AcceptAsync(Socket?acceptSocket)
        {
            // Get any cached SocketAsyncEventArg we may have.
            TaskSocketAsyncEventArgs <Socket>?saea = Interlocked.Exchange(ref _acceptEventArgs, null);

            if (saea is null)
            {
                saea            = new TaskSocketAsyncEventArgs <Socket>();
                saea.Completed += (s, e) => CompleteAccept((Socket)s !, (TaskSocketAsyncEventArgs <Socket>)e);
            }

            // Configure the SAEA.
            saea.AcceptSocket = acceptSocket;

            // Initiate the accept operation.
            Task <Socket> t;

            if (AcceptAsync(saea))
            {
                // The operation is completing asynchronously (it may have already completed).
                // Get the task for the operation, with appropriate synchronization to coordinate
                // with the async callback that'll be completing the task.
                bool responsibleForReturningToPool;
                t = saea.GetCompletionResponsibility(out responsibleForReturningToPool).Task;
                if (responsibleForReturningToPool)
                {
                    // We're responsible for returning it only if the callback has already been invoked
                    // and gotten what it needs from the SAEA; otherwise, the callback will return it.
                    ReturnSocketAsyncEventArgs(saea);
                }
            }
            else
            {
                // The operation completed synchronously.  Get a task for it.
                t = saea.SocketError == SocketError.Success ?
                    Task.FromResult(saea.AcceptSocket !) :
                    Task.FromException <Socket>(GetException(saea.SocketError));

                // There won't be a callback, and we're done with the SAEA, so return it to the pool.
                ReturnSocketAsyncEventArgs(saea);
            }

            return(t);
        }