// // AcceptCallback - called by WaitCallback to do special Accept handling // this involves searching through a queue of queued Accept requests // and handling them if there are available accept sockets to handle them, // or rewaiting if they are not // // The overlapped function called by the thread pool // when IO completes. // internal static void AcceptCallback(object stateObject, bool Signaled) { AcceptAsyncResult thisAsyncResult = (AcceptAsyncResult)stateObject; Socket socket = (Socket)thisAsyncResult.AsyncObject; Exception unhandledException = null; Monitor.Enter(socket); // // Accept Callback - called on the callback path, when we expect to release // an accept socket that winsock says has completed. // // While we still have items in our Queued list of Accept Requests, // we recall the Winsock accept, to attempt to gather new // results, and then match them again the queued items, // when accept call returns would_block, we reinvoke ourselves // and rewait for the next asyc callback. // // If we have emptied the queue, then disable the queue and go back // to sync. // socket.incallback = true; // // Attempt to process queued Accept async // while (socket.AcceptQueue.Count != 0) // if ! empty // // pick an element from the head of the list // { AcceptAsyncResult AResult = (AcceptAsyncResult)socket.AcceptQueue[0]; socket.AcceptQueue.RemoveAt(0); Monitor.Exit(socket); int Status = SocketErrors.WSAENOTSOCK; SocketAddress socketAddress = null; IntPtr AcceptResult = (IntPtr)0; if (!socket.CleanedUp) { socketAddress = socket.m_RightEndPoint.Serialize(); AcceptResult = UnsafeNclNativeMethods.OSSOCK.accept( socket.m_Handle, socketAddress.m_Buffer, ref socketAddress.m_Size); Status = AcceptResult == SocketErrors.InvalidSocketIntPtr ? Marshal.GetLastWin32Error() : 0; } GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::AcceptCallback() UnsafeNclNativeMethods.OSSOCK.accept returns:" + Status.ToString()); // // now check for synchronous completion // if (Status == 0) { // // on synchronous completion give our async callback // the accepted Socket right away // try { AResult.InvokeCallback(false, socket.CreateAcceptSocket(AcceptResult, socket.m_RightEndPoint.Create(socketAddress))); } catch (Exception exception) { unhandledException = new InvalidOperationException("AcceptCallback", exception); } } else if (Status == SocketErrors.WSAEWOULDBLOCK) { Monitor.Enter(socket); socket.AcceptQueue.Add(AResult); ThreadPool.RegisterWaitForSingleObject( socket.m_AsyncEvent, new WaitOrTimerCallback(AcceptCallback), thisAsyncResult, -1, true); socket.incallback = false; Monitor.Exit(socket); return; } else { try { AResult.ErrorCode = Status; AResult.InvokeCallback(false, null); } catch (Exception exception) { unhandledException = new InvalidOperationException("AcceptCallback", exception); } } // // Attempt to accept another socket // Monitor.Enter(socket); } socket.incallback = false; // // the accept queue is empty. // cancel async event // socket.SetAsyncEventSelect(AsyncEventBits.FdNone); // // go back to blocking mode // socket.InternalSetBlocking(true); Monitor.Exit(socket); if (unhandledException != null) { throw unhandledException; } }