|
|
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.