|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.