⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 overlap.cpp

📁 《Windows网络编程技术》附书源码源码. 运行环境:9x/Me/NT/2000/XP/ 源码语言:简体中文 第十四章
💻 CPP
字号:
// Module Name: overlapped.cpp
//
// Description:
//
//    This sample illustrates how to develop a layered service provider that is
//    capable of counting all bytes transmitted through a TCP/IP socket.
//
//    This file contains an overlapped I/O manager that supports the event
//    object I/O model, completion routine I/O model, and the I/O completion
//    port model that is used in winsock.
//    
//
// Compile:
//
//    This project is managed through the LSP.DSW project file.
//
// Execute:
//
//    This project produces a DLL named lsp.dll. This dll should be copied to the
//    %SystemRoot%\System32 directory. Once the file is in place you should execute
//    the application instlsp.exe to insert this provider in the Winsock 2 catalog
//    of service providers.
//
#include "provider.h"

#define POOLSIZE 64

typedef struct _WSAOVERLAPPEDPLUS
{
    WSAOVERLAPPED ProviderOverlapped;
    SOCKET CallerSocket;
    SOCKET ProviderSocket;
    LPWSAOVERLAPPED lpCallerOverlapped;
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCallerCompletionRoutine;
    LPWSATHREADID lpCallerThreadId;
    DWORD BytesTransferred;
    DWORD Flags;
    DWORD Error;
    DWORD *ByteCount;
    _WSAOVERLAPPEDPLUS *Next;
} WSAOVERLAPPEDPLUS, * LPWSAOVERLAPPEDPLUS;

LPWSAOVERLAPPEDPLUS PoolHead, PoolTail;
WSAOVERLAPPEDPLUS OverlappedPool[POOLSIZE];
HANDLE WorkerThread = NULL,
       WorkerMutex  = NULL;
WSAEVENT EventArray[POOLSIZE];
CRITICAL_SECTION gOverlappedCS;

DWORD WINAPI OverlappedManager(LPVOID lpParameter);
void CALLBACK IntermediateCompletionRoutine(DWORD dwContext);

static TCHAR Msg[512];

void InitOverlappedCS(void)
{
    InitializeCriticalSection(&gOverlappedCS);
}


LPWSAOVERLAPPED GetOverlappedStructure(SOCKET CallerSocket,
                                       SOCKET ProviderSocket,
                                       LPWSAOVERLAPPED lpCallerOverlapped,
                                       LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCallerCompletionRoutine, 
                                       LPWSATHREADID lpCallerThreadId,
                                       DWORD *ByteCount)
{
    LPWSAOVERLAPPEDPLUS lpWorkerOverlappedPlus;
    SOCK_INFO *SocketContext;
    INT Error;

    if (!WorkerThread)
    {
        int i;
        DWORD ThreadId;
        BOOL EventFailed = FALSE;

        EnterCriticalSection(&gOverlappedCS);

        if (!WorkerThread)
        {
            WorkerMutex = CreateMutex(NULL, FALSE, NULL);

            // Initialize the overlapped plus structure pool

            PoolHead = &OverlappedPool[0];

            for(i = 1; i < POOLSIZE; i++)
            {
                OverlappedPool[i - 1].Next = &OverlappedPool[i];
            }

            PoolTail = &OverlappedPool[POOLSIZE - 1];
            PoolTail->Next = NULL;

            // Setup event object handles for the pool
        
            for (i = 0; i < POOLSIZE; i++)
            {
                if ((EventArray[i] = OverlappedPool[i].ProviderOverlapped.hEvent = 
                    MainUpCallTable.lpWPUCreateEvent(&Error)) == NULL)
                    EventFailed = TRUE;
            }

            // Start a worker thread

            WorkerThread = CreateThread(NULL, 0, OverlappedManager, NULL, 0,
                &ThreadId);
        }

        LeaveCriticalSection(&gOverlappedCS);

        if (!WorkerThread || EventFailed)
            return NULL;
    }

    if (MainUpCallTable.lpWPUQuerySocketHandleContext(CallerSocket, (LPDWORD) &SocketContext, &Error) == SOCKET_ERROR)
        return NULL;

    // We have to keep track of the number of outstanding overlapped requests an application
    // has. Otherwise, if the app were to close a socket that had oustanding overlapped ops
    // remaining, we'd start leaking structures in OverlappedPool. The idea here is to force
    // the CallerSocket to remain open until the lower provider has processed all the 
    // overlapped requests. If we closed both the lower socket and the caller socket, we
    // would no longer be able to correlate completed requests to any apps sockets.

    (SocketContext->dwOutstandingAsync)++;

    // Get an Overlapped plus structure from the queue
    WaitForSingleObject(WorkerMutex, INFINITE);

    if (PoolHead)
    {
        lpWorkerOverlappedPlus = PoolHead;
        PoolHead = PoolHead->Next;
    }
    else // Empty pool
    {
        ReleaseMutex(WorkerMutex);
        return NULL;
    }
    ReleaseMutex(WorkerMutex);

    // Set callers overlapped status

    lpCallerOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
    lpCallerOverlapped->InternalHigh = 0;

    lpWorkerOverlappedPlus->CallerSocket = CallerSocket;
    lpWorkerOverlappedPlus->ProviderSocket = ProviderSocket;
    lpWorkerOverlappedPlus->lpCallerOverlapped = lpCallerOverlapped;
    lpWorkerOverlappedPlus->lpCallerCompletionRoutine = lpCallerCompletionRoutine;
    lpWorkerOverlappedPlus->lpCallerThreadId = lpCallerThreadId;
    lpWorkerOverlappedPlus->ByteCount = ByteCount;

    return(&(lpWorkerOverlappedPlus->ProviderOverlapped));
}

