//
// 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;
}
}