home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / winnt / pop3 / threads.c < prev   
Encoding:
C/C++ Source or Header  |  1997-10-05  |  11.5 KB  |  401 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples.
  4. *       Copyright (C) 1992-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. //+---------------------------------------------------------------------------
  13. //
  14. //  File:       pop3.c
  15. //
  16. //  Contents:
  17. //
  18. //  Classes:
  19. //
  20. //  Functions:
  21. //
  22. //----------------------------------------------------------------------------
  23.  
  24. #include "pop3srvp.h"
  25. #pragma hdrstop
  26.  
  27. extern BOOL bServiceTerminating;
  28.  
  29. DWORD
  30. WINAPI
  31. WorkerThread (
  32.     LPVOID WorkContext
  33.     );
  34.  
  35.  
  36. HANDLE
  37. InitializeThreads (
  38.     VOID
  39.     )
  40.  
  41. /*++
  42.  
  43. Routine Description:
  44.  
  45.     Starts up the POP3SRV worker threads.  We use two worker threads
  46.     for eachprocessor on the system--this is choosen as a good balance
  47.     that ensures that there are a sufficient number of threads available
  48.     to get useful work done but not too many that context switches
  49.     consume significant overhead.
  50.  
  51. Arguments:
  52.  
  53.     None.
  54.  
  55. Return Value:
  56.  
  57.     HANDLE - A handle to the completion port if everything was 
  58.         successful, or NULL if there was a failure.  
  59.  
  60. --*/
  61.  
  62. {
  63.  
  64.     SOCKET s;
  65.     DWORD i;
  66.     HANDLE hCompletionPort;
  67.     HANDLE hThreadHandle;
  68.     DWORD dwThreadId;
  69.     SYSTEM_INFO systemInfo;
  70.  
  71.     //
  72.     // First open a temporary socket that we will use to create the
  73.     // completion port.  In NT 3.51 it will not be necessary to specify
  74.     // the FileHandle parameter of CreateIoCompletionPort()--it will
  75.     // be legal to specify FileHandle as NULL.  However, for NT 3.5
  76.     // we need an overlapped file handle.
  77.     //
  78.  
  79.     s = socket( AF_INET, SOCK_DGRAM, 0 );
  80.     if ( s == INVALID_SOCKET ) {
  81.         return NULL;
  82.     }
  83.  
  84.     //
  85.     // Create the completion port that will be used by all the worker
  86.     // threads.
  87.     //
  88.  
  89.     hCompletionPort = CreateIoCompletionPort( (HANDLE)s, NULL, 0, 0 );
  90.     if ( hCompletionPort == NULL ) {
  91.         closesocket( s );
  92.         return NULL;
  93.     }
  94.  
  95.     //
  96.     // Close the socket, we don't need it any longer.
  97.     //
  98.  
  99.     closesocket( s );
  100.  
  101.     //
  102.     // Determine how many processors are on the system.
  103.     //
  104.  
  105.     GetSystemInfo( &systemInfo );
  106.  
  107.     //
  108.     // Create worker threads that will service the actual overlapped
  109.     // I/O requests.  Create two worker threads for each processor
  110.     // on the system.
  111.     //
  112.  
  113.     for ( i = 0; i < systemInfo.dwNumberOfProcessors*2; i++ ) {
  114.  
  115.         hThreadHandle = CreateThread(
  116.                             NULL,
  117.                             0,
  118.                             WorkerThread,
  119.                             hCompletionPort,
  120.                             0,
  121.                             &dwThreadId
  122.                             );
  123.         if ( hThreadHandle == NULL ) {
  124.             CloseHandle( hCompletionPort );
  125.             return NULL;
  126.         }
  127.  
  128.         //
  129.         // Close each thread handle as we open them.  We do not need
  130.         // the thread handles.  Note that each thread will continue
  131.         // executing.
  132.         //
  133.  
  134.         CloseHandle( hThreadHandle );
  135.     }
  136.  
  137.     //
  138.     // All was successful.
  139.     //
  140.  
  141.     return hCompletionPort;
  142.  
  143. } // InitializeThreads
  144.  
  145.  
  146. DWORD
  147. WINAPI
  148. WorkerThread (
  149.     LPVOID WorkContext
  150.     )
  151.  
  152. /*++
  153.  
  154. Routine Description:
  155.  
  156.     This is the main worker routine for the POP3SRV worker threads.  
  157.     Worker threads wait on a completion port for I/O to complete.  When 
  158.     it completes, the worker thread processes the I/O, then either pends 
  159.     new I/O or closes the client's connection.  When the service shuts 
  160.     down, other code closes the completion port which causes 
  161.     GetQueuedCompletionStatus() to wake up and the worker thread then 
  162.     exits.  
  163.  
  164. Arguments:
  165.  
  166.     WorkContext - the completion port handle that will get I/O completion
  167.         notifications.
  168.  
  169. Return Value:
  170.  
  171.     DWORD - status of the thread.
  172.  
  173. --*/
  174.  
  175. {
  176.     HANDLE hCompletionPort = WorkContext;
  177.     BOOL bSuccess;
  178.     DWORD dwIoSize;
  179.     LPOVERLAPPED lpOverlapped;
  180.     PCLIENT_CONTEXT lpClientContext;
  181.     Pop3Disposition Disposition;
  182.     HANDLE hFile;
  183.     CHAR * OutputBuffer;
  184.     DWORD OutputBufferLen;
  185.     TRANSMIT_FILE_BUFFERS TranfileBuffers;
  186.  
  187.     //
  188.     // Loop servicing I/O completions.
  189.     //
  190.  
  191.     while ( TRUE ) {
  192.  
  193.         // --- DavidTr: Slide 14(b) ------------------------------------------
  194.         //
  195.         // Get a completed IO request.
  196.         //
  197.  
  198.         bSuccess = GetQueuedCompletionStatus(
  199.                        hCompletionPort,
  200.                        &dwIoSize,
  201.                        (LPDWORD)&lpClientContext,
  202.                        &lpOverlapped,
  203.                        (DWORD)-1
  204.                        );
  205.  
  206.         //
  207.         // If the service is terminating, exit this thread.
  208.         //
  209.  
  210.         if ( bServiceTerminating ) {
  211.             return 0;
  212.         }
  213.  
  214.         //
  215.         // If the IO failed, close the socket and free context.
  216.         //
  217.  
  218.         if ( !bSuccess ) {
  219.             CloseClient( lpClientContext, FALSE );
  220.             continue;
  221.         }
  222.  
  223.         //
  224.         // If the request was a read, process the client request.
  225.         //
  226.  
  227.         if ( lpClientContext->LastClientIo == ClientIoRead ) {
  228.  
  229.             //
  230.             // BUGBUG: if this were a real production piece of code,
  231.             // we would check here for an incomplete read.  Because
  232.             // TCP/IP is a stream oriented protocol, it is feasible
  233.             // that we could receive part of a client request.
  234.             // Therefore, we should check for the CRLF that ends a
  235.             // client request.
  236.             //
  237.  
  238.             //
  239.             // Process the request.  Pop3Dispatch() handles all aspects 
  240.             // of the request and tells us how to respond to the client.  
  241.             //
  242.  
  243.             Disposition = Pop3Dispatch(
  244.                               lpClientContext->Context,
  245.                               lpClientContext->Buffer,
  246.                               dwIoSize,
  247.                               &hFile,
  248.                               &OutputBuffer,
  249.                               &OutputBufferLen
  250.                               );
  251.  
  252.             //
  253.             // Act based on the Disposition.
  254.             //
  255.  
  256.             switch ( Disposition ) {
  257.  
  258.             case Pop3_Discard:
  259.                 break;
  260.  
  261.             case Pop3_SendError:
  262.             case Pop3_SendBuffer:
  263.  
  264.                 // --- DavidTr: Slide 7(a) -----------------------------------
  265.                 //
  266.                 // Set up context information and perform an overlapped 
  267.                 // write on the socket.  
  268.                 //
  269.  
  270.                 lpClientContext->LastClientIo = ClientIoWrite;
  271.                 lpClientContext->TransmittedBuffer = OutputBuffer;
  272.  
  273.                 bSuccess = WriteFile(
  274.                                (HANDLE)lpClientContext->Socket,
  275.                                OutputBuffer,
  276.                                OutputBufferLen,
  277.                                &dwIoSize,
  278.                                &lpClientContext->Overlapped
  279.                                );
  280.                 if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
  281.                     CloseClient( lpClientContext, FALSE );
  282.                     continue;
  283.                 }
  284.  
  285.                 //
  286.                 // Continue looping to get completed IO requests--we
  287.                 // do not want to pend another read now.
  288.                 //
  289.  
  290.                 continue;
  291.  
  292.             case Pop3_SendFile:
  293.             case Pop3_SendBufferThenFile:
  294.  
  295.                 //
  296.                 // Determine based on the disposition whether we will
  297.                 // need to send a head or tail buffer.
  298.                 //
  299.  
  300.                 if ( Disposition == Pop3_SendFile ) {
  301.                     TranfileBuffers.Head = NULL;
  302.                     TranfileBuffers.HeadLength = 0;
  303.                 } else if ( Disposition == Pop3_SendBufferThenFile ) {
  304.                     TranfileBuffers.Head = OutputBuffer;
  305.                     TranfileBuffers.HeadLength = OutputBufferLen;
  306.                 }
  307.  
  308.                 //
  309.                 // After the file, we're going to send a .CRLF sequence 
  310.                 // so that the client detects EOF.  Note that 
  311.                 // TransmitFile() will send this terminator in the same 
  312.                 // packet as the last chunk of the file, thereby saving 
  313.                 // network traffic.  
  314.                 //
  315.  
  316.                 TranfileBuffers.Tail = ".\r\n";
  317.                 TranfileBuffers.TailLength = 3;
  318.  
  319.                 //
  320.                 // Set up context for the I/O so that we know how to act 
  321.                 // when the I/O completes.  
  322.                 //
  323.  
  324.                 lpClientContext->LastClientIo = ClientIoTransmitFile;
  325.                 lpClientContext->TransmittedFile = hFile;
  326.                 lpClientContext->TransmittedBuffer = OutputBuffer;
  327.  
  328.                 // --- DavidTr: Slide 21 ---------------------------------
  329.                 //
  330.                 // Now transmit the file and the data buffers.
  331.                 //
  332.  
  333.                 bSuccess = TransmitFile(
  334.                                lpClientContext->Socket,
  335.                                hFile,
  336.                                0,
  337.                                0,
  338.                                &lpClientContext->Overlapped,
  339.                                &TranfileBuffers,
  340.                                0
  341.                                );
  342.                 if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
  343.                     CloseClient( lpClientContext, FALSE );
  344.                     continue;
  345.                 }
  346.  
  347.                 //
  348.                 // Continue looping to get completed IO requests--we
  349.                 // do not want to pend another read now.
  350.                 //
  351.  
  352.                 continue;
  353.             }
  354.  
  355.         } else if ( lpClientContext->LastClientIo == ClientIoWrite ) {
  356.  
  357.             //
  358.             // Clean up after the WriteFile().
  359.             //
  360.  
  361.             LocalFree( lpClientContext->TransmittedBuffer );
  362.  
  363.         } else if ( lpClientContext->LastClientIo == ClientIoTransmitFile ) {
  364.  
  365.             //
  366.             // Clean up after the TransmitFile().
  367.             //
  368.  
  369.             CloseHandle( lpClientContext->TransmittedFile );
  370.             LocalFree( lpClientContext->TransmittedBuffer );
  371.         } 
  372.  
  373.         // --- DavidTr: Slide 7(b) ---------------------------------------
  374.         //
  375.         // Pend another read request to get the next client request.
  376.         //
  377.  
  378.         lpClientContext->LastClientIo = ClientIoRead;
  379.         lpClientContext->BytesReadSoFar = 0;
  380.  
  381.         bSuccess = ReadFile(
  382.                        (HANDLE)lpClientContext->Socket,
  383.                        lpClientContext->Buffer,
  384.                        sizeof(lpClientContext->Buffer),
  385.                        &dwIoSize,
  386.                        &lpClientContext->Overlapped
  387.                        );
  388.         if ( !bSuccess && GetLastError( ) != ERROR_IO_PENDING ) {
  389.             CloseClient( lpClientContext, FALSE );
  390.             continue;
  391.         }
  392.  
  393.         //
  394.         // Loop around to get another completed IO request.
  395.         //
  396.     }
  397.  
  398.     return 0;
  399.  
  400. } // WorkThread
  401.