select.c
上传用户:ruihaiyan
上传日期:2007-02-14
资源大小:1017k
文件大小:57k
源码类别:

网络编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 1992-1996 Microsoft Corporation
  3. Module Name:
  4.     select.c
  5. Abstract:
  6.     This module contains support for the select( ) and WSASelectWindow
  7.     WinSock APIs.
  8. Author:
  9.     David Treadwell (davidtr)    4-Apr-1992
  10. Revision History:
  11. --*/
  12. #include "winsockp.h"
  13. //
  14. // FD_SET uses the FD_SETSIZE macro, so define it to a huge value here so
  15. // that apps can pass a very large number of sockets to select(), which
  16. // uses the FD_SET macro.
  17. // Have to do this after precompiled include since it will be ignored
  18. // otherwise
  19. //
  20. #undef FD_SETSIZE
  21. #define FD_SETSIZE 65536
  22. #define HANDLES_IN_SET(set) ( (set) == NULL ? 0 : (set->fd_count & 0xFFFF) )
  23. #define IS_EVENT_ENABLED(event, socket)                     
  24.             ( (socket->DisabledAsyncSelectEvents & event) == 0 && 
  25.               (socket->AsyncSelectlEvent & event) != 0 )
  26. typedef struct _POLL_CONTEXT_BLOCK {
  27.     PSOCKET_INFORMATION SocketInfo;
  28.     DWORD AsyncSelectSerialNumber;
  29.     IO_STATUS_BLOCK IoStatus;
  30.     AFD_POLL_INFO PollInfo;
  31. } POLL_CONTEXT_BLOCK, *PPOLL_CONTEXT_BLOCK;
  32. BOOL
  33. SockCheckAndInitAsyncSelectHelper (
  34.     VOID
  35.     );
  36. VOID
  37. SockProcessAsyncSelect (
  38.     PSOCKET_INFORMATION Socket,
  39.     PPOLL_CONTEXT_BLOCK Context
  40.     );
  41. int
  42. WSPAPI
  43. WSPSelect (
  44.     int nfds,
  45.     fd_set *readfds,
  46.     fd_set *writefds,
  47.     fd_set *exceptfds,
  48.     const struct timeval *timeout,
  49.     LPINT lpErrno
  50.     )
  51. /*++
  52. Routine Description:
  53.     This function is used to determine the status of one or more
  54.     sockets.  For each socket, the caller may request information on
  55.     read, write or error status.  The set of sockets for which a given
  56.     status is requested is indicated by an fd_set structure.  Upon
  57.     return, the structure is updated to reflect the subset of these
  58.     sockets which meet the specified condition, and select() returns the
  59.     number of sockets meeting the conditions.  A set of macros is
  60.     provided for manipulating an fd_set.  These macros are compatible
  61.     with those used in the Berkeley software, but the underlying
  62.     representation is completely different.
  63.     The parameter readfds identifies those sockets which are to be
  64.     checked for readability.  If the socket is currently listen()ing, it
  65.     will be marked as readable if an incoming connection request has
  66.     been received, so that an accept() is guaranteed to complete without
  67.     blocking.  For other sockets, readability means that queued data is
  68.     available for reading, so that a recv() or recvfrom() is guaranteed
  69.     to complete without blocking.  The presence of out-of-band data will
  70.     be checked if the socket option SO_OOBINLINE has been enabled (see
  71.     setsockopt()).
  72.     The parameter writefds identifies those sockets which are to be
  73.     checked for writeability.  If a socket is connect()ing
  74.     (non-blocking), writeability means that the connection establishment
  75.     is complete.  For other sockets, writeability means that a send() or
  76.     sendto() will complete without blocking.  [It is not specified how
  77.     long this guarantee can be assumed to be valid, particularly in a
  78.     multithreaded environment.]
  79.     The parameter exceptfds identifies those sockets which are to be
  80.     checked for the presence of out- of-band data or any exceptional
  81.     error conditions.  Note that out-of-band data will only be reported
  82.     in this way if the option SO_OOBINLINE is FALSE.  For a SOCK_STREAM,
  83.     the breaking of the connection by the peer or due to KEEPALIVE
  84.     failure will be indicated as an exception.  This specification does
  85.     not define which other errors will be included.
  86.     Any of readfds, writefds, or exceptfds may be given as NULL if no
  87.     descriptors are of interest.
  88.     Four macros are defined in the header file winsock.h for
  89.     manipulating the descriptor sets.  The variable FD_SETSIZE
  90.     determines the maximum number of descriptors in a set.  (The default
  91.     value of FD_SETSIZE is 64, which may be modified by #defining
  92.     FD_SETSIZE to another value before #including winsock.h.)
  93.     Internally, an fd_set is represented as an array of SOCKETs; the
  94.     last valid entry is followed by an element set to INVALID_SOCKET.
  95.     The macros are:
  96.     FD_CLR(s, *set)     Removes the descriptor s from set.
  97.     FD_ISSET(s, *set)   Nonzero if s is a member of the set, zero otherwise.
  98.     FD_SET(s, *set)     Adds descriptor s to set.
  99.     FD_ZERO(*set)       Initializes the set to the NULL set.
  100.     The parameter timeout controls how long the select() may take to
  101.     complete.  If timeout is a null pointer, select() will block
  102.     indefinitely until at least one descriptor meets the specified
  103.     criteria.  Otherwise, timeout points to a struct timeval which
  104.     specifies the maximum time that select() should wait before
  105.     returning.  If the timeval is initialized to {0, 0}, select() will
  106.     return immediately; this is used to "poll" the state of the selected
  107.     sockets.
  108. Arguments:
  109.     nfds - This argument is ignored and included only for the sake of
  110.         compatibility.
  111.     readfds - A set of sockets to be checked for readability.
  112.     writefds - A set of sockets to be checked for writeability
  113.     exceptfds -  set of sockets to be checked for errors.
  114.     timeout   The maximum time for select() to wait, or NULL for blocking
  115.         operation.
  116. Return Value:
  117.     select() returns the total number of descriptors which are ready and
  118.     contained in the fd_set structures, or 0 if the time limit expired.
  119. --*/
  120. {
  121.     NTSTATUS status;
  122. PWINSOCK_TLS_DATA tlsData;
  123.     int err;
  124.     PAFD_POLL_INFO pollInfo;
  125.     ULONG pollBufferSize;
  126.     PAFD_POLL_HANDLE_INFO pollHandleInfo;
  127.     ULONG handleCount;
  128.     ULONG i;
  129.     IO_STATUS_BLOCK ioStatusBlock;
  130.     ULONG handlesReady;
  131.     UCHAR pollBuffer[MAX_FAST_AFD_POLL];
  132.     WS_ENTER( "WSPSelect", readfds, writefds, exceptfds, (PVOID)timeout );
  133.     WS_ASSERT( lpErrno != NULL );
  134.     err = SockEnterApi( &tlsData );
  135.     if( err != NO_ERROR ) {
  136.         WS_EXIT( "WSPSelect", SOCKET_ERROR, TRUE );
  137.         *lpErrno = err;
  138.         return SOCKET_ERROR;
  139.     }
  140.     //
  141.     // Set up locals so that we know how to clean up on exit.
  142.     //
  143.     pollInfo = NULL;
  144.     handlesReady = 0;
  145.     __try {
  146.         //
  147.         // Determine how many handles we're going to check so that we can
  148.         // allocate a buffer large enough to hold information about all of
  149.         // them.
  150.         //
  151.         handleCount = HANDLES_IN_SET( readfds ) +
  152.                       HANDLES_IN_SET( writefds ) +
  153.                       HANDLES_IN_SET( exceptfds );
  154.         //
  155.         // If there are no handles specified, just return.
  156.         //
  157.         if ( handleCount == 0 ) {
  158.             WS_EXIT( "WSPSelect", 0, FALSE );
  159.             return 0;
  160.         }
  161.         //
  162.         // Allocate space to hold the input buffer for the poll IOCTL.
  163.         //
  164.         pollBufferSize = sizeof(AFD_POLL_INFO) +
  165.                              handleCount * sizeof(AFD_POLL_HANDLE_INFO);
  166.         if( pollBufferSize <= sizeof(pollBuffer) ) {
  167.             pollInfo = (PVOID)pollBuffer;
  168.         } else {
  169.             pollInfo = ALLOCATE_HEAP( pollBufferSize );
  170.             if ( pollInfo == NULL ) {
  171.                 err = WSAENOBUFS;
  172.                 goto exit;
  173.             }
  174.         }
  175.         //
  176.         // Initialize the poll buffer.
  177.         //
  178.         pollInfo->NumberOfHandles = handleCount;
  179.         pollInfo->Unique = FALSE;
  180.         pollHandleInfo = pollInfo->Handles;
  181.         for ( i = 0; readfds != NULL && i < (readfds->fd_count & 0xFFFF); i++ ) {
  182.             //
  183.             // If the connection is disconnected, either abortively or
  184.             // orderly, then it is considered possible to read immediately
  185.             // on the socket, so include these events in addition to receive.
  186.             //
  187.             pollHandleInfo->Handle = (HANDLE)readfds->fd_array[i];
  188.             pollHandleInfo->PollEvents =
  189.                 AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ABORT;
  190.             pollHandleInfo++;
  191.         }
  192.         for ( i = 0; writefds != NULL && i < (writefds->fd_count & 0xFFFF); i++ ) {
  193.             pollHandleInfo->Handle = (HANDLE)writefds->fd_array[i];
  194.             pollHandleInfo->PollEvents = AFD_POLL_SEND;
  195.             pollHandleInfo++;
  196.         }
  197.         for ( i = 0; exceptfds != NULL && i < (exceptfds->fd_count & 0xFFFF); i++ ) {
  198.             pollHandleInfo->Handle = (HANDLE)exceptfds->fd_array[i];
  199.             pollHandleInfo->PollEvents =
  200.                 AFD_POLL_RECEIVE_EXPEDITED | AFD_POLL_CONNECT_FAIL;
  201.             pollHandleInfo++;
  202.         }
  203.         //
  204.         // If a timeout was specified, convert it to NT format.  Since it is
  205.         // a relative time, it must be negative.
  206.         //
  207.         if ( timeout != NULL ) {
  208.             LARGE_INTEGER microseconds;
  209.             pollInfo->Timeout = RtlEnlargedIntegerMultiply(
  210.                                     timeout->tv_sec,
  211.                                     -10*1000*1000
  212.                                     );
  213.             microseconds = RtlEnlargedIntegerMultiply( timeout->tv_usec, -10 );
  214.             pollInfo->Timeout.QuadPart =
  215.                 pollInfo->Timeout.QuadPart + microseconds.QuadPart;
  216.         } else {
  217.             //
  218.             // No timeout was specified, just set the timeout value
  219.             // to the largest possible value, in effect using an infinite
  220.             // timeout.
  221.             //
  222.             pollInfo->Timeout.LowPart = 0xFFFFFFFF;
  223.             pollInfo->Timeout.HighPart = 0x7FFFFFFF;
  224.         }
  225.     }
  226.     __except (SOCK_EXCEPTION_FILTER()) {
  227.         err = WSAEFAULT;
  228.         goto exit;
  229.     }
  230.     //
  231.     // Send the IOCTL to AFD.  AFD will complete the request as soon as
  232.     // one or more of the specified handles is ready for the specified
  233.     // operation.
  234.     //
  235.     // Just use the first handle as the handle for the request.  Any
  236.     // handle is fine; we just need a handle to AFD so that it gets to the
  237.     // driver.
  238.     //
  239.     // Note that the same buffer is used for both input and output.
  240.     // Since IOCTL_AFD_POLL is a method 0 (buffered) IOCTL, this
  241.     // shouldn't cause problems.
  242.     //
  243.     WS_ASSERT( (IOCTL_AFD_POLL & 0x03) == METHOD_BUFFERED );
  244.     status = NtDeviceIoControlFile(
  245.                  pollInfo->Handles[0].Handle,
  246.                  tlsData->EventHandle,
  247.                  NULL,                   // APC Routine
  248.                  NULL,                   // APC Context
  249.                  &ioStatusBlock,
  250.                  IOCTL_AFD_POLL,
  251.                  pollInfo,
  252.                  pollBufferSize,
  253.                  pollInfo,
  254.                  pollBufferSize
  255.                  );
  256.     if ( status == STATUS_PENDING ) {
  257.         SockWaitForSingleObject(
  258.             tlsData->EventHandle,
  259.             (SOCKET)pollInfo->Handles[0].Handle,
  260.             pollInfo->Timeout.QuadPart == 0 ?
  261.                 SOCK_NEVER_CALL_BLOCKING_HOOK :
  262.                 SOCK_ALWAYS_CALL_BLOCKING_HOOK,
  263.             SOCK_NO_TIMEOUT
  264.             );
  265.         status = ioStatusBlock.Status;
  266.     }
  267.     if ( !NT_SUCCESS(status) ) {
  268.         err = SockNtStatusToSocketError( status );
  269.         goto exit;
  270.     }
  271.     __try {
  272.         //
  273.         // Use the information provided by the driver to set up the fd_set
  274.         // structures to return to the caller.  First zero out the structures.
  275.         //
  276.         if ( readfds != NULL ) {
  277.             FD_ZERO( readfds );
  278.         }
  279.         if ( writefds != NULL ) {
  280.             FD_ZERO( writefds );
  281.         }
  282.         if ( exceptfds != NULL ) {
  283.             FD_ZERO( exceptfds );
  284.         }
  285.         //
  286.         // Walk the poll buffer returned by AFD, setting up the fd_set
  287.         // structures as we go.
  288.         //
  289.         pollHandleInfo = pollInfo->Handles;
  290.         for ( i = 0; i < pollInfo->NumberOfHandles; i++ ) {
  291.             WS_ASSERT( pollHandleInfo->PollEvents != 0 );
  292.             if ( (pollHandleInfo->PollEvents & AFD_POLL_RECEIVE) != 0 ) {
  293.                 WS_ASSERT( readfds != NULL );
  294.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, readfds ) ) {
  295.                     FD_SET( (SOCKET)pollHandleInfo->Handle, readfds );
  296.                     handlesReady++;
  297.                 }
  298.                 IF_DEBUG(SELECT) {
  299.                     WS_PRINT(( "WSPSelect handle %lx ready for reading.n",
  300.                                    pollHandleInfo->Handle ));
  301.                 }
  302.             }
  303.             if ( (pollHandleInfo->PollEvents & AFD_POLL_SEND) != 0 ) {
  304.                 WS_ASSERT( writefds != NULL );
  305.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, writefds ) ) {
  306.                     FD_SET( (SOCKET)pollHandleInfo->Handle, writefds );
  307.                     handlesReady++;
  308.                 }
  309.                 IF_DEBUG(SELECT) {
  310.                     WS_PRINT(( "WSPSelect handle %lx ready for writing.n",
  311.                                    pollHandleInfo->Handle ));
  312.                 }
  313.             }
  314.             if ( (pollHandleInfo->PollEvents & AFD_POLL_RECEIVE_EXPEDITED) != 0 ) {
  315.                 WS_ASSERT( exceptfds != NULL );
  316.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, exceptfds ) ) {
  317.                     FD_SET( (SOCKET)pollHandleInfo->Handle, exceptfds );
  318.                     handlesReady++;
  319.                 }
  320.                 IF_DEBUG(SELECT) {
  321.                     WS_PRINT(( "WSPSelect handle %lx ready for expedited reading.n",
  322.                                    pollHandleInfo->Handle ));
  323.                 }
  324.             }
  325.             if ( (pollHandleInfo->PollEvents & AFD_POLL_ACCEPT) != 0 ) {
  326.                 WS_ASSERT( readfds != NULL );
  327.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, readfds ) ) {
  328.                     FD_SET( (SOCKET)pollHandleInfo->Handle, readfds );
  329.                     handlesReady++;
  330.                 }
  331.                 IF_DEBUG(SELECT) {
  332.                     WS_PRINT(( "WSPSelect handle %lx ready for accept.n",
  333.                                    pollHandleInfo->Handle ));
  334.                 }
  335.             }
  336.             if ( (pollHandleInfo->PollEvents & AFD_POLL_CONNECT) != 0 ) {
  337.                 WS_ASSERT( NT_SUCCESS(pollHandleInfo->Status) );
  338.                 WS_ASSERT( writefds != NULL );
  339.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, writefds ) ) {
  340.                     FD_SET( (SOCKET)pollHandleInfo->Handle, writefds );
  341.                     handlesReady++;
  342.                 }
  343.                 IF_DEBUG(SELECT) {
  344.                     WS_PRINT(( "WSPSelect handle %lx completed connect, status %lxn",
  345.                                    pollHandleInfo->Handle, pollHandleInfo->Status ));
  346.                 }
  347.             }
  348.             if ( (pollHandleInfo->PollEvents & AFD_POLL_CONNECT_FAIL) != 0 ) {
  349.                 WS_ASSERT( !NT_SUCCESS(pollHandleInfo->Status) );
  350.                 WS_ASSERT( exceptfds != NULL );
  351.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, exceptfds ) ) {
  352.                     FD_SET( (SOCKET)pollHandleInfo->Handle, exceptfds );
  353.                     handlesReady++;
  354.                 }
  355.                 IF_DEBUG(SELECT) {
  356.                     WS_PRINT(( "WSPSelect handle %lx completed connect, status %lxn",
  357.                                    pollHandleInfo->Handle, pollHandleInfo->Status ));
  358.                 }
  359.             }
  360.             if ( (pollHandleInfo->PollEvents & AFD_POLL_DISCONNECT) != 0 ) {
  361.                 WS_ASSERT( readfds != NULL );
  362.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, readfds ) ) {
  363.                     FD_SET( (SOCKET)pollHandleInfo->Handle, readfds );
  364.                     handlesReady++;
  365.                 }
  366.                 IF_DEBUG(SELECT) {
  367.                     WS_PRINT(( "WSPSelect handle %lx disconnected.n",
  368.                                    pollHandleInfo->Handle ));
  369.                 }
  370.             }
  371.             if ( (pollHandleInfo->PollEvents & AFD_POLL_ABORT) != 0 ) {
  372.                 WS_ASSERT( readfds != NULL );
  373.                 if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, readfds ) ) {
  374.                     FD_SET( (SOCKET)pollHandleInfo->Handle, readfds );
  375.                     handlesReady++;
  376.                 }
  377.                 IF_DEBUG(SELECT) {
  378.                     WS_PRINT(( "WSPSelect handle %lx aborted.n",
  379.                                    pollHandleInfo->Handle ));
  380.                 }
  381.             }
  382.             if ( (pollHandleInfo->PollEvents & AFD_POLL_LOCAL_CLOSE) != 0 ) {
  383.                 //
  384.                 // If the app does a closesocket() on a handle that has a
  385.                 // select() outstanding on it, this event may get set by
  386.                 // AFD even though we didn't request notification of it.
  387.                 // If exceptfds is NULL, then this is an error condition.
  388.                 //
  389.                 if ( readfds == NULL ) {
  390.                     handlesReady = 0;
  391.                     err = WSAENOTSOCK;
  392.                     goto exit;
  393.                 } else {
  394.                     if ( !FD_ISSET( (SOCKET)pollHandleInfo->Handle, readfds ) ) {
  395.                         FD_SET( (SOCKET)pollHandleInfo->Handle, readfds );
  396.                         handlesReady++;
  397.                     }
  398.                 }
  399.                 IF_DEBUG(SELECT) {
  400.                     WS_PRINT(( "WSPSelect handle %lx closed locally.n",
  401.                                    pollHandleInfo->Handle ));
  402.                 }
  403.             }
  404.             pollHandleInfo++;
  405.         }
  406.     }
  407.     __except (SOCK_EXCEPTION_FILTER()) {
  408.         err = WSAEFAULT;
  409.         goto exit;
  410.     }
  411. exit:
  412.     IF_DEBUG(SELECT) {
  413.         if ( err != NO_ERROR ) {
  414.             WS_PRINT(( "WSPSelect failed: %ld.n", err ));
  415.         } else {
  416.             WS_PRINT(( "WSPSelect succeeded, %ld readfds, %ld writefds, "
  417.                        "%ld exceptfdsn",
  418.                            HANDLES_IN_SET( readfds ),
  419.                            HANDLES_IN_SET( writefds ),
  420.                            HANDLES_IN_SET( exceptfds ) ));
  421.         }
  422.     }
  423.     if ( pollInfo != NULL && pollInfo != (PVOID)pollBuffer ) {
  424.         FREE_HEAP( pollInfo );
  425.     }
  426.     if ( err != NO_ERROR ) {
  427.         WS_EXIT( "WSPSelect", SOCKET_ERROR, TRUE );
  428.         *lpErrno = err;
  429.         return SOCKET_ERROR;
  430.     }
  431.     WS_ASSERT( (ULONG)handlesReady == (ULONG)(HANDLES_IN_SET( readfds ) +
  432.                                               HANDLES_IN_SET( writefds ) +
  433.                                               HANDLES_IN_SET( exceptfds )) );
  434.     WS_EXIT( "WSPSelect", handlesReady, FALSE );
  435.     return handlesReady;
  436. }   // WSPSelect
  437. int
  438. WSPAPI
  439. WSPAsyncSelect (
  440.     SOCKET Handle,
  441.     HWND hWnd,
  442.     unsigned int wMsg,
  443.     long lEvent,
  444.     LPINT lpErrno
  445.     )
  446. /*++
  447. Routine Description:
  448.     This function is used to request that the Windows Sockets DLL should
  449.     send a message to the window hWnd whenever it detects any of the
  450.     network events specified by the lEvent parameter.  The message which
  451.     should be sent is specified by the wMsg parameter.  The socket for
  452.     which notification is required is identified by s.
  453.     The lEvent parameter is constructed by or'ing any of the values
  454.     specified in the following list:
  455.          Value       Meaning
  456.          FD_READ     Want to receive notification of readiness for reading.
  457.          FD_WRITE    Want to receive notification of readiness for writing.
  458.          FD_OOB      Want to receive notification of the arrival of
  459.                      out-of-band data.
  460.          FD_ACCEPT   Want to receive notification of incoming connections.
  461.          FD_CONNECT  Want to receive notification of completed connection.
  462.          FD_CLOSE    Want to receive notification of socket closure.
  463.     Issuing a WSAAsyncSelect() for a socket cancels any previous
  464.     WSAAsyncSelect() for the same socket.  For example, to receive
  465.     notification for both reading and writing, the application must call
  466.     WSAAsyncSelect() with both FD_READ and FD_WRITE, as follows:
  467.         rc = WSAAsyncSelect(s, hWnd, wMsg, FD_READ | FD_WRITE);
  468.     It is not possible to specify different messages for different
  469.     events.  The following code will not work; the second call will
  470.     cancel the effects of the first, and only FD_WRITE events will be
  471.     reported with message wMsg2:
  472.     rc = WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);
  473.     rc = WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);
  474.     To cancel all notification i.e., to indicate that the Windows
  475.     Sockets implementation should send no further messages related to
  476.     network events on the socket lEvent should be set to zero.
  477.     rc = WSAAsyncSelect(s, hWnd, 0, 0);
  478.     Although the WSAAsyncSelect() takes effect immediately, it is
  479.     possible that messages may be waiting in the application's message
  480.     queue.  The application must therefore be prepared to receive
  481.     network event messages even after cancellation.
  482.     This function automatically sets socket s to non-blocking mode.
  483.     When one of the nominated network events occurs on the specified
  484.     socket s, the application's window hWnd receives message wMsg.  The
  485.     wParam argument identifies the socket on which a network event has
  486.     occurred.  The low word of lParam specifies the network event that
  487.     has occurred.  The high word of lParam contains any error code.  The
  488.     error code be any error as defined in winsock.h.
  489.     The error and event codes may be extracted from the lParam using the
  490.     macros WSAGETSELECTERROR and WSAGETSELECTEVENT, defined in winsock.h
  491.     as:
  492.     #define WSAGETSELECTERROR(lParam) HIWORD(lParam)
  493.     #define WSAGETSELECTEVENT(lParam) LOWORD(lParam)
  494.     The use of these macros will maximize the portability of the source
  495.     code for the application.
  496.     The possible network event codes which may be returned are as
  497.     follows:
  498.          Value       Meaning
  499.          FD_READ     Socket s ready for reading.
  500.          FD_WRITE    Socket s ready for writing.
  501.          FD_OOB      Out-of-band data ready for reading on socket s.
  502.          FD_ACCEPT   Socket s ready for accepting a new incoming connection.
  503.          FD_CONNECT  Connection on socket s completed.
  504.          FD_CLOSE    Connection identified by socket s has been closed.
  505. Arguments:
  506.     s - A descriptor identifying the socket for which event notification
  507.         is required.
  508.     hWnd - A handle identifying the window which should receive a
  509.         message when a network event occurs.
  510.     wMsg - The message to be received when a network event occurs.
  511.     lEvent - A bitmask which specifies a combination of network events
  512.         in which the application is interested.
  513. Return Value:
  514.     The return value is 0 if the application's declaration of interest
  515.     in the network event set was successful.  Otherwise the value
  516.     SOCKET_ERROR is returned, and a specific error number may be
  517.     retrieved by calling WSAGetLastError().
  518. --*/
  519. {
  520. PWINSOCK_TLS_DATA tlsData;
  521.     PSOCKET_INFORMATION socket;
  522.     int err;
  523.     PPOLL_CONTEXT_BLOCK context;
  524.     NTSTATUS    status;
  525.     BOOLEAN nonBlocking;
  526.     WS_ENTER( "WSPAsyncSelect", (PVOID)Handle, (PVOID)hWnd, (PVOID)wMsg, (PVOID)lEvent );
  527.     WS_ASSERT( lpErrno != NULL );
  528.     err = SockEnterApi( &tlsData );
  529.     if( err != NO_ERROR ) {
  530.         WS_EXIT( "WSPSelect", SOCKET_ERROR, TRUE );
  531.         *lpErrno = err;
  532.         return SOCKET_ERROR;
  533.     }
  534.     //
  535.     // Initialize locals so that we know how to clean up on exit.
  536.     //
  537.     socket = NULL;
  538.     context = NULL;
  539.     //
  540.     // Check that the hWnd passed in is a valid Windows handle.
  541.     //
  542.     if ( !IsWindow( hWnd ) ) {
  543.         err = WSAEINVAL;
  544.         goto errorexit;
  545.     }
  546.     //
  547.     // Make sure that only valid bits are specified in lEvent.
  548.     //
  549.     // !!! should we also make sure that the bits make sense for the
  550.     //     state of the socket, i.e. don't allow FD_ACCEPT on a
  551.     //     connected socket?
  552.     //
  553.     if ( (lEvent & ~FD_ALL_EVENTS) != 0 ) {
  554.         err = WSAEINVAL;
  555.         goto errorexit;
  556.     }
  557.     //
  558.     // Find a pointer to the socket structure corresponding to the
  559.     // passed-in handle.
  560.     //
  561.     socket = SockFindAndReferenceSocket( Handle, TRUE );
  562.     if ( socket == NULL ) {
  563.         err = WSAENOTSOCK;
  564.         goto errorexit;
  565.     }
  566.     //
  567.     // Allocate space to hold the poll context block.
  568.     //
  569.     context = ALLOCATE_HEAP( sizeof(POLL_CONTEXT_BLOCK) );
  570.     if ( context == NULL ) {
  571.         err = WSAENOBUFS;
  572.         goto errorexit;
  573.     }
  574.     //
  575.     // Set the socket to nonblocking.
  576.     //
  577.     nonBlocking = TRUE;
  578.     err = SockSetInformation(
  579.                 socket,
  580.                 AFD_NONBLOCKING_MODE,
  581.                 &nonBlocking,
  582.                 NULL,
  583.                 NULL
  584.                 );
  585.     if ( err != NO_ERROR ) {
  586.         goto errorexit;
  587.     }
  588.     socket->NonBlocking = TRUE;
  589.     //
  590.     // If there's a WSPEventSelect active on this socket, deactivate it.
  591.     //
  592.     if( socket->EventSelectlNetworkEvents ) {
  593.         err = SockEventSelectHelper(
  594.                   socket,
  595.                   NULL,
  596.                   0
  597.                   );
  598.         if( err != NO_ERROR ) {
  599.             goto errorexit;
  600.         }
  601.     }
  602.     //
  603.     // Initialize the async thread if it hasn't already been started.
  604.     //
  605.     if ( !SockCheckAndReferenceAsyncThread( ) ) {
  606.         err = WSAENOBUFS;
  607.         goto errorexit;
  608.     }
  609.     if (!SockCheckAndInitAsyncSelectHelper ()) {
  610.         SockDereferenceAsyncThread ();
  611.         err = WSAENOBUFS;
  612.         goto errorexit;
  613.     }
  614.     //
  615.     // Acquire the lock that protects this socket.  We hold this lock
  616.     // throughout this routine to synchronize against other callers
  617.     // performing operations on the socket we're using.
  618.     //
  619.     SockAcquireSocketLockExclusive( socket );
  620.     //
  621.     // Store the specified window handle, message, and event mask in
  622.     // the socket information structure.
  623.     //
  624.     socket->AsyncSelecthWnd = hWnd;
  625.     socket->AsyncSelectwMsg = wMsg;
  626.     socket->AsyncSelectlEvent = lEvent;
  627.     socket->DisabledAsyncSelectEvents = 0;
  628.     //
  629.     // If the socket is not connected and is not a datagram socket,
  630.     // disable FD_WRITE events.  We'll reenable them when the socket
  631.     // becomes connected.  Disabling them here prevents a race condition
  632.     // between FD_WRITE events and FD_CONNECT events, and we don't want
  633.     // FD_WRITE events to be posted before FD_CONNECT.
  634.     //
  635.     if ( !SockIsSocketConnected( socket ) &&
  636.              !IS_DGRAM_SOCK(socket) ) {
  637.         socket->DisabledAsyncSelectEvents |= FD_WRITE;
  638.     }
  639.     //
  640.     // Bump the async select serial number on this socket.  This field
  641.     // allows us to stop sending a particular message as soon as
  642.     // WSPAsyncSelect is called to change the settings on the socket.
  643.     // When an AFD poll completes for an async select, if the serial
  644.     // number has changed then no message is sent.
  645.     //
  646.     socket->AsyncSelectSerialNumber++;
  647.     //
  648.     // If there are no events that we can poll on, just return.  When a
  649.     // reenabling function or WSPAsyncSelect is called a new request
  650.     // will be queued to the async thread, and a new poll will be initiated.
  651.     //
  652.     if ( (socket->AsyncSelectlEvent &
  653.                        (~socket->DisabledAsyncSelectEvents)) == 0 ) {
  654.         SockReleaseSocketLock (socket);
  655.         SockDereferenceAsyncThread ();
  656.         SockDereferenceSocket( socket );
  657.         FREE_HEAP (context);
  658.         IF_DEBUG(ASYNC_SELECT) {
  659.             WS_PRINT(( "WSPAsyncSelect: no events to poll on, "
  660.                        "socket = %lx, lEvent = %lx, disabled = %lxn",
  661.                            socket, socket->AsyncSelectlEvent,
  662.                            socket->DisabledAsyncSelectEvents ));
  663.         }
  664.         WS_EXIT( "WSPAsyncSelect", NO_ERROR, FALSE );
  665.         return NO_ERROR;
  666.     }
  667.     //
  668.     // Initialize unchanging part of the context
  669.     // Store referenced pointer to socket info structure, so we can
  670.     // safely access it when poll completes even if socket is closed.
  671.     // This reference will be released when we free the context.
  672.     //
  673.     context->SocketInfo = socket;
  674.     context->AsyncSelectSerialNumber = socket->AsyncSelectSerialNumber;
  675.     SockReleaseSocketLock( socket );
  676. //
  677. // Start async select in the context of our thread.
  678. // Some of the applications tend to exit the thread in which async select
  679. // was started killing the poll IRP.  Because we are not that much concerned with
  680. // performance in async select, we'd rather take a hit here than trying to pick up
  681. // and repost the IRP in our own thread when it gets cancelled.
  682. //
  683.     status = NtSetIoCompletion (SockAsyncQueuePort,
  684.                         (PVOID)&SockProcessQueuedAsyncSelect,
  685.                         context,
  686.                         0,
  687.                         0
  688.                         );
  689.     if (!NT_SUCCESS (status)) {
  690.         SockDereferenceAsyncThread ();
  691.         err = SockNtStatusToSocketError (status);
  692.         goto errorexit;
  693.     }
  694.     IF_DEBUG(ASYNC_SELECT) {
  695.         WS_PRINT(( "WSPAsyncSelect successfully posted request, "
  696.                    "socket = %lxn", socket ));
  697.     }
  698.     WS_EXIT( "WSPAsyncSelect", NO_ERROR, FALSE );
  699.     return NO_ERROR;
  700. errorexit:
  701.     if ( socket != NULL ) {
  702.         SockDereferenceSocket( socket );
  703.     }
  704.     if (context!=NULL) {
  705.         FREE_HEAP (context);
  706.     }
  707.     IF_DEBUG(ASYNC_SELECT) {
  708.         WS_PRINT(( "WSPAsyncSelect failed: %ldn", err ));
  709.     }
  710.     WS_EXIT( "WSPAsyncSelect", SOCKET_ERROR, TRUE );
  711.     *lpErrno = err;
  712.     return SOCKET_ERROR;
  713. } // WSPAsyncSelect
  714. VOID
  715. SockProcessAsyncSelect (
  716.     PSOCKET_INFORMATION Socket,
  717.     PPOLL_CONTEXT_BLOCK Context
  718.     )
  719. {
  720.     ULONG eventsToPoll;
  721.     NTSTATUS status;
  722.     //
  723.     // Initialize the context and poll buffer.  Use an infinite timeout
  724.     // and just the one socket handle.  Also, this should be a unique
  725.     // poll, so if another unique poll is outstanding on this socket
  726.     // it will be canceleld.
  727.     //
  728.     Context->PollInfo.Timeout.HighPart = 0x7FFFFFFF;
  729.     Context->PollInfo.Timeout.LowPart = 0xFFFFFFFF;
  730.     Context->PollInfo.NumberOfHandles = 1;
  731.     Context->PollInfo.Unique = TRUE;
  732.     Context->PollInfo.Handles[0].Handle = Socket->HContext.Handle;
  733.     Context->PollInfo.Handles[0].PollEvents = 0;
  734.     //
  735.     // Determine which events we want to poll.
  736.     //
  737.     eventsToPoll = Socket->AsyncSelectlEvent &
  738.                        (~Socket->DisabledAsyncSelectEvents);
  739.     WS_ASSERT (eventsToPoll!=0);
  740.     //
  741.     // Set up the events to poll on.  Note that we don't put down
  742.     // AFD_POLL_CONNECT or AFD_POLL_CONNECT_FAIL requests even if
  743.     // FD_CONNECT is specified-- this event is handled manually by the
  744.     // connect() routine because of it's inherently different semantics.
  745.     //
  746.     if ( (eventsToPoll & FD_READ) != 0) {
  747.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_RECEIVE;
  748.     }
  749.     if ( (eventsToPoll & FD_WRITE) != 0) {
  750.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_SEND;
  751.     }
  752.     if ( (eventsToPoll & FD_OOB) != 0 ) {
  753.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_RECEIVE_EXPEDITED;
  754.     }
  755.     if ( (eventsToPoll & FD_ACCEPT) != 0 ) {
  756.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_ACCEPT;
  757.     }
  758.     if ( (eventsToPoll & FD_CLOSE) != 0) {
  759.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_DISCONNECT |
  760.                                                    AFD_POLL_ABORT |
  761.                                                    AFD_POLL_LOCAL_CLOSE;
  762.     }
  763.     if ( (eventsToPoll & FD_QOS) != 0) {
  764.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_QOS;
  765.     }
  766.     if ( (eventsToPoll & FD_GROUP_QOS) != 0) {
  767.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_GROUP_QOS;
  768.     }
  769. #ifdef _PNP_POWER_
  770.     if ( (eventsToPoll & FD_ROUTING_INTERFACE_CHANGE) != 0 ) {
  771.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_ROUTING_IF_CHANGE;
  772.     }
  773.     if ( (eventsToPoll & FD_ADDRESS_LIST_CHANGE) != 0 ) {
  774.         Context->PollInfo.Handles[0].PollEvents |= AFD_POLL_ADDRESS_LIST_CHANGE;
  775.     }
  776. #endif // _PNP_POWER_
  777.     IF_DEBUG(ASYNC_SELECT) {
  778.         WS_PRINT(( "SockProcessAsyncSelect: socket = %lx, handle = %lx, "
  779.                    "lEvent = %lx, disabled = %lx, actual = %lxn",
  780.                        Socket, Socket->HContext.Handle, Socket->AsyncSelectlEvent,
  781.                        Socket->DisabledAsyncSelectEvents, eventsToPoll ));
  782.     }
  783.     //
  784.     // Start the actual poll.
  785.     //
  786.     WS_ASSERT( (IOCTL_AFD_POLL & 0x03) == METHOD_BUFFERED );
  787.     status = NtDeviceIoControlFile(
  788.                  SockAsyncSelectHelperHandle,
  789.                  NULL,                      // Event
  790.                  NULL,                      // APC
  791.                  Context,
  792.                  &Context->IoStatus,
  793.                  IOCTL_AFD_POLL,
  794.                  &Context->PollInfo,
  795.                  sizeof(Context->PollInfo),
  796.                  &Context->PollInfo,
  797.                  sizeof(Context->PollInfo)
  798.                  );
  799.     if ( NT_ERROR(status) ) {
  800.         //
  801.         // If the request failed, call the completion routine since
  802.         // the system didn't complete it.
  803.         //
  804.         Context->IoStatus.Status = status;
  805.         SockAsyncSelectCompletion( Context, &Context->IoStatus);
  806.     }
  807.     return;
  808. } // SockProcessAsyncSelect
  809. VOID
  810. SockProcessQueuedAsyncSelect (
  811.     IN PVOID ApcContext,
  812.     IN PIO_STATUS_BLOCK IoStatusBlock
  813.     )
  814. {
  815.     PPOLL_CONTEXT_BLOCK context = ApcContext;
  816.     PSOCKET_INFORMATION socket = context->SocketInfo;
  817.     //
  818.     // Acquire the socket's lock to keep it's state constant while
  819.     // we do the message posts.
  820.     //
  821.     SockAcquireSocketLockExclusive( socket );
  822.     //
  823.     // If the socket has been closed, just return.
  824.     //
  825.     if ( socket->State == SocketStateClosing ) {
  826.         IF_DEBUG(ASYNC_SELECT) {
  827.             WS_PRINT(( "SockProcessQueuedAsyncSelect: tossing request on handle %lx"
  828.                        "--closedn",
  829.                            socket->HContext.Handle));
  830.         }
  831.         SockReleaseSocketLock( socket );
  832.         goto exit;
  833.     }
  834.     //
  835.     // If the serial number on the socket has changed since this request
  836.     // was initialized, or if the original socket was closed, just bag
  837.     // this notification.  Another poll request should be on the way if the
  838.     // socket is still open.
  839.     //
  840.     if ( context->AsyncSelectSerialNumber != socket->AsyncSelectSerialNumber ){
  841.         IF_DEBUG(ASYNC_SELECT) {
  842.             WS_PRINT(( "SockProcessQueuedAsyncSelect: tossing req on handle %lx, "
  843.                        " ASN %ld req ASN %ldn",
  844.                            socket->HContext.Handle,
  845.                            socket->AsyncSelectSerialNumber,
  846.                            context->AsyncSelectSerialNumber ));
  847.         }
  848.         SockReleaseSocketLock( socket );
  849.         goto exit;
  850.     }
  851.     //
  852.     // If there are no events that we can poll on, just return.  When a
  853.     // reenabling function or WSPAsyncSelect is called a new request
  854.     // will be queued to the async thread, and a new poll will be initiated.
  855.     //
  856.     if ( (socket->AsyncSelectlEvent &
  857.                        (~socket->DisabledAsyncSelectEvents)) == 0 ) {
  858.         IF_DEBUG(ASYNC_SELECT) {
  859.             WS_PRINT(( "SockProcessQueuedAsyncSelect: no events to poll on, "
  860.                        "socket = %lx, lEvent = %lx, disabled = %lxn",
  861.                            socket, socket->AsyncSelectlEvent,
  862.                            socket->DisabledAsyncSelectEvents ));
  863.         }
  864.         SockReleaseSocketLock( socket );
  865.         goto exit;
  866.     }
  867.     //
  868.     // Start another poll.
  869.     //
  870.     SockProcessAsyncSelect(
  871.         socket,
  872.         context
  873.         );
  874.     SockReleaseSocketLock( socket );
  875.     return;
  876. exit:
  877.     SockDereferenceSocket( socket );
  878.     FREE_HEAP( context );
  879.     SockDereferenceAsyncThread ();
  880. return;
  881. }
  882. VOID
  883. SockAsyncSelectCompletion (
  884.     IN PVOID ApcContext,
  885.     IN PIO_STATUS_BLOCK IoStatusBlock
  886.     )
  887. {
  888.     PPOLL_CONTEXT_BLOCK context = ApcContext;
  889.     PSOCKET_INFORMATION socket = context->SocketInfo;
  890.     BOOL posted = FALSE;
  891.     ULONG error;
  892.     DWORD pollEvents;
  893.     IF_DEBUG(ASYNC_SELECT) {
  894.         WS_PRINT(( "AsyncSelectCompletionApc: socket %lx (h:%lx), status %lx, "
  895.                    "poll events %lxn" ,
  896.                    context->SocketInfo,
  897.                    socket->HContext.Handle,
  898.                    IoStatusBlock->Status,
  899.                    context->PollInfo.Handles[0].PollEvents ));
  900.     }
  901.     //
  902.     // Acquire the socket's lock to keep it's state constant while
  903.     // we do the message posts.
  904.     //
  905.     SockAcquireSocketLockExclusive( socket );
  906.     //
  907.     // If the socket has been closed, just return.
  908.     //
  909.     if ( IoStatusBlock->Status == STATUS_CANCELLED || socket->State == SocketStateClosing ) {
  910.         IF_DEBUG(ASYNC_SELECT) {
  911.             WS_PRINT(( "AsyncSelectCompletionApc: tossing request on handle %lx"
  912.                        "--%s.n",
  913.                            socket->HContext.Handle,
  914.    (socket->State == SocketStateClosing) ? "closed" : "cancelled"));
  915.         }
  916.         SockReleaseSocketLock( socket );
  917.         goto exit;
  918.     }
  919.     //
  920.     // If the serial number on the socket has changed since this request
  921.     // was initialized, or if the original socket was closed, just bag
  922.     // this notification.  Another poll request should be on the way if the
  923.     // socket is still open.
  924.     //
  925.     if ( context->AsyncSelectSerialNumber != socket->AsyncSelectSerialNumber ){
  926.         IF_DEBUG(ASYNC_SELECT) {
  927.             WS_PRINT(( "AsyncSelectCompletionApc: tossing req on handle %lx, "
  928.                        " ASN %ld req ASN %ldn",
  929.                            socket->HContext.Handle,
  930.                            socket->AsyncSelectSerialNumber,
  931.                            context->AsyncSelectSerialNumber ));
  932.         }
  933.         SockReleaseSocketLock( socket );
  934.         goto exit;
  935.     }
  936.     //
  937.     // If the request failed, post a message indicating the failure.
  938.     //
  939.     if ( !NT_SUCCESS(IoStatusBlock->Status) ) {
  940.         ULONG error = SockNtStatusToSocketError( IoStatusBlock->Status );
  941.         posted = (SockUpcallTable->lpWPUPostMessage)(
  942.                      socket->AsyncSelecthWnd,
  943.                      socket->AsyncSelectwMsg,
  944.                      (WPARAM)socket->Handle,
  945.                      WSAMAKESELECTREPLY( 0, error )
  946.                      );
  947.         //WS_ASSERT( posted );
  948.         IF_DEBUG(POST) {
  949.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  950.                            socket->AsyncSelectwMsg,
  951.                            socket->AsyncSelecthWnd,
  952.                            socket->Handle, "0", error ));
  953.         }
  954.         SockReleaseSocketLock( socket );
  955.         goto exit;
  956.     }
  957.     //
  958.     // We should never get AFD_POLL_CONNECT or AFD_POLL_CONNECT_FAIL
  959.     // events, since we never ask for them.  FD_CONNECT is handled
  960.     // manually by the connect() routine.
  961.     //
  962.     pollEvents = context->PollInfo.Handles[0].PollEvents;
  963.     WS_ASSERT( (pollEvents & AFD_POLL_CONNECT) == 0 );
  964.     WS_ASSERT( (pollEvents & AFD_POLL_CONNECT_FAIL) == 0 );
  965.     //
  966.     // Post messages based on the event(s) that occurred.
  967.     //
  968.     if ( IS_EVENT_ENABLED( FD_READ, socket ) &&
  969.              (pollEvents & AFD_POLL_RECEIVE) != 0 ) {
  970.         posted = (SockUpcallTable->lpWPUPostMessage)(
  971.                      socket->AsyncSelecthWnd,
  972.                      socket->AsyncSelectwMsg,
  973.                      (WPARAM)socket->Handle,
  974.                      WSAMAKESELECTREPLY( FD_READ, 0 )
  975.                      );
  976.         //WS_ASSERT( posted );
  977.         IF_DEBUG(POST) {
  978.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  979.                            socket->AsyncSelectwMsg,
  980.                            socket->AsyncSelecthWnd,
  981.                            socket->Handle, "FD_READ", 0 ));
  982.         }
  983.         //
  984.         // Disable this event.  It will be reenabled when the app does a
  985.         // recv().
  986.         //
  987.         socket->DisabledAsyncSelectEvents |= FD_READ;
  988.     }
  989.     if ( IS_EVENT_ENABLED( FD_OOB, socket ) &&
  990.              (pollEvents & AFD_POLL_RECEIVE_EXPEDITED) != 0 ) {
  991.         posted = (SockUpcallTable->lpWPUPostMessage)(
  992.                      socket->AsyncSelecthWnd,
  993.                      socket->AsyncSelectwMsg,
  994.                      (WPARAM)socket->Handle,
  995.                      WSAMAKESELECTREPLY( FD_OOB, 0 )
  996.                      );
  997.         //WS_ASSERT( posted );
  998.         IF_DEBUG(POST) {
  999.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1000.                            socket->AsyncSelectwMsg,
  1001.                            socket->AsyncSelecthWnd,
  1002.                            socket->Handle, "FD_OOB", 0 ));
  1003.         }
  1004.         //
  1005.         // Disable this event.  It will be reenabled when the app does a
  1006.         // recv( MSG_OOB ).
  1007.         //
  1008.         // !!! need synchronization?
  1009.         //
  1010.         socket->DisabledAsyncSelectEvents |= FD_OOB;
  1011.     }
  1012.     if ( IS_EVENT_ENABLED( FD_WRITE, socket ) &&
  1013.              (pollEvents & AFD_POLL_SEND) != 0 ) {
  1014.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1015.                      socket->AsyncSelecthWnd,
  1016.                      socket->AsyncSelectwMsg,
  1017.                      (WPARAM)socket->Handle,
  1018.                      WSAMAKESELECTREPLY( FD_WRITE, 0 )
  1019.                      );
  1020.         //WS_ASSERT( posted );
  1021.         IF_DEBUG(POST) {
  1022.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1023.                            socket->AsyncSelectwMsg,
  1024.                            socket->AsyncSelecthWnd,
  1025.                            socket->Handle, "FD_WRITE", 0 ));
  1026.         }
  1027.         //
  1028.         // Disable this event.  It will be reenabled when the app does a
  1029.         // send().
  1030.         //
  1031.         socket->DisabledAsyncSelectEvents |= FD_WRITE;
  1032.     }
  1033.     if ( IS_EVENT_ENABLED( FD_ACCEPT, socket ) &&
  1034.              (pollEvents & AFD_POLL_ACCEPT) != 0 ) {
  1035.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1036.                      socket->AsyncSelecthWnd,
  1037.                      socket->AsyncSelectwMsg,
  1038.                      (WPARAM)socket->Handle,
  1039.                      WSAMAKESELECTREPLY( FD_ACCEPT, 0 )
  1040.                      );
  1041.         //WS_ASSERT( posted );
  1042.         IF_DEBUG(POST) {
  1043.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1044.                            socket->AsyncSelectwMsg,
  1045.                            socket->AsyncSelecthWnd,
  1046.                            socket->Handle, "FD_ACCEPT", 0 ));
  1047.         }
  1048.         //
  1049.         // Disable this event.  It will be reenabled when the app does an
  1050.         // accept().
  1051.         //
  1052.         socket->DisabledAsyncSelectEvents |= FD_ACCEPT;
  1053.     }
  1054.     if ( IS_EVENT_ENABLED( FD_CLOSE, socket ) &&
  1055.          ((pollEvents & AFD_POLL_DISCONNECT) != 0 ||
  1056.           (pollEvents & AFD_POLL_ABORT) != 0 ||
  1057.           (pollEvents & AFD_POLL_LOCAL_CLOSE) != 0) ) {
  1058.         if ( (pollEvents & AFD_POLL_ABORT) != 0 ) {
  1059.             error = WSAECONNABORTED;
  1060.         } else {
  1061.             error = NO_ERROR;
  1062.         }
  1063.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1064.                      socket->AsyncSelecthWnd,
  1065.                      socket->AsyncSelectwMsg,
  1066.                      (WPARAM)socket->Handle,
  1067.                      WSAMAKESELECTREPLY( FD_CLOSE, error )
  1068.                      );
  1069.         //WS_ASSERT( posted );
  1070.         IF_DEBUG(POST) {
  1071.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1072.                            socket->AsyncSelectwMsg,
  1073.                            socket->AsyncSelecthWnd,
  1074.                            socket->Handle, "FD_CLOSE", 0 ));
  1075.         }
  1076.         //
  1077.         // Disable this event.  It will never be reenabled.
  1078.         //
  1079.         socket->DisabledAsyncSelectEvents |= FD_CLOSE;
  1080.     }
  1081.     if ( IS_EVENT_ENABLED( FD_QOS, socket ) &&
  1082.              (pollEvents & AFD_POLL_QOS) != 0 ) {
  1083.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1084.                      socket->AsyncSelecthWnd,
  1085.                      socket->AsyncSelectwMsg,
  1086.                      (WPARAM)socket->Handle,
  1087.                      WSAMAKESELECTREPLY( FD_QOS, 0 )
  1088.                      );
  1089.         //WS_ASSERT( posted );
  1090.         IF_DEBUG(POST) {
  1091.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1092.                            socket->AsyncSelectwMsg,
  1093.                            socket->AsyncSelecthWnd,
  1094.                            socket->Handle, "FD_QOS", 0 ));
  1095.         }
  1096.         //
  1097.         // Disable this event.  It will be reenabled when the app does an
  1098.         // WSAIoctl (SIO_GET_QOS).
  1099.         //
  1100.         socket->DisabledAsyncSelectEvents |= FD_QOS;
  1101.     }
  1102.     if ( IS_EVENT_ENABLED( FD_GROUP_QOS, socket ) &&
  1103.              (pollEvents & AFD_POLL_GROUP_QOS) != 0 ) {
  1104.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1105.                      socket->AsyncSelecthWnd,
  1106.                      socket->AsyncSelectwMsg,
  1107.                      (WPARAM)socket->Handle,
  1108.                      WSAMAKESELECTREPLY( FD_GROUP_QOS, 0 )
  1109.                      );
  1110.         //WS_ASSERT( posted );
  1111.         IF_DEBUG(POST) {
  1112.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1113.                            socket->AsyncSelectwMsg,
  1114.                            socket->AsyncSelecthWnd,
  1115.                            socket->Handle, "FD_GROUP_QOS", 0 ));
  1116.         }
  1117.         //
  1118.         // Disable this event.  It will be reenabled when the app does an
  1119.         // WSAIoctl (SIO_GET_GROUP_QOS).
  1120.         //
  1121.         socket->DisabledAsyncSelectEvents |= FD_GROUP_QOS;
  1122.     }
  1123. #ifdef _PNP_POWER_
  1124.     if ( IS_EVENT_ENABLED( FD_ROUTING_INTERFACE_CHANGE, socket ) &&
  1125.              (pollEvents & AFD_POLL_ROUTING_IF_CHANGE) != 0 ) {
  1126.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1127.                      socket->AsyncSelecthWnd,
  1128.                      socket->AsyncSelectwMsg,
  1129.                      (WPARAM)socket->Handle,
  1130.                      WSAMAKESELECTREPLY( FD_ROUTING_INTERFACE_CHANGE, 0 )
  1131.                      );
  1132.         //WS_ASSERT( posted );
  1133.         IF_DEBUG(POST) {
  1134.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1135.                            socket->AsyncSelectwMsg,
  1136.                            socket->AsyncSelecthWnd,
  1137.                            socket->Handle, "FD_ROUTING_INTERFACE_CHANGE", 0 ));
  1138.         }
  1139.         //
  1140.         // Don't need to disable this event.  It will not occur until application does
  1141.         // WSAIoctl (SIO_ROUTING_INTERFACE_CHANGE).
  1142.         //
  1143.         // socket->DisabledAsyncSelectEvents |= FD_ROUTING_INTERFACE_CHANGE;
  1144.     }
  1145.     if ( IS_EVENT_ENABLED( FD_ADDRESS_LIST_CHANGE, socket ) &&
  1146.              (pollEvents & AFD_POLL_ADDRESS_LIST_CHANGE) != 0 ) {
  1147.         posted = (SockUpcallTable->lpWPUPostMessage)(
  1148.                      socket->AsyncSelecthWnd,
  1149.                      socket->AsyncSelectwMsg,
  1150.                      (WPARAM)socket->Handle,
  1151.                      WSAMAKESELECTREPLY( FD_ADDRESS_LIST_CHANGE, 0 )
  1152.                      );
  1153.         //WS_ASSERT( posted );
  1154.         IF_DEBUG(POST) {
  1155.             WS_PRINT(( "POSTED wMsg %lx hWnd %lx socket %lx event %s err %ldn",
  1156.                            socket->AsyncSelectwMsg,
  1157.                            socket->AsyncSelecthWnd,
  1158.                            socket->Handle, "FD_ADDRESS_LIST_CHANGE", 0 ));
  1159.         }
  1160.         //
  1161.         // Don't need to disable this event.  It will not occur until application does
  1162.         // WSAIoctl (SIO_ADDRESS_LIST_CHANGE).
  1163.         //
  1164.         // socket->DisabledAsyncSelectEvents |= FD_ADDRESS_LIST_CHANGE;
  1165.     }
  1166. #endif // _PNP_POWER_
  1167.     //
  1168.     // If there are no events that we can poll on, just return.  When a
  1169.     // reenabling function or WSPAsyncSelect is called a new request
  1170.     // will be queued to the async thread, and a new poll will be initiated.
  1171.     //
  1172.     if ( (socket->AsyncSelectlEvent &
  1173.                        (~socket->DisabledAsyncSelectEvents)) == 0 ) {
  1174.         IF_DEBUG(ASYNC_SELECT) {
  1175.             WS_PRINT(( "SockAsyncSelectCompletion: no events to poll on, "
  1176.                        "socket = %lx, lEvent = %lx, disabled = %lxn",
  1177.                            socket, socket->AsyncSelectlEvent,
  1178.                            socket->DisabledAsyncSelectEvents ));
  1179.         }
  1180.         SockReleaseSocketLock( socket );
  1181.         goto exit;
  1182.     }
  1183.     //
  1184.     // Start another poll.
  1185.     //
  1186.     SockProcessAsyncSelect(
  1187.         socket,
  1188.         context
  1189.         );
  1190.     SockReleaseSocketLock( socket );
  1191.     return;
  1192. exit:
  1193.     SockDereferenceSocket( socket );
  1194.     FREE_HEAP( context );
  1195.     SockDereferenceAsyncThread ();
  1196. return;
  1197. } // AsyncSelectCompletionApc
  1198. VOID
  1199. SockReenableAsyncSelectEvent (
  1200.     IN PSOCKET_INFORMATION Socket,
  1201.     IN ULONG Event
  1202.     )
  1203. {
  1204.     PPOLL_CONTEXT_BLOCK context;
  1205.     NTSTATUS    status;
  1206.     //
  1207.     // Note: caller must have acquired socket lock prior to calling this func
  1208.     //
  1209.     //
  1210.     // Check whether the specified event is in the list of disabled
  1211.     // async select events for the socket.  If it isn't, we don't
  1212.     // need to do anything.
  1213.     //
  1214.     if ( (Socket->DisabledAsyncSelectEvents & Event) == 0 ) {
  1215.         return;
  1216.     }
  1217.     //
  1218.     // If the socket is closing, don't reenable the select event.
  1219.     //
  1220.     if ( Socket->State == SocketStateClosing ) {
  1221.         return;
  1222.     }
  1223.     IF_DEBUG(ASYNC_SELECT) {
  1224.         WS_PRINT(( "SockReenableSelectEvent: reenabling event %lx for socket "
  1225.                    "%lx (%lx)n", Event, Socket->HContext.Handle, Socket ));
  1226.     }
  1227.     //
  1228.     // The specified event is currently disabled.
  1229.     //
  1230.     // *** Note that it is assumed that the socket lock is held on entry
  1231.     //     to this routine!
  1232.     //
  1233.     //
  1234.     // Reset the bit for this event so that it is no longer disabled.
  1235.     //
  1236.     Socket->DisabledAsyncSelectEvents &= ~Event;
  1237.     //
  1238.     // If there are no events that we can poll on, just return.  When a
  1239.     // reenabling function or WSPAsyncSelect is called a new request
  1240.     // will be queued to the async thread, and a new poll will be initiated.
  1241.     //
  1242.     if ( (Socket->AsyncSelectlEvent &
  1243.                        (~Socket->DisabledAsyncSelectEvents)) == 0 ) {
  1244.         IF_DEBUG(ASYNC_SELECT) {
  1245.             WS_PRINT(( "SockReenableAsyncSelectEvent: no events to poll on, "
  1246.                        "socket = %lx, lEvent = %lx, disabled = %lxn",
  1247.                            Socket, Socket->AsyncSelectlEvent,
  1248.                            Socket->DisabledAsyncSelectEvents ));
  1249.         }
  1250.         return;
  1251.     }
  1252.     //
  1253.     // Allocate space to hold the poll context block.
  1254.     //
  1255.     context = ALLOCATE_HEAP( sizeof(POLL_CONTEXT_BLOCK) );
  1256.     if ( context == NULL ) {
  1257.         //
  1258.         // BUGBUG Need to report error.
  1259.         //
  1260.         return ;
  1261.     }
  1262.     if (!SockCheckAndReferenceAsyncThread ()) {
  1263.         //
  1264.         // BUGBUG Need to report error.
  1265.         //
  1266.         FREE_HEAP (context);
  1267.         return;
  1268.     }
  1269.     //
  1270.     // Initialize unchanging part of the context
  1271.     // Store referenced pointer to socket info structure, so we can
  1272.     // safely access it when poll completes even if socket is closed.
  1273.     // This reference will be released when we free the context.
  1274.     //
  1275.     SockReferenceSocket(Socket);
  1276.     context->SocketInfo = Socket;
  1277.     //
  1278.     // We need to bump the number, so that if there is outstaning async
  1279.     // select on the socket it will go away
  1280.     //
  1281.     Socket->AsyncSelectSerialNumber += 1;
  1282.     context->AsyncSelectSerialNumber = Socket->AsyncSelectSerialNumber;
  1283. //
  1284. // Start async select in the context of our thread.
  1285. // Some of the applications tend to exit the thread in which async select
  1286. // was started killing the poll IRP.  Because we are not that much concerned with
  1287. // performance in async select, we'd rather take a hit here than trying to pick up
  1288. // and repost the IRP in our own thread when it gets cancelled
  1289. //
  1290.     status = NtSetIoCompletion (SockAsyncQueuePort,
  1291.                         (PVOID)&SockProcessQueuedAsyncSelect,
  1292.                         context,
  1293.                         0,
  1294.                         0
  1295.                         );
  1296.     if (!NT_SUCCESS (status)) {
  1297.         //
  1298.         // BUGBUG Need to report error.
  1299.         //
  1300.         FREE_HEAP (context);
  1301.     }
  1302.     return;
  1303. } // SockReenableAsyncSelectEvent
  1304. BOOL
  1305. SockCheckAndInitAsyncSelectHelper (
  1306.     VOID
  1307.     ) {
  1308.     HANDLE  Handle;
  1309.     UNICODE_STRING afdName;
  1310.     OBJECT_ATTRIBUTES objectAttributes;
  1311.     IO_STATUS_BLOCK ioStatusBlock;
  1312.     FILE_COMPLETION_INFORMATION completionInfo;
  1313.     OBJECT_HANDLE_FLAG_INFORMATION HandleInfo;
  1314.     NTSTATUS status;
  1315.     //
  1316.     // If the async select helper handle is already initialized, return.
  1317.     //
  1318.     if (SockAsyncSelectHelperHandle!=NULL)
  1319.         return TRUE;
  1320.     //
  1321.     // Acquire the global lock to synchronize the creation of the handle.
  1322.     //
  1323. SockAcquireRwLockExclusive (&SocketGlobalLock);
  1324.     // Check again, in case another thread has already initialized
  1325.     // the async helper handle.
  1326.     //
  1327.     if (SockAsyncSelectHelperHandle!=NULL) {
  1328.      SockReleaseRwLockExclusive (&SocketGlobalLock);
  1329.         return TRUE;
  1330.     }
  1331.     //
  1332.     // Set up to open a handle to AFD.
  1333.     //
  1334.     RtlInitUnicodeString( &afdName, L"\Device\Afd\AsyncSelectHlp" );
  1335.     InitializeObjectAttributes(
  1336.         &objectAttributes,
  1337.         &afdName,
  1338.         OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
  1339.         NULL,
  1340.         NULL
  1341.         );
  1342.     //
  1343.     // Open a handle to AFD.
  1344.     //
  1345.     status = NtCreateFile(
  1346.                  (PHANDLE)&Handle,
  1347.                  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1348.                  &objectAttributes,
  1349.                  &ioStatusBlock,
  1350.                  NULL,                                     // AllocationSize
  1351.                  0L,                                       // FileAttributes
  1352.                  FILE_SHARE_READ | FILE_SHARE_WRITE,       // ShareAccess
  1353.                  FILE_OPEN_IF,                             // CreateDisposition
  1354.                  0,                                        // CreateOptions
  1355.                  NULL,                                     // EaBuffer
  1356.                  0                                         // EaBufferLength
  1357.                  );
  1358.     if ( !NT_SUCCESS(status) ) {
  1359.         WS_PRINT(( "SockCheckAndInitAsyncSelectHelper: NtCreateFile(helper) failed: %Xn",
  1360.                        status ));
  1361.         SockReleaseRwLockExclusive (&SocketGlobalLock);
  1362.         return FALSE;
  1363.     }
  1364.     completionInfo.Port = SockAsyncQueuePort;
  1365.     completionInfo.Key = SockAsyncSelectCompletion;
  1366.     status = NtSetInformationFile (
  1367.                 Handle,
  1368.                 &ioStatusBlock,
  1369.                 &completionInfo,
  1370.                 sizeof (completionInfo),
  1371.                 FileCompletionInformation);
  1372.     if (!NT_SUCCESS (status)) {
  1373.         WS_PRINT(( "SockCheckAndInitAsyncSelectHelper: NtSeInformationFile(completion) failed: %Xn",
  1374.                        status ));
  1375.         NtClose (Handle);
  1376.     SockReleaseRwLockExclusive (&SocketGlobalLock);
  1377.         return FALSE;
  1378.     }
  1379.     //
  1380.     // Protect our handle from being closed by random NtClose call
  1381.     // by some messed up dll or application
  1382.     //
  1383.     HandleInfo.ProtectFromClose = TRUE;
  1384.     HandleInfo.Inherit = FALSE;
  1385.     status = NtSetInformationObject( Handle,
  1386.                     ObjectHandleFlagInformation,
  1387.                     &HandleInfo,
  1388.                     sizeof( HandleInfo )
  1389.                   );
  1390.     //
  1391.     // This shouldn't fail
  1392.     //
  1393.     WS_ASSERT (NT_SUCCESS (status));
  1394.     SockAsyncSelectHelperHandle = Handle;
  1395.     //
  1396.     // Remember that WSAAsyncSelect has been called in this process.
  1397.     // We'll use this information in the send and receive routines to
  1398.     // know if and when to attempt to reenable async select events.
  1399.     //
  1400.     SockAsyncSelectCalled = TRUE;
  1401. SockReleaseRwLockExclusive (&SocketGlobalLock);
  1402.     return TRUE;
  1403. }
  1404. int PASCAL FAR
  1405. __WSAFDIsSet (
  1406.     SOCKET fd,
  1407.     fd_set FAR *set
  1408.     )
  1409. /*++
  1410. Routine Description:
  1411.     This routine is used by the FD_ISSET macro; applications should
  1412.     not call it directly.  It determines whether a socket handle is
  1413.     included in an fd_set structure.
  1414. Arguments:
  1415.     fd - The socket handle to look for.
  1416.     set - The fd_set structure to examine.
  1417. Return Value:
  1418.     TRUE if the socket handle is in the set, FALSE if it is not.
  1419. --*/
  1420. {
  1421.     int i = (set->fd_count & 0xFFFF);
  1422.     while (i--) {
  1423.         if (set->fd_array[i] == fd) {
  1424.             return 1;
  1425.         }
  1426.     }
  1427.     return 0;
  1428. }   // __WSAFDIsSet