internal Task <int> SendAsync(ArraySegment <byte> buffer, SocketFlags socketFlags, bool wrapExceptionsInIOExceptions) { // Validate the arguments. ValidateBuffer(buffer); // Get the SocketAsyncEventArgs instance to use for the operation. Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: false); if (saea == null) { // We couldn't get a cached instance, which means there's already a receive operation // happening on this socket. Fall back to wrapping APM. var tcs = new TaskCompletionSource <int>(this); BeginSend(buffer.Array, buffer.Offset, buffer.Count, socketFlags, iar => { var innerTcs = (TaskCompletionSource <int>)iar.AsyncState; try { innerTcs.TrySetResult(((Socket)innerTcs.Task.AsyncState).EndSend(iar)); } catch (Exception e) { innerTcs.TrySetException(e); } }, tcs); return(tcs.Task); } // Configure the buffer. We don't clear the buffers when returning the SAEA to the pool, // so as to minimize overhead if the same buffer is used for subsequent operations (which is likely). // But SAEA doesn't support having both a buffer and a buffer list configured, so clear out a buffer list // if there is one before we set the desired buffer. if (saea.BufferList != null) { saea.BufferList = null; } saea.SetBuffer(buffer.Array, buffer.Offset, buffer.Count); saea.SocketFlags = socketFlags; saea.WrapExceptionsInIOExceptions = wrapExceptionsInIOExceptions; // Initiate the send Task <int> t; if (!SendAsync(saea)) { // The operation completed synchronously. Get a task for it and return the SAEA for future use. t = saea.SocketError == SocketError.Success ? GetSuccessTask(saea) : Task.FromException <int>(GetException(saea.SocketError, wrapExceptionsInIOExceptions)); ReturnSocketAsyncEventArgs(saea, isReceive: false); } else { // The operation completed asynchronously. Get the task for the operation, // with appropriate synchronization to coordinate with the async callback // that'll be completing the task. t = saea.GetTaskSafe(); } return(t); }
/// <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(Int32TaskSocketAsyncEventArgs saea, bool isReceive) { // Synchronize with the initiating thread accessing the task from the builder. saea.GetTaskSafe(); // Pull the relevant state off of the SAEA and only then return it to the pool. Socket s = (Socket)saea.UserToken; AsyncTaskMethodBuilder <int> builder = saea.Builder; SocketError error = saea.SocketError; int bytesTransferred = saea.BytesTransferred; bool wrapExceptionsInIOExceptions = saea.WrapExceptionsInIOExceptions; s.ReturnSocketAsyncEventArgs(saea, isReceive); // Complete the builder/task with the results. if (error == SocketError.Success) { builder.SetResult(bytesTransferred); } else { builder.SetException(GetException(error, wrapExceptionsInIOExceptions)); } }