DWORD WINAPI OverlappedManager(LPVOID lpParameter)
{
    SOCK_INFO *SocketContext;
    DWORD Ret, Ret2;
    INT OverlappedResultError;
    INT Error;

    while((Ret = WaitForMultipleObjects(POOLSIZE, EventArray, FALSE,
            INFINITE)) != WAIT_FAILED)
    {
        if (Ret >= WAIT_OBJECT_0 && Ret <= (WAIT_OBJECT_0 + POOLSIZE - 1))
        {
            if (MainUpCallTable.lpWPUQuerySocketHandleContext(OverlappedPool[Ret - WAIT_OBJECT_0].CallerSocket,
                                                              (LPDWORD) &SocketContext, 
                                                              &Error) == SOCKET_ERROR)
                continue;

            // Reset event handle
            MainUpCallTable.lpWPUResetEvent(EventArray[Ret - WAIT_OBJECT_0], &Error);

            // Get Overlapped I/O results

            Ret2 = NextProcTable.lpWSPGetOverlappedResult(
                OverlappedPool[Ret - WAIT_OBJECT_0].ProviderSocket,
                &OverlappedPool[Ret - WAIT_OBJECT_0].ProviderOverlapped,
                &OverlappedPool[Ret - WAIT_OBJECT_0].BytesTransferred,
                TRUE,
                &OverlappedPool[Ret - WAIT_OBJECT_0].Flags,
                &OverlappedResultError);

            if (Ret2 != 0)
            {
                if (OverlappedPool[Ret - WAIT_OBJECT_0].ByteCount)
                {
                    *(OverlappedPool[Ret - WAIT_OBJECT_0].ByteCount) += 
                        OverlappedPool[Ret - WAIT_OBJECT_0].BytesTransferred;
                }
            }

            // When an I/O operation is complete, the provider sets OffsetHigh
            // to the Windows Sockets 2 error code resulting from the operation,
            // sets Offset to the flags resulting from the I/O operation, and
            // calls WPUCompleteOverlappedRequest, passing the transfer byte count
            // as one of the parameters. WPUCompleteOverlappedRequest eventually
            // sets InternalHigh to the transfer byte count, then sets Internal
            // to a value other than WSS_OPERATION_IN_PROGRESS.
            OverlappedPool[Ret - WAIT_OBJECT_0].lpCallerOverlapped->OffsetHigh =
                ((Ret2 == 0) ? WSAENOTSOCK : OverlappedResultError);

            OverlappedPool[Ret - WAIT_OBJECT_0].lpCallerOverlapped->Offset = 
                OverlappedPool[Ret - WAIT_OBJECT_0].Flags;    

            if (OverlappedPool[Ret - WAIT_OBJECT_0].lpCallerCompletionRoutine)
            {
                // Handle callers completion routine
                MainUpCallTable.lpWPUQueueApc(
                    OverlappedPool[Ret - WAIT_OBJECT_0].lpCallerThreadId,
                    IntermediateCompletionRoutine,
                    (DWORD) &OverlappedPool[Ret - WAIT_OBJECT_0],   
               	    &Error);
            }
            else
            {
                // Signal callers overlapped event handle
                WPUCompleteOverlappedRequest(
                    OverlappedPool[Ret - WAIT_OBJECT_0].CallerSocket,
                    OverlappedPool[Ret - WAIT_OBJECT_0].lpCallerOverlapped,
                    OverlappedResultError,                 
                    OverlappedPool[Ret - WAIT_OBJECT_0].BytesTransferred,             
                    &Error);
            }

            (SocketContext->dwOutstandingAsync)--;

            if ((SocketContext->bClosing) && (SocketContext->dwOutstandingAsync == 0))
            {
                RemoveSockInfo(SocketContext->ProviderSocket);

                if (MainUpCallTable.lpWPUCloseSocketHandle(OverlappedPool[Ret-WAIT_OBJECT_0].CallerSocket, &Error) == SOCKET_ERROR)
                    return SOCKET_ERROR;

                {
                    TCHAR buffer[128];
                    wsprintf(buffer, L"Closing socket %d Bytes Sent [%lu] Bytes Recv [%lu]\n", 
                        OverlappedPool[Ret-WAIT_OBJECT_0].CallerSocket,
                        SocketContext->BytesSent, SocketContext->BytesRecv);
                    OutputDebugString(buffer);
                }

                GlobalFree(SocketContext);
            }
            // Put Overlapped plus structure back in the pool

            WaitForSingleObject(WorkerMutex, INFINITE);
            PoolTail->Next = &OverlappedPool[Ret - WAIT_OBJECT_0];
            PoolTail = &OverlappedPool[Ret - WAIT_OBJECT_0];
            PoolTail->Next = NULL;
            ReleaseMutex(WorkerMutex);
        }
    }
    return 0;
}


void CALLBACK IntermediateCompletionRoutine(DWORD dwContext)
{
    LPWSAOVERLAPPEDPLUS olp = (LPWSAOVERLAPPEDPLUS) dwContext;

    olp->lpCallerCompletionRoutine(olp->Error, olp->BytesTransferred,
        olp->lpCallerOverlapped, olp->Flags);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -