Retail products


Traffic interception SDK

Control every TCP/IP network connection

  • Route connections via proxy
  • Redirect connections and modify the data
  • Block connections and applications
SSL interception SDK

View SSL in plaintext and modify it

  • View the SSL stream decrypted in plaintext
  • Redirect SSL connection and modify decrypted data
  • Browser shows "SSL lock" without warnings

Documentation


overlap.cpp File Reference

#include "lspdef.h"
#include <stdio.h>
#include <stdlib.h>

Include dependency graph for overlap.cpp:

Go to the source code of this file.


Functions

LPWSAOVERLAPPEDPLUS AllocOverlappedStructure (SOCK_INFO *SocketContext)
void FreeOverlappedStructure (WSAOVERLAPPEDPLUS *olp)
int ExecuteOverlappedOperation (WSAOVERLAPPEDPLUS *lpOverlapped, BOOL bSynchronous)
int EnqueueOverlappedOperation (WSAOVERLAPPEDPLUS *op)
void SetOverlappedInProgress (OVERLAPPED *ol)
DWORD WINAPI OverlappedManagerThread (LPVOID lpParam)
VOID CALLBACK CallUserApcProc (ULONG_PTR Context)
void CheckForContextCleanup (WSAOVERLAPPEDPLUS *ol)
int InitOverlappedManager ()
int StopOverlappedManager ()
int QueueOverlappedOperation (WSAOVERLAPPEDPLUS *ol, SOCK_INFO *SocketContext)
WSAOVERLAPPEDPLUSDequeueOverlappedOperation ()
void CALLBACK IntermediateCompletionRoutine (DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
WSAOVERLAPPEDPLUSPrepareOverlappedOperation (SOCK_INFO *SocketContext, LspOperation operation, WSABUF *lpBuffers, DWORD dwBufferCount, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, int *lpErrno)
void UndoOverlappedOperation (SOCK_INFO *SocketContext, WSAOVERLAPPEDPLUS *ProviderOverlapped)
void FreeOverlappedLookasideList ()

Variables

HANDLE * gWorkerThread = NULL
HANDLE gWakeupSemaphore = NULL
HANDLE gIocp = NULL
DWORD gThreadCount = (DWORD)-1

Function Documentation

LPWSAOVERLAPPEDPLUS AllocOverlappedStructure ( SOCK_INFO SocketContext  ) 

Definition at line 913 of file overlap.cpp.

00916 {
00917     LPWSAOVERLAPPEDPLUS lpWorkerOverlappedPlus = NULL;
00918 
00919     if ( NULL == SocketContext )
00920     {
00921         dbgprint("AllocOverlappedStructure: SocketContext is NULL!");
00922         return NULL;
00923     }
00924 
00925     EnterCriticalSection( &gOverlappedCS );
00926 
00927     AcquireSocketLock( SocketContext );
00928 
00929     //
00930     // We have to keep track of the number of outstanding overlapped requests 
00931     // an application has. Otherwise, if the app were to close a socket that 
00932     // had oustanding overlapped ops remaining, we'd start leaking structures 
00933     // in gOverlappedPool. The idea here is to force the CallerSocket to remain 
00934     // open until the lower provider has processed all the overlapped requests. 
00935     // If we closed both the lower socket and the caller socket, we would no 
00936     // longer be able to correlate completed requests to any apps sockets.
00937     //
00938     (SocketContext->dwOutstandingAsync)++;
00939 
00940     if ( IsListEmpty( &gFreeOverlappedPlus ) )
00941     {
00942         int     err;
00943 
00944         lpWorkerOverlappedPlus = (WSAOVERLAPPEDPLUS *) LspAlloc( 
00945                 sizeof(WSAOVERLAPPEDPLUS), 
00946                &err 
00947                 );
00948     }
00949     else
00950     {
00951         LIST_ENTRY  *entry = NULL;
00952 
00953         entry = RemoveHeadList( &gFreeOverlappedPlus );
00954 
00955         lpWorkerOverlappedPlus = CONTAINING_RECORD( entry, WSAOVERLAPPEDPLUS, Link );
00956     }
00957 
00958     ReleaseSocketLock( SocketContext );
00959 
00960     LeaveCriticalSection( &gOverlappedCS );
00961 
00962     return lpWorkerOverlappedPlus;
00963 }

VOID CALLBACK CallUserApcProc ( ULONG_PTR  Context  ) 

Definition at line 1255 of file overlap.cpp.

01258 {
01259     LPOVERLAPPED                        lpOverlapped;
01260     LPWSAOVERLAPPED_COMPLETION_ROUTINE  UserCompletionRoutine;
01261 
01262     lpOverlapped = (LPOVERLAPPED) Context;
01263     UserCompletionRoutine  = (LPWSAOVERLAPPED_COMPLETION_ROUTINE)lpOverlapped->Internal;
01264     lpOverlapped->Internal = 0; // Remove the WSS_OPERATION_IN_PROGRESS value 
01265 
01266     UserCompletionRoutine(
01267             (DWORD)lpOverlapped->OffsetHigh,
01268             (DWORD)lpOverlapped->InternalHigh,
01269             lpOverlapped,
01270             (DWORD)lpOverlapped->Offset
01271             );
01272     return;
01273 }

void CheckForContextCleanup ( WSAOVERLAPPEDPLUS ol  ) 

Definition at line 1285 of file overlap.cpp.

01288 {
01289     SOCK_INFO  *SocketContext = NULL;
01290     int         Error,
01291                 ret;
01292 
01293     SocketContext = FindAndRefSocketContext( ol->CallerSocket, &Error );
01294     if ( NULL == SocketContext )
01295     {
01296         dbgprint( "CheckForContextCleanup: FindAndRefSocketContext failed!" );
01297         return;
01298     }
01299 
01300     EnterCriticalSection( &gCriticalSection );
01301 
01302     AcquireSocketLock( ol->SockInfo );
01303 
01304     (ol->SockInfo->dwOutstandingAsync)--;
01305 
01306     if ( ( TRUE == ol->SockInfo->bClosing ) && 
01307          ( 0 == ol->SockInfo->dwOutstandingAsync ) &&
01308          ( 1 == ol->SockInfo->RefCount )
01309        )
01310     {
01311         //
01312         // If the calling app closed the socket while there were still outstanding
01313         //  async operations then all the outstanding operations have completed so
01314         //  we can close the apps socket handle.
01315         //
01316         ret = gMainUpCallTable.lpWPUCloseSocketHandle(
01317                 ol->CallerSocket, 
01318                &ol->Error
01319                 );
01320         if ( SOCKET_ERROR == ret )
01321         {
01322             dbgprint("CheckForContextClenaup: WPUCloseSocketHandle() failed: %d", ol->Error);
01323         }
01324 
01325         ol->SockInfo->LayeredSocket = INVALID_SOCKET;
01326 
01327         RemoveSocketInfo( ol->SockInfo->Provider, ol->SockInfo );
01328 
01329         dbgprint("CheckForContxtCleanup: Closing socket %d Bytes Sent [%lu] Bytes Recv [%lu]", 
01330                 ol->CallerSocket, ol->SockInfo->BytesSent, ol->SockInfo->BytesRecv);
01331 
01332         ReleaseSocketLock( ol->SockInfo );
01333 
01334         ol->SockInfo = NULL;
01335 
01336         FreeSockInfo( SocketContext );
01337 
01338         goto cleanup;
01339     }
01340 
01341     ReleaseSocketLock( ol->SockInfo );
01342 
01343     DerefSocketContext( SocketContext, &Error );
01344 
01345 cleanup:
01346 
01347     LeaveCriticalSection( &gCriticalSection );
01348 
01349     return;
01350 }

WSAOVERLAPPEDPLUS* DequeueOverlappedOperation (  ) 

Definition at line 472 of file overlap.cpp.

00474 {
00475     WSAOVERLAPPEDPLUS   *op = NULL;
00476     LIST_ENTRY         *link = NULL;
00477 
00478     EnterCriticalSection( &gOverlappedCS );
00479 
00480     link = RemoveHeadList( &gPendingOperations );
00481 
00482     op = CONTAINING_RECORD( link, WSAOVERLAPPEDPLUS, Link );
00483 
00484     /*
00485     op = gPendingStart;
00486     if ( NULL != gPendingStart )
00487     {
00488         gPendingStart = op->next;
00489     }
00490     if (op == gPendingEnd)
00491     {
00492         gPendingStart = gPendingEnd = NULL;
00493     }
00494     */
00495 
00496     LeaveCriticalSection( &gOverlappedCS );
00497 
00498     return op;
00499 }

int EnqueueOverlappedOperation ( WSAOVERLAPPEDPLUS op  ) 

Definition at line 433 of file overlap.cpp.

00436 {
00437     int ret = WSA_IO_PENDING;
00438 
00439     EnterCriticalSection( &gOverlappedCS );
00440 
00441     if ( NULL == op )
00442     {
00443         dbgprint("EnqueueOverlappedOperation: op == NULL!");
00444         ret = WSAEFAULT;
00445         goto cleanup;
00446     }
00447 
00448     InsertTailList( &gPendingOperations, &op->Link );
00449 
00450     //
00451     // Increment the semaphore count. This lets the worker thread
00452     // know that there are pending overlapped operations to execute.
00453     //
00454     ReleaseSemaphore( gWakeupSemaphore, 1, NULL );
00455 
00456 cleanup:
00457 
00458     LeaveCriticalSection( &gOverlappedCS );
00459 
00460     return ret;
00461 }

int ExecuteOverlappedOperation ( WSAOVERLAPPEDPLUS lpOverlapped,
BOOL  bSynchronous 
)

Definition at line 512 of file overlap.cpp.

00516 {
00517     LPWSAOVERLAPPED_COMPLETION_ROUTINE   routine = NULL;
00518     PROVIDER                            *Provider;
00519     DWORD                               *lpdwFlags = NULL,
00520                                         *lpdwBytes = NULL;
00521     int                                  ret=SOCKET_ERROR, err=0;
00522 
00523     if ( NULL == gIocp)
00524         routine = IntermediateCompletionRoutine;
00525 
00526     Provider = ol->Provider;
00527 
00528     //
00529     // Reset the event handle if present. The handle is masked with 0xFFFFFFFE in
00530     //  order to zero out the last bit. If the last bit is one and the socket is
00531     //  associated with a compeltion port then when an overlapped operation is 
00532     //  called, the operation is not posted to the IO completion port.
00533     //
00534     if ( NULL != ol->lpCallerOverlapped->hEvent )
00535     {
00536         ULONG_PTR   ptr = 1;
00537 
00538         ResetEvent( (HANDLE) ( (ULONG_PTR) ol->lpCallerOverlapped->hEvent & ~ptr ) );
00539     }
00540 
00541     switch ( ol->Operation )
00542     {
00543         case LSP_OP_IOCTL:
00544             lpdwFlags = NULL;
00545             lpdwBytes = &ol->IoctlArgs.cbBytesReturned;
00546             ret = Provider->NextProcTable.lpWSPIoctl(
00547                     ol->ProviderSocket,
00548                     ol->IoctlArgs.dwIoControlCode,
00549                     ol->IoctlArgs.lpvInBuffer,
00550                     ol->IoctlArgs.cbInBuffer,
00551                     ol->IoctlArgs.lpvOutBuffer,
00552                     ol->IoctlArgs.cbOutBuffer,
00553                    &ol->IoctlArgs.cbBytesReturned,
00554                    &ol->ProviderOverlapped,
00555                     routine,
00556                    &ol->CallerThreadId,
00557                    &err
00558                    );
00559             break;                         
00560 
00561         case LSP_OP_RECV:
00562             lpdwFlags = &ol->RecvArgs.dwFlags;
00563             lpdwBytes = &ol->RecvArgs.dwNumberOfBytesRecvd;
00564             ret = Provider->NextProcTable.lpWSPRecv(
00565                     ol->ProviderSocket,
00566                     ol->RecvArgs.lpBuffers,
00567                     ol->RecvArgs.dwBufferCount,
00568                    &ol->RecvArgs.dwNumberOfBytesRecvd,
00569                    &ol->RecvArgs.dwFlags,
00570                    &ol->ProviderOverlapped,
00571                     routine,
00572                    &ol->CallerThreadId,
00573                    &err
00574                     );
00575             break;
00576 
00577         case LSP_OP_RECVFROM:
00578             lpdwFlags = &ol->RecvFromArgs.dwFlags;
00579             lpdwBytes = &ol->RecvFromArgs.dwNumberOfBytesRecvd;
00580             ret = Provider->NextProcTable.lpWSPRecvFrom(
00581                     ol->ProviderSocket,
00582                     ol->RecvFromArgs.lpBuffers,
00583                     ol->RecvFromArgs.dwBufferCount,
00584                    &ol->RecvFromArgs.dwNumberOfBytesRecvd,
00585                    &ol->RecvFromArgs.dwFlags,
00586                     ol->RecvFromArgs.lpFrom,
00587                     ol->RecvFromArgs.lpFromLen,
00588                    &ol->ProviderOverlapped,
00589                     routine,
00590                    &ol->CallerThreadId,
00591                    &err
00592                     );
00593             break;
00594 
00595         case LSP_OP_SEND:
00596             lpdwFlags = &ol->SendArgs.dwFlags;
00597             lpdwBytes = &ol->SendArgs.dwNumberOfBytesSent;
00598             ret = Provider->NextProcTable.lpWSPSend(
00599                     ol->ProviderSocket,
00600                     ol->SendArgs.lpBuffers,
00601                     ol->SendArgs.dwBufferCount,
00602                    &ol->SendArgs.dwNumberOfBytesSent,
00603                     ol->SendArgs.dwFlags,
00604                    &ol->ProviderOverlapped,
00605                     routine,
00606                    &ol->CallerThreadId,
00607                    &err
00608                    );
00609              break;
00610 
00611         case LSP_OP_SENDTO:
00612             lpdwFlags = &ol->SendToArgs.dwFlags;
00613             lpdwBytes = &ol->SendToArgs.dwNumberOfBytesSent;
00614             ret = Provider->NextProcTable.lpWSPSendTo(
00615                     ol->ProviderSocket,
00616                     ol->SendToArgs.lpBuffers,
00617                     ol->SendToArgs.dwBufferCount,
00618                    &ol->SendToArgs.dwNumberOfBytesSent,
00619                     ol->SendToArgs.dwFlags,
00620                     (SOCKADDR *)&ol->SendToArgs.To,
00621                     ol->SendToArgs.iToLen,
00622                    &ol->ProviderOverlapped,
00623                     routine,
00624                    &ol->CallerThreadId,
00625                    &err
00626                     );
00627             break;
00628 
00629         case LSP_OP_TRANSMITFILE:
00630             lpdwFlags = &ol->TransmitFileArgs.dwFlags;
00631             lpdwBytes = NULL;
00632             ret = Provider->NextProcTableExt.lpfnTransmitFile(
00633                     ol->ProviderSocket,
00634                     ol->TransmitFileArgs.hFile,
00635                     ol->TransmitFileArgs.nNumberOfBytesToWrite,
00636                     ol->TransmitFileArgs.nNumberOfBytesPerSend,
00637                    &ol->ProviderOverlapped,
00638                     ol->TransmitFileArgs.lpTransmitBuffers,
00639                     ol->TransmitFileArgs.dwFlags
00640                     );
00641             if ( FALSE == ret )
00642             {
00643                 ret = SOCKET_ERROR;
00644                 err = WSAGetLastError();
00645                 WSASetLastError(err);
00646             }
00647             else
00648             {
00649                 ret = NO_ERROR;
00650             }
00651             break;
00652 
00653         case LSP_OP_ACCEPTEX:
00654             lpdwFlags = NULL;
00655             lpdwBytes = &ol->AcceptExArgs.dwBytesReceived;
00656             ret = Provider->NextProcTableExt.lpfnAcceptEx(
00657                     ol->ProviderSocket,
00658                     ol->AcceptExArgs.sProviderAcceptSocket,
00659                     ol->AcceptExArgs.lpOutputBuffer,
00660                     ol->AcceptExArgs.dwReceiveDataLength,
00661                     ol->AcceptExArgs.dwLocalAddressLength,
00662                     ol->AcceptExArgs.dwRemoteAddressLength,
00663                    &ol->AcceptExArgs.dwBytesReceived,
00664                    &ol->ProviderOverlapped
00665                     );
00666             if ( FALSE == ret )
00667             {
00668                 ret = SOCKET_ERROR;
00669                 err = WSAGetLastError();
00670                 WSASetLastError(err);
00671             }
00672             else
00673             {
00674                 ret = NO_ERROR;
00675             }
00676             break;
00677 
00678         case LSP_OP_CONNECTEX:
00679             lpdwFlags = NULL;
00680             lpdwBytes = &ol->ConnectExArgs.dwBytesSent;
00681             ret = Provider->NextProcTableExt.lpfnConnectEx(
00682                     ol->ProviderSocket,
00683                     (SOCKADDR *)&ol->ConnectExArgs.name,
00684                     ol->ConnectExArgs.namelen,
00685                     ol->ConnectExArgs.lpSendBuffer,
00686                     ol->ConnectExArgs.dwSendDataLength,
00687                    &ol->ConnectExArgs.dwBytesSent,
00688                    &ol->ProviderOverlapped
00689                     );
00690             if ( FALSE == ret )
00691             {
00692                 ret = SOCKET_ERROR;
00693                 err = WSAGetLastError();
00694                 WSASetLastError(err);
00695             }
00696             else
00697             {
00698                 ret = NO_ERROR;
00699             }
00700             break;
00701 
00702         case LSP_OP_DISCONNECTEX:
00703             lpdwFlags = &ol->DisconnectExArgs.dwFlags;
00704             lpdwBytes = NULL;
00705             ret = Provider->NextProcTableExt.lpfnDisconnectEx(
00706                     ol->ProviderSocket,
00707                    &ol->ProviderOverlapped,
00708                     ol->DisconnectExArgs.dwFlags,
00709                     ol->DisconnectExArgs.dwReserved
00710                     );
00711             if ( FALSE == ret )
00712             {
00713                 ret = SOCKET_ERROR;
00714                 err = WSAGetLastError();
00715                 WSASetLastError(err);
00716             }
00717             else
00718             {
00719                 ret = NO_ERROR;
00720             }
00721             break;
00722 
00723         case LSP_OP_TRANSMITPACKETS:
00724             lpdwFlags = &ol->TransmitPacketsArgs.dwFlags;
00725             lpdwBytes = NULL;
00726             ret = Provider->NextProcTableExt.lpfnTransmitPackets(
00727                     ol->ProviderSocket,
00728                     ol->TransmitPacketsArgs.lpPacketArray,
00729                     ol->TransmitPacketsArgs.nElementCount,
00730                     ol->TransmitPacketsArgs.nSendSize,
00731                    &ol->ProviderOverlapped,
00732                     ol->TransmitPacketsArgs.dwFlags
00733                     );
00734             if ( FALSE == ret )
00735             {
00736                 ret = SOCKET_ERROR;
00737                 err = WSAGetLastError();
00738                 WSASetLastError(err);
00739             }
00740             else
00741             {
00742                 ret = NO_ERROR;
00743             }
00744             break;
00745 
00746         case LSP_OP_WSARECVMSG:
00747             lpdwFlags = NULL;
00748             lpdwBytes = &ol->WSARecvMsgArgs.dwNumberOfBytesRecvd;
00749             ret = Provider->NextProcTableExt.lpfnWSARecvMsg(
00750                     ol->ProviderSocket,
00751                     ol->WSARecvMsgArgs.lpMsg,
00752                    &ol->WSARecvMsgArgs.dwNumberOfBytesRecvd,
00753                    &ol->ProviderOverlapped,
00754                     routine
00755                     );
00756             if ( SOCKET_ERROR == ret )
00757             {
00758                 err = WSAGetLastError();
00759                 WSASetLastError( err );
00760             }
00761             else
00762             {
00763                 ret = NO_ERROR;
00764             }
00765             break;
00766 
00767         default:
00768             dbgprint("ExecuteOverlappedOperation: Unknown operation!");
00769             ret = SOCKET_ERROR;
00770             break;
00771     }
00772 
00773     if ( ( NO_ERROR != ret ) && ( WSA_IO_PENDING != err ) )
00774     {
00775         //
00776         // If the call immediately fails, update the OVERLAPPED info and return
00777         //
00778         ol->lpCallerOverlapped->Offset       = (lpdwFlags ? *lpdwFlags : 0);
00779         ol->lpCallerOverlapped->OffsetHigh   = err;
00780         ol->lpCallerOverlapped->InternalHigh = (lpdwBytes ? *lpdwBytes : 0);
00781         ol->lpCallerOverlapped->Internal     = 0;
00782 
00783         dbgprint("Overlap op failed immediately: %d", ol->Error);
00784 
00785         CheckForContextCleanup( ol );
00786 
00787         FreeOverlappedStructure( ol );
00788     }
00789     else if ( ( NO_ERROR == ret ) && ( FALSE == bSynchronous ) )
00790     {
00791         // 
00792         // NOTE: We could return success from here, but if you want to perform
00793         //       some post processing on the data buffers before indicating
00794         //       success to the upper layer (because once success is returned, the
00795         //       upper layer can inspect the buffers). Because of this we return
00796         //       pending and in the completion processing (either via IOCP or
00797         //       APC), we can do post processing there.
00798         //
00799         err = WSA_IO_PENDING;
00800         ret = SOCKET_ERROR;
00801     }
00802     else if ( ( NO_ERROR == ret ) && ( TRUE == bSynchronous ) )
00803     {
00804         // The winsock call actually blocked and there will be no completion
00805         // notification on the IOCP.
00806         //
00807         dbgprint("Succeeded without error - synchronous socket though");
00808     }
00809 
00810     return ( ( NO_ERROR == ret ) ? ret : err );
00811 }

void FreeOverlappedLookasideList (  ) 

Definition at line 1545 of file overlap.cpp.

01547 {
01548     WSAOVERLAPPEDPLUS  *olp = NULL;
01549     LIST_ENTRY         *entry = NULL;
01550 
01551     EnterCriticalSection( &gOverlappedCS );
01552 
01553     while ( ! IsListEmpty( &gFreeOverlappedPlus ) )
01554     {
01555         entry = RemoveHeadList( &gFreeOverlappedPlus );
01556 
01557         olp = CONTAINING_RECORD( entry, WSAOVERLAPPEDPLUS, Link );
01558 
01559         LspFree( olp );
01560     }
01561 
01562     LeaveCriticalSection( &gOverlappedCS );
01563 }

void FreeOverlappedStructure ( WSAOVERLAPPEDPLUS olp  ) 

Definition at line 973 of file overlap.cpp.

00976 {
00977     EnterCriticalSection( &gOverlappedCS );
00978 
00979     switch ( olp->Operation )
00980     {
00981         case LSP_OP_RECV:
00982             FreeWSABuf( olp->RecvArgs.lpBuffers );
00983             break;
00984 
00985         case LSP_OP_RECVFROM:
00986             FreeWSABuf( olp->RecvFromArgs.lpBuffers );
00987             break;
00988 
00989         case LSP_OP_SEND:
00990             FreeWSABuf( olp->SendArgs.lpBuffers );
00991             break;
00992 
00993         case LSP_OP_SENDTO:
00994             FreeWSABuf( olp->SendToArgs.lpBuffers );
00995             break;
00996 
00997         default:
00998             break;
00999     }
01000 
01001     memset( olp, 0, sizeof( WSAOVERLAPPEDPLUS ) );
01002 
01003     InsertHeadList( &gFreeOverlappedPlus, &olp->Link );
01004 
01005     LeaveCriticalSection( &gOverlappedCS );
01006 }

int InitOverlappedManager (  ) 

Definition at line 127 of file overlap.cpp.

00129 {
00130     DWORD   i;
00131     int     ret = NO_ERROR;
00132 
00133     EnterCriticalSection( &gOverlappedCS );
00134 
00135     //
00136     // Make sure we're not already initialized -- we'll always have at least
00137     // one worker thread running
00138     //
00139     if ( NULL != gWorkerThread )
00140         goto cleanup;
00141 
00142     InitializeListHead( &gFreeOverlappedPlus );
00143     InitializeListHead( &gPendingOperations );
00144 
00145     //
00146     // See if we're on NT by trying to create the completion port. If it
00147     //  fails then we're on Win9x.
00148     //
00149     gIocp = CreateIoCompletionPort(
00150             INVALID_HANDLE_VALUE,
00151             NULL,
00152             (ULONG_PTR)0,
00153             0
00154             );
00155     if ( NULL != gIocp )
00156     {
00157         SYSTEM_INFO     sinfo;
00158 
00159         //
00160         // We're on NT so figure out how many processors we have
00161         //
00162         GetSystemInfo( &sinfo );
00163         gThreadCount = sinfo.dwNumberOfProcessors;
00164     }
00165     else
00166     {
00167         //
00168         // We're on Win9x so create a semaphore instead. This is used to
00169         //  wake up the worker thread to service overlapped IO calls.
00170         //
00171         gWakeupSemaphore = CreateSemaphore(
00172                 NULL,
00173                 0,
00174                 MAXLONG,
00175                 NULL
00176                 );
00177         if ( NULL == gWakeupSemaphore )
00178         {
00179             dbgprint("InitOverlappedManager: CreateSemaphore() failed: %d", GetLastError());
00180             ret = WSAEPROVIDERFAILEDINIT;
00181             goto cleanup;
00182         }
00183 
00184         //
00185         // This is Win9x, no multiproc support so create just a single thread
00186         //
00187         gThreadCount = 1;
00188     }
00189 
00190     dbgprint("Creating %d threads", gThreadCount);
00191 
00192     gWorkerThread = (HANDLE *) LspAlloc(
00193             sizeof( HANDLE ) * gThreadCount,
00194            &ret         // if fails, ret will be WSAENOBUFS
00195             );
00196     if ( NULL == gWorkerThread )
00197     {
00198         goto cleanup;
00199     }
00200 
00201     //
00202     // Create our worker threads
00203     //
00204     for(i=0; i < gThreadCount ;i++)
00205     {
00206         gWorkerThread[i] = CreateThread(
00207                 NULL, 
00208                 0, 
00209                 OverlappedManagerThread, 
00210                 (LPVOID)gIocp, 
00211                 0, 
00212                 NULL
00213                 );
00214         if ( NULL == gWorkerThread[ i ] )
00215         {
00216             dbgprint("InitOverlappedManager: CreateThread() failed: %d", GetLastError());
00217             ret = WSAEPROVIDERFAILEDINIT;
00218             goto cleanup;
00219         }
00220     }
00221 
00222 cleanup:
00223 
00224     LeaveCriticalSection( &gOverlappedCS );
00225 
00226     return ret;
00227 }

void CALLBACK IntermediateCompletionRoutine ( DWORD  dwError,
DWORD  cbTransferred,
LPWSAOVERLAPPED  lpOverlapped,
DWORD  dwFlags 
)

Definition at line 1033 of file overlap.cpp.

01039 {
01040     LPWSAOVERLAPPEDPLUS olp = NULL;
01041     SOCK_INFO          *SocketContext = NULL,
01042                        *AcceptSocketContext = NULL;
01043     int                 Error,
01044                         ret;
01045 
01046     if ( NULL == lpOverlapped )
01047     {
01048         dbgprint("IntermediateCompletionRoutine: lpOverlapped == NULL!");
01049         goto cleanup;
01050     }
01051 
01052     ASSERT( lpOverlapped );
01053 
01054     olp = CONTAINING_RECORD( lpOverlapped, WSAOVERLAPPEDPLUS, ProviderOverlapped );
01055 
01056     //
01057     // We actually already have the socket context for this operation (its in
01058     //    the WSAOVERLAPPEDPLUS structure but do this anyway to make sure the
01059     //    socket hasn't been closed as well as to increment the ref count while
01060     //    we're accessing the SOCK_INFO structure.
01061     //
01062     SocketContext = FindAndRefSocketContext(olp->CallerSocket, &Error);
01063     if ( NULL == SocketContext )
01064     {
01065         dbgprint( "IntermediateCompletionRoutine: FindAndRefSocketContext failed!" );
01066         goto cleanup;
01067     }
01068 
01069     if ( WSA_IO_PENDING == dwError )
01070     {
01071         //
01072         // Get the results of the operation
01073         //
01074 
01075         ASSERT( olp->Provider );
01076         ASSERT( olp->Provider->NextProcTable.lpWSPGetOverlappedResult );
01077 
01078         dwError = NO_ERROR;
01079         ret = olp->Provider->NextProcTable.lpWSPGetOverlappedResult(
01080                 olp->ProviderSocket,
01081                 lpOverlapped,
01082                &cbTransferred,
01083                 FALSE,
01084                &dwFlags,
01085                 (int *)&dwError
01086                 );
01087  
01088         if ( FALSE == ret )
01089         {
01090             dbgprint("IntermediateCompletionRoutine: WSPGetOverlappedResult failed: %d", dwError);
01091         }
01092         else
01093         {
01094 
01095             dbgprint("Bytes transferred on socket 0x%x: %d [op=%d; err=%d]", 
01096                     olp->CallerSocket, cbTransferred, olp->Operation, dwError);
01097         }
01098     }
01099 
01100     olp->lpCallerOverlapped->Offset       = dwFlags;
01101     olp->lpCallerOverlapped->OffsetHigh   = dwError;
01102     olp->lpCallerOverlapped->InternalHigh = cbTransferred;
01103 
01104     SocketContext->LastError = dwError;
01105 
01106     if ( 0 == dwError )
01107     {
01108         AcquireSocketLock( SocketContext );
01109 
01110         //
01111         // NOTE: This is where any post processing should go for overlapped operations.
01112         //       For example, if you wanted to inspect the data received, you would do
01113         //       that here for any operation that receives data (don't forget AcceptEx!).
01114         //       In this sample, all we do is count the bytes sent and received on the
01115         //       socket.
01116         //
01117 
01118         switch ( olp->Operation )
01119         {
01120             case LSP_OP_RECV:
01121                 SocketContext->BytesRecv += cbTransferred;
01122                 FreeWSABuf(olp->RecvArgs.lpBuffers);
01123                 break;
01124 
01125             case LSP_OP_RECVFROM:
01126                 SocketContext->BytesRecv += cbTransferred;
01127                 FreeWSABuf(olp->RecvFromArgs.lpBuffers);
01128                 break;
01129 
01130             case LSP_OP_SEND:
01131                 SocketContext->BytesSent += cbTransferred;
01132                 FreeWSABuf(olp->SendArgs.lpBuffers);
01133                 break;
01134 
01135             case LSP_OP_SENDTO:
01136                 SocketContext->BytesSent += cbTransferred;
01137                 FreeWSABuf(olp->SendToArgs.lpBuffers);
01138                 break;
01139 
01140             case LSP_OP_TRANSMITFILE:
01141                 SocketContext->BytesSent += cbTransferred;
01142                 break;
01143 
01144             case LSP_OP_TRANSMITPACKETS:
01145                 SocketContext->BytesSent += cbTransferred;
01146                 break;
01147 
01148             case LSP_OP_ACCEPTEX:
01149 
01150                 ReleaseSocketLock( SocketContext );
01151 
01152                 AcceptSocketContext = FindAndRefSocketContext(
01153                         olp->AcceptExArgs.sAcceptSocket,
01154                        &Error
01155                        );
01156                 if (AcceptSocketContext == NULL)
01157                 {
01158                     dbgprint( "IntermediateCompletionRoutine: FindAndRefSocketContext failed! (LSP_OP_ACCEPTEX)" );
01159                 }
01160                 AcquireSocketLock( AcceptSocketContext );
01161 
01162                 AcceptSocketContext->BytesRecv += cbTransferred;
01163 
01164                 ReleaseSocketLock( AcceptSocketContext );
01165 
01166                 DerefSocketContext(AcceptSocketContext, &Error);
01167 
01168                 break;
01169 
01170             case LSP_OP_CONNECTEX:
01171                 SocketContext->BytesSent += cbTransferred;
01172                 break;
01173 
01174             case LSP_OP_WSARECVMSG:
01175                 SocketContext->BytesRecv += cbTransferred;
01176                 break;
01177 
01178             default:
01179                 break;
01180         }
01181         // Already released for AcceptEx operations
01182         if ( LSP_OP_ACCEPTEX != olp->Operation )
01183             ReleaseSocketLock( SocketContext );
01184     }
01185 
01186     DerefSocketContext( SocketContext, &Error );
01187 
01188     if ( NULL != olp->lpCallerCompletionRoutine )
01189     {
01190         //
01191         // If the app supplied a completion routine, queue it up for completion
01192         //
01193         olp->lpCallerOverlapped->Internal = (ULONG_PTR)olp->lpCallerCompletionRoutine;
01194 
01195         ret = gMainUpCallTable.lpWPUQueueApc(
01196                &olp->CallerThreadId,
01197                CallUserApcProc,
01198                (DWORD_PTR) olp->lpCallerOverlapped,
01199               &Error
01200                );
01201         if ( SOCKET_ERROR == ret )
01202         {
01203             dbgprint("IntermediateCompletionRoutine: WPUQueueApc() failed: %d", Error);
01204         }
01205     }
01206     else
01207     {
01208         //
01209         // Otherwise we signal that the op has completed
01210         //
01211         ret = WPUCompleteOverlappedRequest(
01212                 olp->CallerSocket,
01213                 olp->lpCallerOverlapped,
01214                 dwError,
01215                 cbTransferred,
01216                &Error
01217                 );
01218         if ( SOCKET_ERROR == ret )
01219         {
01220             dbgprint("WPUCompleteOverlappedRequest failed: %d (provider socket 0x%x)", 
01221                     Error, olp->CallerSocket );
01222         }
01223     }
01224 
01225     if ( ( NULL != olp ) && ( TRUE == olp->CloseThread ) )
01226     {
01227         ret = gMainUpCallTable.lpWPUCloseThread( &olp->CallerThreadId, &Error );
01228         if ( SOCKET_ERROR == ret )
01229         {
01230             dbgprint("WPUCloseThread failed: %d", Error );
01231         }
01232         olp->CloseThread = FALSE;
01233     }
01234 
01235     //
01236     // Cleanup the accounting on the socket
01237     //
01238     CheckForContextCleanup( olp );
01239 
01240 cleanup:
01241 
01242     if ( NULL != olp )
01243         FreeOverlappedStructure( olp );
01244 
01245     return;
01246 }

DWORD WINAPI OverlappedManagerThread ( LPVOID  lpParam  ) 

Definition at line 822 of file overlap.cpp.

00825 {
00826     WSAOVERLAPPEDPLUS *pOverlapPlus = NULL;
00827     WSAOVERLAPPED     *pOverlap = NULL;
00828     HANDLE             hIocp = (HANDLE)lpParam;
00829     ULONG_PTR          key;
00830     DWORD              dwBytesXfered;
00831     int                ret;
00832 
00833     while ( TRUE )
00834     {
00835         if ( NULL != hIocp )
00836         {
00837             ret = GetQueuedCompletionStatus(
00838                     hIocp,
00839                    &dwBytesXfered,
00840                    &key,
00841                    &pOverlap,
00842                     INFINITE
00843                     );
00844             if ( 0 == ret )
00845             {
00846                 // Socket failures could be reported here so we still
00847                 // call IntermediateCompletionRoutine
00848                 dbgprint("GetQueuedCompletionStatus() failed: %d", GetLastError());
00849             }
00850 
00851             if ( -1 == dwBytesXfered )
00852             {
00853                 //
00854                 // StopOverlappedManager will send a completion packet with -1
00855                 //    bytes transfered to indicate the completion routine
00856                 //    should exit
00857                 //
00858                 dbgprint("OverlappedManagerThread: Received exit message");
00859                 goto cleanup;
00860             }
00861 
00862             // Handle the IO that completed
00863             IntermediateCompletionRoutine(
00864                     WSA_IO_PENDING,
00865                     dwBytesXfered,
00866                     pOverlap,
00867                     0
00868                     );
00869         }
00870         else
00871         {
00872             ret = WaitForSingleObjectEx(
00873                     gWakeupSemaphore,
00874                     INFINITE, 
00875                     TRUE
00876                     );
00877             if ( WAIT_IO_COMPLETION == ret )
00878             {
00879                 // An APC fired so keep waiting until semaphore is signaled
00880                 continue;
00881             }
00882             else if ( WAIT_OBJECT_0 == ret )
00883             {
00884                 pOverlapPlus = DequeueOverlappedOperation();
00885                 if ( NULL == pOverlapPlus )
00886                     continue;
00887 
00888                 ExecuteOverlappedOperation( pOverlapPlus, FALSE );
00889             }
00890             else
00891             {
00892                 dbgprint("OverlappedManagerThread: WaitForSingleObjectEx() failed: %d (error = %d)",
00893                         ret, GetLastError() );
00894                 goto cleanup;
00895             }
00896         }
00897     }
00898 
00899 cleanup:
00900 
00901     ExitThread( 0 );
00902 }

WSAOVERLAPPEDPLUS* PrepareOverlappedOperation ( SOCK_INFO SocketContext,
LspOperation  operation,
WSABUF *  lpBuffers,
DWORD  dwBufferCount,
LPWSAOVERLAPPED  lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
LPWSATHREADID  lpThreadId,
int *  lpErrno 
)

Definition at line 1361 of file overlap.cpp.

01371 {
01372     WSAOVERLAPPEDPLUS *ProviderOverlapped = NULL;
01373     int                ret = SOCKET_ERROR,
01374                        err = 0;
01375 
01376     // Allocate a WSAOVERLAPPEDPLUS structure
01377     ProviderOverlapped = AllocOverlappedStructure( SocketContext );
01378     if ( NULL == ProviderOverlapped )
01379     {
01380         *lpErrno = WSAENOBUFS;
01381         goto cleanup;
01382     }
01383 
01384     __try 
01385     {
01386         // Check for an event and reset if. Also, copy the offsets from the upper
01387         // layer's WSAOVERLAPPED structure.
01388         if ( ( NULL == lpCompletionRoutine ) && 
01389              ( NULL != lpOverlapped->hEvent ) )
01390         { 
01391             ULONG_PTR   ptr = 1;
01392 
01393             ret = ResetEvent( (HANDLE) ( (ULONG_PTR) lpOverlapped->hEvent & ~ptr ) );
01394             if (ret == 0)
01395             {
01396                 *lpErrno = ERROR_INVALID_HANDLE;
01397                 ret = SOCKET_ERROR;
01398                 goto cleanup;
01399             }
01400         }
01401 
01402         // Copy any offset information from the caller's overlapped to ours
01403         CopyOffset( &ProviderOverlapped->ProviderOverlapped, lpOverlapped );
01404 
01405     }
01406     __except(EXCEPTION_EXECUTE_HANDLER)
01407     {
01408         *lpErrno = WSAEFAULT;
01409         goto cleanup;
01410     }
01411 
01412     if ( NULL != lpThreadId )
01413     {
01414         ProviderOverlapped->CallerThreadId = *lpThreadId;
01415     }
01416     else
01417     {
01418         // If thread info wasn't passed to us, we need to open the thread context
01419         ret = gMainUpCallTable.lpWPUOpenCurrentThread( &ProviderOverlapped->CallerThreadId, &err );
01420         if ( SOCKET_ERROR == ret )
01421         {
01422             dbgprint("WPUOpenCurrentThread failed: %d", err);
01423         }
01424         else
01425         {
01426             // Need to remember for later to close the context since we opened it
01427             ProviderOverlapped->CloseThread = TRUE;
01428         }
01429     }
01430 
01431     // Fill in the remaining fields
01432     ProviderOverlapped->Provider           = SocketContext->Provider;
01433     ProviderOverlapped->lpCallerOverlapped = lpOverlapped;
01434     ProviderOverlapped->lpCallerCompletionRoutine = lpCompletionRoutine;
01435     ProviderOverlapped->SockInfo           = SocketContext;
01436     ProviderOverlapped->CallerSocket       = SocketContext->LayeredSocket;
01437     ProviderOverlapped->ProviderSocket     = SocketContext->ProviderSocket;
01438     ProviderOverlapped->Error              = NO_ERROR;
01439     ProviderOverlapped->Operation          = operation;
01440 
01441     if ( ( NULL != lpBuffers) && ( dwBufferCount ) )
01442     {
01443         // Depending on the underlying operation, copy some parameters specific to it
01444         switch ( operation )
01445         {
01446             case LSP_OP_RECV:
01447                 ProviderOverlapped->RecvArgs.dwBufferCount = dwBufferCount;
01448                 ProviderOverlapped->RecvArgs.lpBuffers = CopyWSABuf(
01449                         lpBuffers,
01450                         dwBufferCount,
01451                         lpErrno
01452                         );
01453                 if ( NULL == ProviderOverlapped->RecvArgs.lpBuffers )
01454                     goto cleanup;
01455 
01456                 break;
01457 
01458             case LSP_OP_RECVFROM:
01459                 ProviderOverlapped->RecvFromArgs.dwBufferCount = dwBufferCount;
01460                 ProviderOverlapped->RecvFromArgs.lpBuffers = CopyWSABuf(
01461                         lpBuffers,
01462                         dwBufferCount,
01463                         lpErrno
01464                         );
01465                 if ( NULL == ProviderOverlapped->RecvFromArgs.lpBuffers )
01466                     goto cleanup;
01467 
01468                 break;
01469 
01470             case LSP_OP_SEND:
01471                 ProviderOverlapped->SendArgs.dwBufferCount = dwBufferCount;
01472                 ProviderOverlapped->SendArgs.lpBuffers = CopyWSABuf(
01473                         lpBuffers,
01474                         dwBufferCount,
01475                         lpErrno
01476                         );
01477                 if ( NULL == ProviderOverlapped->SendArgs.lpBuffers )
01478                     goto cleanup;
01479 
01480                 break;
01481               
01482             case LSP_OP_SENDTO:
01483                 ProviderOverlapped->SendToArgs.dwBufferCount = dwBufferCount;
01484                 ProviderOverlapped->SendToArgs.lpBuffers = CopyWSABuf(
01485                         lpBuffers,
01486                         dwBufferCount,
01487                         lpErrno
01488                         );
01489                 if ( NULL == ProviderOverlapped->SendToArgs.lpBuffers )
01490                     goto cleanup;
01491 
01492                 break;
01493 
01494             default:
01495                 break;
01496         }
01497     }
01498 
01499     ret = NO_ERROR;
01500 
01501 cleanup:
01502 
01503     if ( SOCKET_ERROR == ret )
01504     {
01505         UndoOverlappedOperation( SocketContext, ProviderOverlapped );
01506         ProviderOverlapped = NULL;
01507     }
01508     else
01509     {
01510         ASSERT( NO_ERROR == ret );
01511     }
01512 
01513     return ProviderOverlapped;
01514 }

int QueueOverlappedOperation ( WSAOVERLAPPEDPLUS ol,
SOCK_INFO SocketContext 
)

Definition at line 344 of file overlap.cpp.

00348 {
00349     BOOL    bSynchronous = FALSE;
00350     int     err;
00351 
00352     //
00353     // Set the fields of the overlapped to indicate IO is not complete yet
00354     //
00355 
00356     __try
00357     {
00358         SetOverlappedInProgress( ol->lpCallerOverlapped );
00359     } 
00360     __except( EXCEPTION_EXECUTE_HANDLER )
00361     {
00362         return WSAEFAULT;
00363     }
00364 
00365     if ( NULL != gIocp )
00366     {
00367         //
00368         // If we haven't already added the provider socket to the IOCP then
00369         //  do it now.
00370         //
00371         AcquireSocketLock( SocketContext );
00372 
00373         if ( NULL == SocketContext->hIocp )
00374         {
00375             SocketContext->hIocp = CreateIoCompletionPort(
00376                     (HANDLE)ol->ProviderSocket,
00377                     gIocp,
00378                     ol->CallerSocket,
00379                     0
00380                     );
00381             if ( NULL == SocketContext->hIocp )
00382             {
00383                 if ( ERROR_INVALID_PARAMETER == (err = GetLastError() ) )
00384                 {
00385                     //
00386                     // If the socket option SO_SYNCHRONOUS_(NON)ALERT is set then 
00387                     // no overlapped operation can be performed on that socket and 
00388                     // tryiing to associate it with a completion port will fail. 
00389                     // The other bad news is that an LSP cannot trap this setsockopt 
00390                     // call. In reality we don't have to do anything. If an app sets 
00391                     // this option and then makes overlapped calls anyway, then they 
00392                     // shouldn't be expecting any overlapped notifications! This 
00393                     // statement is put here in case you want to mark the socket
00394                     // info structure as synchronous.
00395                     //
00396                     bSynchronous = TRUE;
00397                 }
00398                 else
00399                 {
00400                     dbgprint("QueueOverlappedOperation: CreateIoCompletionPort() "
00401                               "failed: %d (Prov %d Iocp 0x%x Caller 0x%x 0)", 
00402                             err, ol->ProviderSocket, 
00403                             gIocp, ol->CallerSocket);
00404                 }
00405             }
00406 
00407             dbgprint("Adding provider handle %X to IOCP", ol->ProviderSocket);
00408         }
00409 
00410         ReleaseSocketLock( SocketContext );
00411 
00412         //
00413         // Simply execute the operation
00414         //
00415         return ExecuteOverlappedOperation( ol, bSynchronous );
00416     }
00417     else
00418     {
00419         // Queue up the operation for the worker thread to initiate
00420         //
00421         return EnqueueOverlappedOperation( ol );
00422     }
00423 }

void SetOverlappedInProgress ( OVERLAPPED *  ol  ) 

Definition at line 1016 of file overlap.cpp.

01019 {
01020     ol->Internal = WSS_OPERATION_IN_PROGRESS;
01021     ol->InternalHigh = 0;
01022 }

int StopOverlappedManager (  ) 

Definition at line 238 of file overlap.cpp.

00240 {
00241     DWORD     i;
00242     int       ret = NO_ERROR;
00243 
00244     EnterCriticalSection( &gOverlappedCS );
00245 
00246     //
00247     // Post a completion packet to the IOCP (one for each thread)
00248     //
00249     if ( NULL != gIocp )
00250     {
00251         for(i=0; i < gThreadCount ;i++)
00252         {
00253             ret = PostQueuedCompletionStatus(
00254                     gIocp,
00255                     (DWORD)-1,
00256                     0,
00257                     NULL
00258                     );
00259             if ( 0 == ret )
00260             {
00261                 dbgprint("PostQueuedCompletionStatus() failed: %d", GetLastError());
00262             }
00263         }
00264 
00265         //
00266         // Wait a while for the threads to get the signal and exit - if it fails or
00267         // times out then oh well, we need to clean up anyway
00268         //
00269     }
00270     else
00271     {
00272         //
00273         // On Win9x we closed the semaphore so the worker thread should fail
00274         // when waiting for a signal and break out of the loop.
00275         // 
00276 
00277         LIST_ENTRY         *entry = NULL;
00278         WSAOVERLAPPEDPLUS  *olp = NULL;
00279 
00280         while ( !IsListEmpty( &gPendingOperations ) )
00281         {
00282             entry = RemoveHeadList( &gPendingOperations );
00283 
00284             olp = CONTAINING_RECORD( entry, WSAOVERLAPPEDPLUS, Link );
00285 
00286             FreeOverlappedStructure( olp );
00287         }
00288     }
00289 
00290     if ( NULL != gWorkerThread )
00291     {
00292         ret = WaitForMultipleObjectsEx( gThreadCount, gWorkerThread, TRUE, 5000, TRUE );
00293         if ( WAIT_TIMEOUT == ret )
00294             dbgprint("StopOverlappedManager: Timed out waiting for IOCP threads to exit!");
00295         else if ( WAIT_FAILED == ret )
00296             dbgprint("StopOverlappedManager: WaitForMultipleObjectsEx failed: %d",
00297                     GetLastError());
00298         else
00299             dbgprint("StopOverlappedManager: All worker threads stopped!");
00300 
00301         for(i=0; i < gThreadCount ;i++)
00302         {
00303             CloseHandle( gWorkerThread[ i ] );
00304             gWorkerThread[ i ] = NULL;
00305 
00306             dbgprint("Closing overlapped thread(s)");
00307         }
00308 
00309         LspFree( gWorkerThread );
00310         gWorkerThread = NULL;
00311     }
00312 
00313     //
00314     // Cleanup remaining handles...
00315     //
00316     if ( NULL != gIocp )
00317     {
00318         CloseHandle( gIocp );
00319         gIocp = NULL;
00320     }
00321 
00322     if ( NULL != gWakeupSemaphore )
00323     {
00324         CloseHandle( gWakeupSemaphore );
00325         gWakeupSemaphore = NULL;
00326     }
00327 
00328     LeaveCriticalSection( &gOverlappedCS );
00329 
00330     return ret;
00331 }

void UndoOverlappedOperation ( SOCK_INFO SocketContext,
WSAOVERLAPPEDPLUS ProviderOverlapped 
)

Definition at line 1525 of file overlap.cpp.

01529 {
01530     AcquireSocketLock( SocketContext );
01531     (SocketContext->dwOutstandingAsync)--;
01532     ReleaseSocketLock( SocketContext );
01533 
01534     FreeOverlappedStructure( ProviderOverlapped );
01535 }


Variable Documentation

HANDLE gIocp = NULL

Definition at line 47 of file overlap.cpp.

DWORD gThreadCount = (DWORD)-1

Definition at line 48 of file overlap.cpp.

HANDLE gWakeupSemaphore = NULL

Definition at line 46 of file overlap.cpp.

HANDLE* gWorkerThread = NULL

Definition at line 45 of file overlap.cpp.