Annotation of q_a/samples/ddk/wshsmple/wshsmple.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1992 Microsoft Corporation
                      4: 
                      5: Module Name:
                      6: 
                      7:     WshTcpip.c
                      8: 
                      9: Abstract:
                     10: 
                     11:     This module contains necessary routines for the TCP/IP Windows Sockets
                     12:     Helper DLL.  This DLL provides the transport-specific support necessary
                     13:     for the Windows Sockets DLL to use TCP/IP as a transport.
                     14: 
                     15: Author:
                     16: 
                     17:     David Treadwell     19-Jul-1992
                     18: 
                     19: Revision History:
                     20: 
                     21:        Converted to use Win32 APIs.
                     22: 
                     23: --*/
                     24: 
                     25: #include <windows.h>
                     26: #include <winerror.h>
                     27: #include <winioctl.h>
                     28: 
                     29: #include <assert.h>
                     30: #include <wchar.h>
                     31: 
                     32: typedef LONG NTSTATUS;
                     33: /*lint -e624 */  // Don't complain about different typedefs.   // winnt
                     34: typedef NTSTATUS *PNTSTATUS;
                     35: /*lint +e624 */  // Resume checking for different typedefs.    // winnt
                     36: 
                     37: #include <tdi.h>
                     38: 
                     39: #include <winsock.h>
                     40: 
                     41: typedef struct _UNICODE_STRING {
                     42:     USHORT Length;
                     43:     USHORT MaximumLength;
                     44: #ifdef MIDL_PASS
                     45:     [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
                     46: #else // MIDL_PASS
                     47:     PWSTR  Buffer;
                     48: #endif // MIDL_PASS
                     49: } UNICODE_STRING;
                     50: typedef UNICODE_STRING *PUNICODE_STRING;
                     51: #define UNICODE_NULL ((WCHAR)0) // winnt
                     52: 
                     53: #define RtlInitUnicodeString(s, b) \
                     54:     do \
                     55:     { \
                     56:        PUNICODE_STRING string = (s); \
                     57:        PWSTR   buffer = (b); \
                     58:        int     length = 2 * wcslen(buffer); \
                     59:  \
                     60:        string->Length = length; \
                     61:        string->MaximumLength = length; \
                     62:        string->Buffer = buffer; \
                     63:     } \
                     64:     while ( 0 );
                     65: 
                     66: #include <wsahelp.h>
                     67: 
                     68: #include <sys\snet\stcp_opt.h>
                     69: 
                     70: //
                     71: // Structure and variables to define the triples supported by TCP/IP. The
                     72: // first entry of each array is considered the canonical triple for
                     73: // that socket type; the other entries are synonyms for the first.
                     74: //
                     75: 
                     76: typedef struct _MAPPING_TRIPLE {
                     77:     INT AddressFamily;
                     78:     INT SocketType;
                     79:     INT Protocol;
                     80: } MAPPING_TRIPLE, *PMAPPING_TRIPLE;
                     81: 
                     82: MAPPING_TRIPLE TcpMappingTriples[] = { AF_INET,   SOCK_STREAM, IPPROTO_TCP,
                     83:                                       AF_INET,   SOCK_STREAM, 0,
                     84:                                       AF_INET,   0,           IPPROTO_TCP,
                     85:                                       AF_UNSPEC, 0,           IPPROTO_TCP,
                     86:                                       AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP };
                     87: 
                     88: MAPPING_TRIPLE UdpMappingTriples[] = { AF_INET,   SOCK_DGRAM,  IPPROTO_UDP,
                     89:                                       AF_INET,   SOCK_DGRAM,  0,
                     90:                                       AF_INET,   0,           IPPROTO_UDP,
                     91:                                       AF_UNSPEC, 0,           IPPROTO_UDP,
                     92:                                       AF_UNSPEC, SOCK_DGRAM,  IPPROTO_UDP };
                     93: 
                     94: //
                     95: // Forward declarations of internal routines.
                     96: //
                     97: 
                     98: VOID
                     99: WINAPI
                    100: CompleteTdiActionApc (
                    101:     DWORD dwErrorCode,
                    102:     DWORD dwNumberOfBytesTransfered,
                    103:     LPOVERLAPPED lpOverlapped
                    104:     );
                    105: 
                    106: INT
                    107: DoTdiAction (
                    108:     IN HANDLE TdiConnectionObjectHandle,
                    109:     IN INT OptionLevel,
                    110:     IN INT OptionName,
                    111:     IN INT OptionalData
                    112:     );
                    113: 
                    114: BOOLEAN
                    115: IsTripleInList (
                    116:     IN PMAPPING_TRIPLE List,
                    117:     IN ULONG ListLength,
                    118:     IN INT AddressFamily,
                    119:     IN INT SocketType,
                    120:     IN INT Protocol
                    121:     );
                    122: 
                    123: //
                    124: // The socket context structure for this DLL.  Each open TCP/IP socket
                    125: // will have one of these context structures, which is used to maintain
                    126: // information about the socket.
                    127: //
                    128: 
                    129: typedef struct _WSHTCPIP_SOCKET_CONTEXT {
                    130:     INT AddressFamily;
                    131:     INT SocketType;
                    132:     INT Protocol;
                    133:     INT ReceiveBufferSize;
                    134:     BOOLEAN KeepAlive;
                    135:     BOOLEAN DontRoute;
                    136:     BOOLEAN NoDelay;
                    137: } WSHTCPIP_SOCKET_CONTEXT, *PWSHTCPIP_SOCKET_CONTEXT;
                    138: 
                    139: #define DEFAULT_RECEIVE_BUFFER_SIZE 8192
                    140: 
                    141: 
                    142: INT
                    143: WINAPI
                    144: WSHGetSockaddrType (
                    145:     IN PSOCKADDR Sockaddr,
                    146:     IN DWORD SockaddrLength,
                    147:     OUT PSOCKADDR_INFO SockaddrInfo
                    148:     )
                    149: 
                    150: /*++
                    151: 
                    152: Routine Description:
                    153: 
                    154:     This routine parses a sockaddr to determine the type of the
                    155:     machine address and endpoint address portions of the sockaddr.
                    156:     This is called by the winsock DLL whenever it needs to interpret
                    157:     a sockaddr.
                    158: 
                    159: Arguments:
                    160: 
                    161:     Sockaddr - a pointer to the sockaddr structure to evaluate.
                    162: 
                    163:     SockaddrLength - the number of bytes in the sockaddr structure.
                    164: 
                    165:     SockaddrInfo - a pointer to a structure that will receive information
                    166:        about the specified sockaddr.
                    167: 
                    168: 
                    169: Return Value:
                    170: 
                    171:     INT - a winsock error code indicating the status of the operation, or
                    172:        NO_ERROR if the operation succeeded.
                    173: 
                    174: --*/
                    175: 
                    176: {
                    177:     UNALIGNED SOCKADDR_IN *sockaddr = (PSOCKADDR_IN)Sockaddr;
                    178:     ULONG i;
                    179: 
                    180:     //
                    181:     // Make sure that the address family is correct.
                    182:     //
                    183: 
                    184:     if ( sockaddr->sin_family != AF_INET ) {
                    185:        return WSAEAFNOSUPPORT;
                    186:     }
                    187: 
                    188:     //
                    189:     // Make sure that the length is correct.
                    190:     //
                    191: 
                    192:     if ( SockaddrLength < sizeof(SOCKADDR_IN) ) {
                    193:        return WSAEFAULT;
                    194:     }
                    195: 
                    196:     //
                    197:     // The address passed the tests, looks like a good address.
                    198:     // Determine the type of the address portion of the sockaddr.
                    199:     //
                    200: 
                    201:     if ( sockaddr->sin_addr.s_addr == INADDR_ANY ) {
                    202:        SockaddrInfo->AddressInfo = SockaddrAddressInfoWildcard;
                    203:     } else if ( sockaddr->sin_addr.s_addr == INADDR_BROADCAST ) {
                    204:        SockaddrInfo->AddressInfo = SockaddrAddressInfoBroadcast;
                    205:     } else if ( sockaddr->sin_addr.s_addr == INADDR_LOOPBACK ) {
                    206:        SockaddrInfo->AddressInfo = SockaddrAddressInfoLoopback;
                    207:     } else {
                    208:        SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
                    209:     }
                    210: 
                    211:     //
                    212:     // Determine the type of the port (endpoint) in the sockaddr.
                    213:     //
                    214: 
                    215:     if ( sockaddr->sin_port == 0 ) {
                    216:        SockaddrInfo->EndpointInfo = SockaddrEndpointInfoWildcard;
                    217:     } else if ( ntohs( sockaddr->sin_port ) < 2000 ) {
                    218:        SockaddrInfo->EndpointInfo = SockaddrEndpointInfoReserved;
                    219:     } else {
                    220:        SockaddrInfo->EndpointInfo = SockaddrEndpointInfoNormal;
                    221:     }
                    222: 
                    223:     //
                    224:     // Zero out the sin_zero part of the address.  We silently allow
                    225:     // nonzero values in this field.
                    226:     //
                    227: 
                    228:     for ( i = 0; i < sizeof(sockaddr->sin_zero); i++ ) {
                    229:        sockaddr->sin_zero[i] = 0;
                    230:     }
                    231: 
                    232:     return NO_ERROR;
                    233: 
                    234: } // WSHGetSockaddrType
                    235: 
                    236: 
                    237: INT
                    238: WINAPI
                    239: WSHGetSocketInformation (
                    240:     IN PVOID HelperDllSocketContext,
                    241:     IN SOCKET SocketHandle,
                    242:     IN HANDLE TdiAddressObjectHandle,
                    243:     IN HANDLE TdiConnectionObjectHandle,
                    244:     IN INT Level,
                    245:     IN INT OptionName,
                    246:     OUT PCHAR OptionValue,
                    247:     OUT PINT OptionLength
                    248:     )
                    249: 
                    250: /*++
                    251: 
                    252: Routine Description:
                    253: 
                    254:     This routine retrieves information about a socket for those socket
                    255:     options supported in this helper DLL.  The options supported here
                    256:     are SO_KEEPALIVE and SO_DONTROUTE.  This routine is called by
                    257:     the winsock DLL when a level/option name combination is passed
                    258:     to getsockopt() that the winsock DLL does not understand.
                    259: 
                    260: Arguments:
                    261: 
                    262:     HelperDllSocketContext - the context pointer returned from
                    263:        WSHOpenSocket().
                    264: 
                    265:     SocketHandle - the handle of the socket for which we're getting
                    266:        information.
                    267: 
                    268:     TdiAddressObjectHandle - the TDI address object of the socket, if
                    269:        any.  If the socket is not yet bound to an address, then
                    270:        it does not have a TDI address object and this parameter
                    271:        will be NULL.
                    272: 
                    273:     TdiConnectionObjectHandle - the TDI connection object of the socket,
                    274:        if any.  If the socket is not yet connected, then it does not
                    275:        have a TDI connection object and this parameter will be NULL.
                    276: 
                    277:     Level - the level parameter passed to getsockopt().
                    278: 
                    279:     OptionName - the optname parameter passed to getsockopt().
                    280: 
                    281:     OptionValue - the optval parameter passed to getsockopt().
                    282: 
                    283:     OptionLength - the optlen parameter passed to getsockopt().
                    284: 
                    285: Return Value:
                    286: 
                    287:     INT - a winsock error code indicating the status of the operation, or
                    288:        NO_ERROR if the operation succeeded.
                    289: 
                    290: --*/
                    291: 
                    292: {
                    293:     PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
                    294: 
                    295:     UNREFERENCED_PARAMETER( SocketHandle );
                    296:     UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
                    297:     UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
                    298: 
                    299:     //
                    300:     // Check if this is an internal request for context information.
                    301:     //
                    302: 
                    303:     if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
                    304: 
                    305:        //
                    306:        // The Windows Sockets DLL is requesting context information 
                    307:        // from us.  If an output buffer was not supplied, the Windows 
                    308:        // Sockets DLL is just requesting the size of our context 
                    309:        // information.  
                    310:        //
                    311: 
                    312:        if ( OptionValue != NULL ) {
                    313: 
                    314:            //
                    315:            // Make sure that the buffer is sufficient to hold all the 
                    316:            // context information.  
                    317:            //
                    318: 
                    319:            if ( *OptionLength < sizeof(*context) ) {
                    320:                return WSAEFAULT;
                    321:            }
                    322: 
                    323:            //
                    324:            // Copy in the context information.
                    325:            //
                    326: 
                    327:            CopyMemory( OptionValue, context, sizeof(*context) );
                    328:        }
                    329: 
                    330:        *OptionLength = sizeof(*context);
                    331: 
                    332:        return NO_ERROR;
                    333:     }
                    334: 
                    335:     //
                    336:     // The only other levels we support here are SOL_SOCKET and 
                    337:     // IPPROTO_TCP.  
                    338:     //
                    339: 
                    340:     if ( Level != SOL_SOCKET && Level != IPPROTO_TCP ) {
                    341:        return WSAEINVAL;
                    342:     }
                    343: 
                    344:     //
                    345:     // Make sure that the output buffer is sufficiently large.
                    346:     //
                    347: 
                    348:     if ( *OptionLength < sizeof(int) ) {
                    349:        return WSAEFAULT;
                    350:     }
                    351: 
                    352:     //
                    353:     // Handle TCP-level options.
                    354:     //
                    355: 
                    356:     if ( Level == IPPROTO_TCP ) {
                    357:               
                    358:        if ( OptionName != TCP_NODELAY ) {
                    359:            return WSAEINVAL;
                    360:        }
                    361: 
                    362:        if ( context->SocketType == SOCK_DGRAM ) {
                    363:            return WSAENOPROTOOPT;
                    364:        }
                    365: 
                    366:        ZeroMemory( OptionValue, *OptionLength );
                    367: 
                    368:        *OptionValue = context->NoDelay;
                    369:        *OptionLength = sizeof(int);
                    370: 
                    371:        return NO_ERROR;
                    372:     }
                    373: 
                    374:     //
                    375:     // Handle socket-level options.
                    376:     //
                    377: 
                    378:     switch ( OptionName ) {
                    379: 
                    380:     case SO_KEEPALIVE:
                    381: 
                    382:        if ( context->SocketType == SOCK_DGRAM ) {
                    383:            return WSAENOPROTOOPT;
                    384:        }
                    385: 
                    386:        ZeroMemory( OptionValue, *OptionLength );
                    387: 
                    388:        *OptionValue = context->KeepAlive;
                    389:        *OptionLength = sizeof(int);
                    390: 
                    391:        break;
                    392: 
                    393:     case SO_DONTROUTE:
                    394: 
                    395:        ZeroMemory( OptionValue, *OptionLength );
                    396: 
                    397:        *OptionValue = context->DontRoute;
                    398:        *OptionLength = sizeof(int);
                    399: 
                    400:        break;
                    401: 
                    402:     default:
                    403: 
                    404:        return WSAENOPROTOOPT;
                    405:     }
                    406: 
                    407:     return NO_ERROR;
                    408: 
                    409: } // WSHGetSocketInformation
                    410: 
                    411: 
                    412: INT
                    413: WINAPI
                    414: WSHGetWildcardSockaddr (
                    415:     IN PVOID HelperDllSocketContext,
                    416:     OUT PSOCKADDR Sockaddr,
                    417:     OUT PINT SockaddrLength
                    418:     )
                    419: 
                    420: /*++
                    421: 
                    422: Routine Description:
                    423: 
                    424:     This routine returns a wildcard socket address.  A wildcard address
                    425:     is one which will bind the socket to an endpoint of the transport's
                    426:     choosing.  For TCP/IP, a wildcard address has IP address ==
                    427:     0.0.0.0 and port = 0.
                    428: 
                    429: Arguments:
                    430: 
                    431:     HelperDllSocketContext - the context pointer returned from
                    432:        WSHOpenSocket() for the socket for which we need a wildcard
                    433:        address.
                    434: 
                    435:     Sockaddr - points to a buffer which will receive the wildcard socket
                    436:        address.
                    437: 
                    438:     SockaddrLength - receives the length of the wioldcard sockaddr.
                    439: 
                    440: Return Value:
                    441: 
                    442:     INT - a winsock error code indicating the status of the operation, or
                    443:        NO_ERROR if the operation succeeded.
                    444: 
                    445: --*/
                    446: 
                    447: {
                    448:     if ( *SockaddrLength < sizeof(SOCKADDR_IN) ) {
                    449:        return WSAEFAULT;
                    450:     }
                    451: 
                    452:     *SockaddrLength = sizeof(SOCKADDR_IN);
                    453: 
                    454:     //
                    455:     // Just zero out the address and set the family to AF_INET--this is 
                    456:     // a wildcard address for TCP/IP.  
                    457:     //
                    458: 
                    459:     ZeroMemory( Sockaddr, sizeof(SOCKADDR_IN) );
                    460: 
                    461:     Sockaddr->sa_family = AF_INET;
                    462: 
                    463:     return NO_ERROR;
                    464: 
                    465: } // WSAGetWildcardSockaddr
                    466: 
                    467: 
                    468: DWORD
                    469: WINAPI
                    470: WSHGetWinsockMapping (
                    471:     OUT PWINSOCK_MAPPING Mapping,
                    472:     IN DWORD MappingLength
                    473:     )
                    474: 
                    475: /*++
                    476: 
                    477: Routine Description:
                    478: 
                    479:     Returns the list of address family/socket type/protocol triples
                    480:     supported by this helper DLL.
                    481: 
                    482: Arguments:
                    483: 
                    484:     Mapping - receives a pointer to a WINSOCK_MAPPING structure that
                    485:        describes the triples supported here.
                    486: 
                    487:     MappingLength - the length, in bytes, of the passed-in Mapping buffer.
                    488: 
                    489: Return Value:
                    490: 
                    491:     DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
                    492:        helper DLL.  If the passed-in buffer is too small, the return
                    493:        value will indicate the size of a buffer needed to contain
                    494:        the WINSOCK_MAPPING structure.
                    495: 
                    496: --*/
                    497: 
                    498: {
                    499:     DWORD mappingLength;
                    500: 
                    501:     mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
                    502:                        sizeof(TcpMappingTriples) + sizeof(UdpMappingTriples);
                    503: 
                    504:     //
                    505:     // If the passed-in buffer is too small, return the length needed
                    506:     // now without writing to the buffer.  The caller should allocate
                    507:     // enough memory and call this routine again.
                    508:     //
                    509: 
                    510:     if ( mappingLength > MappingLength ) {
                    511:        return mappingLength;
                    512:     }
                    513: 
                    514:     //
                    515:     // Fill in the output mapping buffer with the list of triples
                    516:     // supported in this helper DLL.
                    517:     //
                    518: 
                    519:     Mapping->Rows = sizeof(TcpMappingTriples) / sizeof(TcpMappingTriples[0])
                    520:                     + sizeof(UdpMappingTriples) / sizeof(UdpMappingTriples[0]);
                    521:     Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
                    522:     MoveMemory(
                    523:        Mapping->Mapping,
                    524:        TcpMappingTriples,
                    525:        sizeof(TcpMappingTriples)
                    526:        );
                    527:     MoveMemory(
                    528:        (PCHAR)Mapping->Mapping + sizeof(TcpMappingTriples),
                    529:        UdpMappingTriples,
                    530:        sizeof(UdpMappingTriples)
                    531:        );
                    532: 
                    533:     //
                    534:     // Return the number of bytes we wrote.
                    535:     //
                    536: 
                    537:     return mappingLength;
                    538: 
                    539: } // WSHGetWinsockMapping
                    540: 
                    541: 
                    542: INT
                    543: WINAPI
                    544: WSHOpenSocket (
                    545:     IN OUT PINT AddressFamily,
                    546:     IN OUT PINT SocketType,
                    547:     IN OUT PINT Protocol,
                    548:     OUT PUNICODE_STRING TransportDeviceName,
                    549:     OUT PVOID *HelperDllSocketContext,
                    550:     OUT PDWORD NotificationEvents
                    551:     )
                    552: 
                    553: /*++
                    554: 
                    555: Routine Description:
                    556: 
                    557:     Does the necessary work for this helper DLL to open a socket and is
                    558:     called by the winsock DLL in the socket() routine.  This routine
                    559:     verifies that the specified triple is valid, determines the NT
                    560:     device name of the TDI provider that will support that triple,
                    561:     allocates space to hold the socket's context block, and
                    562:     canonicalizes the triple.
                    563: 
                    564: Arguments:
                    565: 
                    566:     AddressFamily - on input, the address family specified in the
                    567:        socket() call.  On output, the canonicalized value for the
                    568:        address family.
                    569: 
                    570:     SocketType - on input, the socket type specified in the socket()
                    571:        call.  On output, the canonicalized value for the socket type.
                    572: 
                    573:     Protocol - on input, the protocol specified in the socket() call.
                    574:        On output, the canonicalized value for the protocol.
                    575: 
                    576:     TransportDeviceName - receives the name of the TDI provider that
                    577:        will support the specified triple.
                    578: 
                    579:     HelperDllSocketContext - receives a context pointer that the winsock
                    580:        DLL will return to this helper DLL on future calls involving
                    581:        this socket.
                    582: 
                    583:     NotificationEvents - receives a bitmask of those state transitions
                    584:        this helper DLL should be notified on.
                    585: 
                    586: Return Value:
                    587: 
                    588:     INT - a winsock error code indicating the status of the operation, or
                    589:        NO_ERROR if the operation succeeded.
                    590: 
                    591: --*/
                    592: 
                    593: {
                    594:     PWSHTCPIP_SOCKET_CONTEXT context;
                    595: 
                    596:     //
                    597:     // Determine whether this is to be a TCP or UDP socket.
                    598:     //
                    599: 
                    600:     if ( IsTripleInList(
                    601:             TcpMappingTriples,
                    602:             sizeof(TcpMappingTriples) / sizeof(TcpMappingTriples[0]),
                    603:             *AddressFamily,
                    604:             *SocketType,
                    605:             *Protocol ) ) {
                    606: 
                    607:        //
                    608:        // Return the canonical form of a TCP socket triple.
                    609:        //
                    610: 
                    611:        *AddressFamily = TcpMappingTriples[0].AddressFamily;
                    612:        *SocketType = TcpMappingTriples[0].SocketType;
                    613:        *Protocol = TcpMappingTriples[0].Protocol;
                    614: 
                    615:        //
                    616:        // Indicate the name of the TDI device that will service
                    617:        // SOCK_STREAM sockets in the internet address family.
                    618:        //
                    619: 
                    620:        RtlInitUnicodeString( TransportDeviceName, L"\\Device\\Streams\\Tcp" );
                    621: 
                    622:     } else if ( IsTripleInList(
                    623:                    UdpMappingTriples,
                    624:                    sizeof(UdpMappingTriples) / sizeof(UdpMappingTriples[0]),
                    625:                    *AddressFamily,
                    626:                    *SocketType,
                    627:                    *Protocol ) ) {
                    628: 
                    629:        //
                    630:        // Return the canonical form of a UDP socket triple.
                    631:        //
                    632: 
                    633:        *AddressFamily = UdpMappingTriples[0].AddressFamily;
                    634:        *SocketType = UdpMappingTriples[0].SocketType;
                    635:        *Protocol = UdpMappingTriples[0].Protocol;
                    636: 
                    637:        //
                    638:        // Indicate the name of the TDI device that will service
                    639:        // SOCK_DGRAM sockets in the internet address family.
                    640:        //
                    641: 
                    642:        RtlInitUnicodeString( TransportDeviceName, L"\\Device\\Streams\\Udp" );
                    643: 
                    644:     } else {
                    645: 
                    646:        //
                    647:        // This should never happen if the registry information about this
                    648:        // helper DLL is correct.  If somehow this did happen, just return
                    649:        // an error.
                    650:        //
                    651: 
                    652:        return WSAEINVAL;
                    653:     }
                    654: 
                    655:     //
                    656:     // Allocate context for this socket.  The Windows Sockets DLL will
                    657:     // return this value to us when it asks us to get/set socket options.
                    658:     //
                    659: 
                    660:     context = (PWSHTCPIP_SOCKET_CONTEXT) HeapAlloc(
                    661:                                                                                 GetProcessHeap(),
                    662:                                                                                 0,
                    663:                                                                                 sizeof(*context)
                    664:                                                                                 );
                    665:     if ( context == NULL ) {
                    666:        return WSAENOBUFS;
                    667:     }
                    668: 
                    669:     //
                    670:     // Initialize the context for the socket.
                    671:     //
                    672: 
                    673:     context->AddressFamily = *AddressFamily;
                    674:     context->SocketType = *SocketType;
                    675:     context->Protocol = *Protocol;
                    676:     context->ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
                    677:     context->KeepAlive = FALSE;
                    678:     context->DontRoute = FALSE;
                    679:     context->NoDelay = FALSE;
                    680: 
                    681:     //
                    682:     // Tell the Windows Sockets DLL which state transitions we're
                    683:     // interested in being notified of.  The only time we need to be
                    684:     // called is after a connect has completed so that we can turn on
                    685:     // the sending of keepalives if SO_KEEPALIVE was set before the
                    686:     // socket was connected.
                    687:     //
                    688: 
                    689:     *NotificationEvents = WSH_NOTIFY_CONNECT | WSH_NOTIFY_CLOSE;
                    690: 
                    691:     //
                    692:     // Everything worked, return success.
                    693:     //
                    694: 
                    695:     *HelperDllSocketContext = context;
                    696:     return NO_ERROR;
                    697: 
                    698: } // WSHOpenSocket
                    699: 
                    700: 
                    701: INT
                    702: WINAPI
                    703: WSHNotify (
                    704:     IN PVOID HelperDllSocketContext,
                    705:     IN SOCKET SocketHandle,
                    706:     IN HANDLE TdiAddressObjectHandle,
                    707:     IN HANDLE TdiConnectionObjectHandle,
                    708:     IN DWORD NotifyEvent
                    709:     )
                    710: 
                    711: /*++
                    712: 
                    713: Routine Description:
                    714: 
                    715:     This routine is called by the winsock DLL after a state transition
                    716:     of the socket.  Only state transitions returned in the
                    717:     NotificationEvents parameter of WSHOpenSocket() are notified here.
                    718:     This routine allows a winsock helper DLL to track the state of
                    719:     socket and perform necessary actions corresponding to state
                    720:     transitions.
                    721: 
                    722: Arguments:
                    723: 
                    724:     HelperDllSocketContext - the context pointer given to the winsock
                    725:        DLL by WSHOpenSocket().
                    726: 
                    727:     SocketHandle - the handle for the socket.
                    728: 
                    729:     TdiAddressObjectHandle - the TDI address object of the socket, if
                    730:        any.  If the socket is not yet bound to an address, then
                    731:        it does not have a TDI address object and this parameter
                    732:        will be NULL.
                    733: 
                    734:     TdiConnectionObjectHandle - the TDI connection object of the socket,
                    735:        if any.  If the socket is not yet connected, then it does not
                    736:        have a TDI connection object and this parameter will be NULL.
                    737: 
                    738:     NotifyEvent - indicates the state transition for which we're being
                    739:        called.
                    740: 
                    741: Return Value:
                    742: 
                    743:     INT - a winsock error code indicating the status of the operation, or
                    744:        NO_ERROR if the operation succeeded.
                    745: 
                    746: --*/
                    747: 
                    748: {
                    749:     PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
                    750:     INT err;
                    751: 
                    752:     //
                    753:     // We should only be called after a connect() completes or when the
                    754:     // socket is being closed.
                    755:     //
                    756: 
                    757:     if ( NotifyEvent == WSH_NOTIFY_CONNECT ) {
                    758: 
                    759:        //
                    760:        // SO_KEEPALIVE or TCP_NODELAY was set before the socket was 
                    761:        // connected.  Set it now.  
                    762:        //
                    763: 
                    764:        if ( context->KeepAlive ) {
                    765:            err = DoTdiAction(
                    766:                      TdiConnectionObjectHandle,
                    767:                      TOL_TLI,
                    768:                      TO_KEEPALIVE,
                    769:                      TRUE
                    770:                      );
                    771:            if ( err != NO_ERROR ) {
                    772:                return err;
                    773:            }
                    774:        }
                    775: 
                    776:        if ( context->NoDelay ) {
                    777:            err = DoTdiAction(
                    778:                      TdiConnectionObjectHandle,
                    779:                      TOL_TLI,
                    780:                      TO_NODELAY,
                    781:                      TRUE
                    782:                      );
                    783:            if ( err != NO_ERROR ) {
                    784:                return err;
                    785:            }
                    786:        }
                    787: 
                    788:        if ( context->ReceiveBufferSize != DEFAULT_RECEIVE_BUFFER_SIZE ) {
                    789:            err = DoTdiAction(
                    790:                      TdiConnectionObjectHandle,
                    791:                      TOL_RCVBUF,
                    792:                      0,
                    793:                      context->ReceiveBufferSize
                    794:                      );
                    795:            if ( err != NO_ERROR ) {
                    796:                return err;
                    797:            }
                    798:        }
                    799: 
                    800:     } else if ( NotifyEvent == WSH_NOTIFY_CLOSE ) {
                    801: 
                    802:        //
                    803:        // Just free the socket context.
                    804:        //
                    805: 
                    806:        HeapFree( GetProcessHeap( ), 0, (LPSTR)HelperDllSocketContext );
                    807: 
                    808:     } else {
                    809: 
                    810:        return WSAEINVAL;
                    811:     }
                    812: 
                    813: 
                    814:     return NO_ERROR;
                    815: 
                    816: } // WSHNotify
                    817: 
                    818: 
                    819: INT
                    820: WINAPI
                    821: WSHSetSocketInformation (
                    822:     IN PVOID HelperDllSocketContext,
                    823:     IN SOCKET SocketHandle,
                    824:     IN HANDLE TdiAddressObjectHandle,
                    825:     IN HANDLE TdiConnectionObjectHandle,
                    826:     IN INT Level,
                    827:     IN INT OptionName,
                    828:     IN PCHAR OptionValue,
                    829:     IN INT OptionLength
                    830:     )
                    831: 
                    832: /*++
                    833: 
                    834: Routine Description:
                    835: 
                    836:     This routine sets information about a socket for those socket
                    837:     options supported in this helper DLL.  The options supported here
                    838:     are SO_KEEPALIVE and SO_DONTROUTE.  This routine is called by the
                    839:     winsock DLL when a level/option name combination is passed to
                    840:     setsockopt() that the winsock DLL does not understand.
                    841: 
                    842: Arguments:
                    843: 
                    844:     HelperDllSocketContext - the context pointer returned from
                    845:        WSHOpenSocket().
                    846: 
                    847:     SocketHandle - the handle of the socket for which we're getting
                    848:        information.
                    849: 
                    850:     TdiAddressObjectHandle - the TDI address object of the socket, if
                    851:        any.  If the socket is not yet bound to an address, then
                    852:        it does not have a TDI address object and this parameter
                    853:        will be NULL.
                    854: 
                    855:     TdiConnectionObjectHandle - the TDI connection object of the socket,
                    856:        if any.  If the socket is not yet connected, then it does not
                    857:        have a TDI connection object and this parameter will be NULL.
                    858: 
                    859:     Level - the level parameter passed to setsockopt().
                    860: 
                    861:     OptionName - the optname parameter passed to setsockopt().
                    862: 
                    863:     OptionValue - the optval parameter passed to setsockopt().
                    864: 
                    865:     OptionLength - the optlen parameter passed to setsockopt().
                    866: 
                    867: Return Value:
                    868: 
                    869:     INT - a winsock error code indicating the status of the operation, or
                    870:        NO_ERROR if the operation succeeded.
                    871: 
                    872: --*/
                    873: 
                    874: {
                    875:     PWSHTCPIP_SOCKET_CONTEXT context = HelperDllSocketContext;
                    876:     INT error;
                    877:     INT optionValue;
                    878: 
                    879:     UNREFERENCED_PARAMETER( SocketHandle );
                    880:     UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
                    881:     UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
                    882: 
                    883:     //
                    884:     // Check if this is an internal request for context information.
                    885:     //
                    886: 
                    887:     if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
                    888: 
                    889:        //
                    890:        // The Windows Sockets DLL is requesting that we set context 
                    891:        // information for a new socket.  If the new socket was 
                    892:        // accept()'ed, then we have already been notified of the socket 
                    893:        // and HelperDllSocketContext will be valid.  If the new socket 
                    894:        // was inherited or duped into this process, then this is our 
                    895:        // first notification of the socket and HelperDllSocketContext 
                    896:        // will be equal to NULL.  
                    897:        //
                    898:        // Insure that the context information being passed to us is 
                    899:        // sufficiently large.  
                    900:        //
                    901: 
                    902:        if ( OptionLength < sizeof(*context) ) {
                    903:            return WSAEINVAL;
                    904:        }
                    905: 
                    906:        if ( HelperDllSocketContext == NULL ) {
                    907:            
                    908:            //
                    909:            // This is our notification that a socket handle was 
                    910:            // inherited or duped into this process.  Allocate a context 
                    911:            // structure for the new socket.  
                    912:            //
                    913:     
                    914:            context = (PWSHTCPIP_SOCKET_CONTEXT) HeapAlloc(
                    915:                                                                                        GetProcessHeap(),
                    916:                                                                                        0,
                    917:                                                                                        sizeof(*context)
                    918:                                                                                        );
                    919:            if ( context == NULL ) {
                    920:                return WSAENOBUFS;
                    921:            }
                    922:     
                    923:            //
                    924:            // Copy over information into the context block.
                    925:            //
                    926:     
                    927:            CopyMemory( context, OptionValue, sizeof(*context) );
                    928:     
                    929:            //
                    930:            // Tell the Windows Sockets DLL where our context information is 
                    931:            // stored so that it can return the context pointer in future 
                    932:            // calls.  
                    933:            //
                    934:     
                    935:            *(PWSHTCPIP_SOCKET_CONTEXT *)OptionValue = context;
                    936:     
                    937:            return NO_ERROR;
                    938: 
                    939:        } else {
                    940: 
                    941:            PWSHTCPIP_SOCKET_CONTEXT parentContext;
                    942:            INT one = 1;
                    943: 
                    944:            //
                    945:            // The socket was accept()'ed and it needs to have the same 
                    946:            // properties as it'sw parent.  The OptionValue buffer 
                    947:            // contains the context information of this socket's parent.  
                    948:            //
                    949: 
                    950:            parentContext = (PWSHTCPIP_SOCKET_CONTEXT)OptionValue;
                    951: 
                    952:            assert( context->AddressFamily == parentContext->AddressFamily );
                    953:            assert( context->SocketType == parentContext->SocketType );
                    954:            assert( context->Protocol == parentContext->Protocol );
                    955: 
                    956:            //
                    957:            // Turn on in the child any options that have been set in
                    958:            // the parent.
                    959:            //
                    960: 
                    961:            if ( parentContext->KeepAlive ) {
                    962: 
                    963:                error = WSHSetSocketInformation(
                    964:                            HelperDllSocketContext,
                    965:                            SocketHandle,
                    966:                            TdiAddressObjectHandle,
                    967:                            TdiConnectionObjectHandle,
                    968:                            SOL_SOCKET,
                    969:                            SO_KEEPALIVE,
                    970:                            (PCHAR)&one,
                    971:                            sizeof(one)
                    972:                            );
                    973:                if ( error != NO_ERROR ) {
                    974:                    return error;
                    975:                }
                    976:            }
                    977: 
                    978:            if ( parentContext->DontRoute ) {
                    979: 
                    980:                error = WSHSetSocketInformation(
                    981:                            HelperDllSocketContext,
                    982:                            SocketHandle,
                    983:                            TdiAddressObjectHandle,
                    984:                            TdiConnectionObjectHandle,
                    985:                            SOL_SOCKET,
                    986:                            SO_DONTROUTE,
                    987:                            (PCHAR)&one,
                    988:                            sizeof(one)
                    989:                            );
                    990:                if ( error != NO_ERROR ) {
                    991:                    return error;
                    992:                }
                    993:            }
                    994: 
                    995:            if ( parentContext->NoDelay ) {
                    996: 
                    997:                error = WSHSetSocketInformation(
                    998:                            HelperDllSocketContext,
                    999:                            SocketHandle,
                   1000:                            TdiAddressObjectHandle,
                   1001:                            TdiConnectionObjectHandle,
                   1002:                            IPPROTO_TCP,
                   1003:                            TCP_NODELAY,
                   1004:                            (PCHAR)&one,
                   1005:                            sizeof(one)
                   1006:                            );
                   1007:                if ( error != NO_ERROR ) {
                   1008:                    return error;
                   1009:                }
                   1010:            }
                   1011: 
                   1012:            if ( parentContext->ReceiveBufferSize != DEFAULT_RECEIVE_BUFFER_SIZE ) {
                   1013: 
                   1014:                error = WSHSetSocketInformation(
                   1015:                            HelperDllSocketContext,
                   1016:                            SocketHandle,
                   1017:                            TdiAddressObjectHandle,
                   1018:                            TdiConnectionObjectHandle,
                   1019:                            SOL_SOCKET,
                   1020:                            SO_RCVBUF,
                   1021:                            (PCHAR)&parentContext->ReceiveBufferSize,
                   1022:                            sizeof(parentContext->ReceiveBufferSize)
                   1023:                            );
                   1024:                if ( error != NO_ERROR ) {
                   1025:                    return error;
                   1026:                }
                   1027:            }
                   1028: 
                   1029:            return NO_ERROR;
                   1030:        }
                   1031:     }
                   1032: 
                   1033:     //
                   1034:     // The only other levels we support here are SOL_SOCKET and 
                   1035:     // IPPROTO_TCP.  
                   1036:     //
                   1037: 
                   1038:     if ( Level != SOL_SOCKET && Level != IPPROTO_TCP ) {
                   1039:        return WSAEINVAL;
                   1040:     }
                   1041: 
                   1042:     //
                   1043:     // Make sure that the option length is sufficient.
                   1044:     //
                   1045: 
                   1046:     if ( OptionLength < sizeof(int) ) {
                   1047:        return WSAEFAULT;
                   1048:     }
                   1049: 
                   1050:     optionValue = *(PINT)OptionValue;
                   1051: 
                   1052:     //
                   1053:     // Handle TCP-level options.
                   1054:     //
                   1055: 
                   1056:     if ( Level == IPPROTO_TCP ) {
                   1057:               
                   1058:        if ( OptionName != TCP_NODELAY ) {
                   1059:            return WSAEINVAL;
                   1060:        }
                   1061: 
                   1062:        if ( context->SocketType == SOCK_DGRAM ) {
                   1063:            return WSAENOPROTOOPT;
                   1064:        }
                   1065: 
                   1066:        //
                   1067:        // Atempt to turn on or off Nagle's algorithm, as necessary.
                   1068:        //
                   1069: 
                   1070:        if ( !context->NoDelay && optionValue != 0 ) {
                   1071: 
                   1072:            //
                   1073:            // NoDelay is currently off and the application wants to 
                   1074:            // turn it on.  If the TDI connection object handle is NULL, 
                   1075:            // then the socket is not yet connected.  In this case we'll 
                   1076:            // just remember that the no delay option was set and 
                   1077:            // actually turn them on in WSHNotify() after a connect() 
                   1078:            // has completed on the socket.  
                   1079:            //
                   1080: 
                   1081:            if ( TdiConnectionObjectHandle != NULL ) {
                   1082:                error = DoTdiAction(
                   1083:                            TdiConnectionObjectHandle,
                   1084:                            TOL_TLI,
                   1085:                            TO_NODELAY,
                   1086:                            TRUE
                   1087:                            );
                   1088:                if ( error != NO_ERROR ) {
                   1089:                    return error;
                   1090:                }
                   1091:            }
                   1092: 
                   1093:            //
                   1094:            // Remember that no delay is enabled for this socket.
                   1095:            //
                   1096: 
                   1097:            context->NoDelay = TRUE;
                   1098: 
                   1099:        } else if ( context->NoDelay && optionValue == 0 ) {
                   1100: 
                   1101:            //
                   1102:            // No delay is currently enabled and the application wants 
                   1103:            // to turn it off.  If the TDI connection object is NULL, 
                   1104:            // the socket is not yet connected.  In this case we'll just 
                   1105:            // remember that nodelay is disabled.  
                   1106:            //
                   1107: 
                   1108:            if ( TdiConnectionObjectHandle != NULL ) {
                   1109:                error = DoTdiAction(
                   1110:                            TdiConnectionObjectHandle,
                   1111:                            TOL_TLI,
                   1112:                            TO_NODELAY,
                   1113:                            FALSE
                   1114:                            );
                   1115:                if ( error != NO_ERROR ) {
                   1116:                    return error;
                   1117:                }
                   1118:            }
                   1119: 
                   1120:            //
                   1121:            // Remember that no delay is disabled for this socket.
                   1122:            //
                   1123: 
                   1124:            context->NoDelay = FALSE;
                   1125:        }
                   1126: 
                   1127:        return NO_ERROR;
                   1128:     }
                   1129: 
                   1130:     //
                   1131:     // Handle socket-level options.
                   1132:     //
                   1133: 
                   1134:     switch ( OptionName ) {
                   1135: 
                   1136:     case SO_KEEPALIVE:
                   1137: 
                   1138:        //
                   1139:        // Atempt to turn on or off keepalive sending, as necessary.
                   1140:        //
                   1141: 
                   1142:        if ( context->SocketType == SOCK_DGRAM ) {
                   1143:            return WSAENOPROTOOPT;
                   1144:        }
                   1145: 
                   1146:        if ( !context->KeepAlive && optionValue != 0 ) {
                   1147: 
                   1148:            //
                   1149:            // Keepalives are currently off and the application wants to
                   1150:            // turn them on.  If the TDI connection object handle is
                   1151:            // NULL, then the socket is not yet connected.  In this case
                   1152:            // we'll just remember that the keepalive option was set and
                   1153:            // actually turn them on in WSHNotify() after a connect()
                   1154:            // has completed on the socket.
                   1155:            //
                   1156: 
                   1157:            if ( TdiConnectionObjectHandle != NULL ) {
                   1158:                error = DoTdiAction(
                   1159:                            TdiConnectionObjectHandle,
                   1160:                            TOL_TLI,
                   1161:                            TO_KEEPALIVE,
                   1162:                            TRUE
                   1163:                            );
                   1164:                if ( error != NO_ERROR ) {
                   1165:                    return error;
                   1166:                }
                   1167:            }
                   1168: 
                   1169:            //
                   1170:            // Remember that keepalives are enabled for this socket.
                   1171:            //
                   1172: 
                   1173:            context->KeepAlive = TRUE;
                   1174: 
                   1175:        } else if ( context->KeepAlive && optionValue == 0 ) {
                   1176: 
                   1177:            //
                   1178:            // Keepalives are currently enabled and the application
                   1179:            // wants to turn them off.  If the TDI connection object is
                   1180:            // NULL, the socket is not yet connected.  In this case
                   1181:            // we'll just remember that keepalives are disabled.
                   1182:            //
                   1183: 
                   1184:            if ( TdiConnectionObjectHandle != NULL ) {
                   1185:                error = DoTdiAction(
                   1186:                            TdiConnectionObjectHandle,
                   1187:                            TOL_TLI,
                   1188:                            TO_KEEPALIVE,
                   1189:                            FALSE
                   1190:                            );
                   1191:                if ( error != NO_ERROR ) {
                   1192:                    return error;
                   1193:                }
                   1194:            }
                   1195: 
                   1196:            //
                   1197:            // Remember that keepalives are disabled for this socket.
                   1198:            //
                   1199: 
                   1200:            context->KeepAlive = FALSE;
                   1201:        }
                   1202: 
                   1203:        break;
                   1204: 
                   1205:     case SO_DONTROUTE:
                   1206: 
                   1207:        //
                   1208:        // We don't really support SO_DONTROUTE.  Just remember that the
                   1209:        // option was set or unset.
                   1210:        //
                   1211: 
                   1212:        if ( optionValue != 0 ) {
                   1213:            context->DontRoute = TRUE;
                   1214:        } else if ( optionValue == 0 ) {
                   1215:            context->DontRoute = FALSE;
                   1216:        }
                   1217: 
                   1218:        break;
                   1219: 
                   1220:     case SO_RCVBUF:
                   1221: 
                   1222:        //
                   1223:        // If the receive buffer size is being changed, tell TCP about 
                   1224:        // it.  Do nothing if this is a datagram.  
                   1225:        //
                   1226: 
                   1227:        if ( context->ReceiveBufferSize == optionValue ||
                   1228:                 context->SocketType == SOCK_DGRAM ) {
                   1229:            break;
                   1230:        }
                   1231: 
                   1232:        //
                   1233:        // We need to pass the new receive buffer size to the TCP 
                   1234:        // transport.  If the TDI connection object is NULL, the socket 
                   1235:        // is not yet connected.  In this case we'll just remember the 
                   1236:        // new buffer size and set it after the socket is connected.  
                   1237:        //
                   1238: 
                   1239:        if ( TdiConnectionObjectHandle != NULL ) {
                   1240:            error = DoTdiAction(
                   1241:                        TdiConnectionObjectHandle,
                   1242:                        TOL_RCVBUF,
                   1243:                        0,
                   1244:                        optionValue
                   1245:                        );
                   1246:            if ( error != NO_ERROR ) {
                   1247:                return error;
                   1248:            }
                   1249:        }
                   1250: 
                   1251:        context->ReceiveBufferSize = optionValue;
                   1252: 
                   1253:        break;
                   1254: 
                   1255:     default:
                   1256: 
                   1257:        return WSAENOPROTOOPT;
                   1258:     }
                   1259: 
                   1260:     return NO_ERROR;
                   1261: 
                   1262: } // WSHSetSocketInformation
                   1263: 
                   1264: 
                   1265: BOOLEAN
                   1266: IsTripleInList (
                   1267:     IN PMAPPING_TRIPLE List,
                   1268:     IN ULONG ListLength,
                   1269:     IN INT AddressFamily,
                   1270:     IN INT SocketType,
                   1271:     IN INT Protocol
                   1272:     )
                   1273: 
                   1274: /*++
                   1275: 
                   1276: Routine Description:
                   1277: 
                   1278:     Determines whether the specified triple has an exact match in the
                   1279:     list of triples.
                   1280: 
                   1281: Arguments:
                   1282: 
                   1283:     List - a list of triples (address family/socket type/protocol) to
                   1284:        search.
                   1285: 
                   1286:     ListLength - the number of triples in the list.
                   1287: 
                   1288:     AddressFamily - the address family to look for in the list.
                   1289: 
                   1290:     SocketType - the socket type to look for in the list.
                   1291: 
                   1292:     Protocol - the protocol to look for in the list.
                   1293: 
                   1294: Return Value:
                   1295: 
                   1296:     BOOLEAN - TRUE if the triple was found in the list, false if not.
                   1297: 
                   1298: --*/
                   1299: 
                   1300: {
                   1301:     ULONG i;
                   1302: 
                   1303:     //
                   1304:     // Walk through the list searching for an exact match.
                   1305:     //
                   1306: 
                   1307:     for ( i = 0; i < ListLength; i++ ) {
                   1308: 
                   1309:        //
                   1310:        // If all three elements of the triple match, return indicating
                   1311:        // that the triple did exist in the list.
                   1312:        //
                   1313: 
                   1314:        if ( AddressFamily == List[i].AddressFamily &&
                   1315:             SocketType == List[i].SocketType &&
                   1316:             Protocol == List[i].Protocol ) {
                   1317:            return TRUE;
                   1318:        }
                   1319:     }
                   1320: 
                   1321:     //
                   1322:     // The triple was not found in the list.
                   1323:     //
                   1324: 
                   1325:     return FALSE;
                   1326: 
                   1327: } // IsTripleInList
                   1328: 
                   1329: 
                   1330: INT
                   1331: DoTdiAction (
                   1332:     IN HANDLE TdiConnectionObjectHandle,
                   1333:     IN INT OptionLevel,
                   1334:     IN INT OptionName,
                   1335:     IN INT OptionalData
                   1336:     )
                   1337: 
                   1338: /*++
                   1339: 
                   1340: Routine Description:
                   1341: 
                   1342:     Performs a TDI action to the TCP/IP driver.  A TDI action translates
                   1343:     into a streams T_OPTMGMT_REQ.
                   1344: 
                   1345: Arguments:
                   1346: 
                   1347:     TdiConnectionObjectHandle - a TDI connection object on which to perform
                   1348:        the TDI action.
                   1349: 
                   1350:     OptionLevel - the opt_level to pass in the TOPT structure.
                   1351: 
                   1352:     OptionName - The TPI option to set.
                   1353: 
                   1354:     OptionalData - data to put in the opt_data field of the TOPT
                   1355:        structure.
                   1356: 
                   1357: Return Value:
                   1358: 
                   1359:     INT - NO_ERROR, or a Windows Sockets error code.
                   1360: 
                   1361: --*/
                   1362: 
                   1363: {
                   1364:     BOOLEAN deviceIoResult;
                   1365:     PSTREAMS_TDI_ACTION tdiAction;
                   1366:     ULONG tdiActionLength;
                   1367:     TOPT *tpiOptions;
                   1368:     ULONG outputLength;
                   1369: 
                   1370:     //
                   1371:     // Allocate space to hold the TDI action buffer and the IO status
                   1372:     // block.  These cannot be stack variables in case we must return
                   1373:     // before the operation is complete.
                   1374:     //
                   1375: 
                   1376:     tdiActionLength = sizeof(*tdiAction) + sizeof(*tpiOptions) -
                   1377:                          sizeof(tdiAction->Buffer[0]);
                   1378: 
                   1379:     tdiAction = (PSTREAMS_TDI_ACTION) HeapAlloc(
                   1380:                                                              GetProcessHeap( ),
                   1381:                                                              0,
                   1382:                                                              tdiActionLength
                   1383:                                                              );
                   1384:     if ( tdiAction == NULL ) {
                   1385:        return WSAENOBUFS;
                   1386:     }
                   1387: 
                   1388:     //
                   1389:     // Initialize the TDI action buffer.
                   1390:     //
                   1391: 
                   1392:     tdiAction->BufferLength = sizeof(*tpiOptions);
                   1393: 
                   1394:     tpiOptions = (TOPT *)tdiAction->Buffer;
                   1395:     tpiOptions->opt_level = OptionLevel;
                   1396:     tpiOptions->opt_name = OptionName;
                   1397:     tpiOptions->opt_data[0] = OptionalData;
                   1398: 
                   1399:     //
                   1400:     // Make the actual TDI action call.  The Streams TDI mapper will 
                   1401:     // translate this into a TPI option management request for us and 
                   1402:     // give it to TCP/IP.  
                   1403:     //
                   1404: 
                   1405:     deviceIoResult = DeviceIoControl(
                   1406:                                 TdiConnectionObjectHandle,
                   1407:                                 IOCTL_TDI_ACTION,
                   1408:                                 tdiAction,
                   1409:                                 tdiActionLength,
                   1410:                                 tdiAction,
                   1411:                                 tdiActionLength,
                   1412:                                 &outputLength,
                   1413:                                 NULL
                   1414:                                 );
                   1415: 
                   1416:     HeapFree( GetProcessHeap( ), 0, (LPSTR)tdiAction );
                   1417: 
                   1418:     return deviceIoResult ? NO_ERROR : WSAENOBUFS;
                   1419: 
                   1420: } // DoTdiAction

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.