4 * Implementation for pre-WinXP getaddrinfo() and getnameinfo() APIs.
9 * Written by Keith Marshall <keith@users.osdn.me>
10 * Copyright (C) 2020, 2022, MinGW.OSDN Project
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
20 * The above copyright notice and this permission notice (including the next
21 * paragraph) shall be included in all copies or substantial portions of the
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
34 * I have written this implementation of <wspiapi.h> from scratch, based
35 * entirely on hints from publicly visible Microsoft documentation, my own
36 * interpretation of IETF's RFC 3493, the corresponding POSIX.1 specification,
37 * and observation of the behaviour of example code from Microsoft's publicly
38 * visible documentation, which I have adapted to run on my GNU/Linux host.
39 * I have never seen code for Microsoft's <wspiapi.h> implementation; nor
40 * have I copied code from any other implementation, however licensed.
42 * This implementation servs as a fall-back for use on those legacy versions
43 * of Windows which do not support the getaddrinfo() and getnameinfo() APIs,
44 * through WS2_32.DLL on WinXP and later, or through WSHIP6.DLL on Win2K
45 * (with the IPv6 Preview Kit). Since such legacy Windows versions do not
46 * otherwise support IPv6, there is no attempt to support the AF_INET6
47 * address family; AF_INET is supported, as is AF_UNSPEC, but only to
48 * the extent that it is interpreted as AF_INET alone.
50 * It should be noted that, as described in Microsoft's documentation, the
51 * fall-back code is implemented in the form of in-line functions. This
52 * has a potentially disadvantageous side effect, in that every translation
53 * unit which calls any of the fall-back functions will incur a substantial
54 * overhead of potentially duplicated fall-back code. To mitigate this, it
55 * is recommended that all such calls be encapsulated within one translation
56 * unit, and exposed globally through public wrapper functions; an example
57 * of this technique may be found in the gcc/ada/socket.c implementation
58 * within recent GCC sources, wherein the public API is exposed via the
59 * __gnat_getaddrinfo(), __gnat_freeaddrinfo(), and __gnat_getnameinfo()
64 #pragma GCC system_header
70 /* Symbolic constants are useful as wild-card identifiers for socket types
71 * and protocols, but these are non-standard; we don't want to pollute the
72 * public namespace, so we add the reserved __WSPIAPI_ prefix for these.
74 #define __WSPIAPI_SOCK_ANY 0
75 #define __WSPIAPI_IPPROTO_ANY 0
79 /* __wspiapi_errout(): a helper to assign a WSA error code, via the
80 * WSASetLastError() function, and also return it for immediate use
81 * as the exit status for any wspiapi function.
83 static __inline__ __attribute__((__always_inline__))
84 int __wspiapi_errout( int status ){ WSASetLastError( status ); return status; }
86 /* __wspiapi_syserrout(): variation on __wspiapi_errout(), returning
87 * EAI_SYSTEM, after assigning a specific system errno value.
90 __attribute__((__always_inline__))
91 int __wspiapi_syserrout( int errcode )
92 { errno = errcode; return __wspiapi_errout( EAI_SYSTEM ); }
94 /* enum __wspiapi: generate symbolic names for the entry point indices
95 * within the wspapi function reference dictionary.
98 { __WSPIAPI_FREEADDRINFO__,
99 __WSPIAPI_GETADDRINFO__,
100 __WSPIAPI_GETNAMEINFO__
103 /* __wspiapi_t: a private use data type, describing the structure of
104 * each individual function reference within the dictionary.
111 /* __wspiapi_reference(): a helper function to retrieve a function
112 * entry point address, by indexed function name look-up within the
113 * reference dictionary.
115 static __inline__ __attribute__((__always_inline__))
116 __wspiapi_t *__wspiapi_reference( enum __wspiapi index )
118 /* The dictionary, itself, is statically encapsulated within this
119 * helper function, (and thus, is not publicly visible). Note that,
120 * initially, all entry point vectors are specified as (void *)(-1),
121 * and will be fixed-up on first call to any related function.
123 static __wspiapi_t dictionary[] =
124 { { "freeaddrinfo", (void *)(-1) },
125 { "getaddrinfo", (void *)(-1) },
126 { "getnameinfo", (void *)(-1) }
129 /* The return value is simply a pointer to the dictionary entry
130 * corresponding to the specified index.
132 return dictionary + index;
135 /* __wspiapi_set_entry(): helper function to perform the dictionary
136 * fix-up, for a single function entry point reference, as described
137 * for the __wspiapi_reference() function above. Note that this is
138 * called, only after a candidate DLL, which may be expected to
139 * provide the associated function, has been identified.
141 static __inline__ __attribute__((__always_inline__))
142 void __wspiapi_set_entry( HMODULE dll, __wspiapi_t *api )
143 { api->entry = (void *)(GetProcAddress( dll, api->name )); }
145 /* __wspiapi_module_handle(): helper to obtain a module handle for
146 * a candidate DLL, which is expected to provide all of the wspiapi
147 * functions, based on it satisfying one dictionary reference.
150 HMODULE __wspiapi_module_handle
151 ( char *path, char *subst, const char *name, __wspiapi_t *api )
155 /* "subst" points to the offset, within the "path" buffer, at which
156 * the system directory path name ends, and the DLL file name should
157 * be inserted; append the specified DLL file "name", and attempt to
158 * load a system DLL of that name.
160 strcpy( subst, name );
161 if( (ref = LoadLibraryA( path )) != NULL )
163 /* We successfully obtained a reference handle for the named DLL;
164 * check that we can also obtain an entry point reference, within
165 * this DLL, for the specified wspiapi function, recording the
166 * result in the wspiapi reference dictionary...
168 if( (api->entry = (void *)(GetProcAddress( ref, api->name ))) == NULL )
170 /* ...and declaring no further wspiapi interest in this DLL, if
171 * the requisite entry point is unavailable.
177 /* If we get to here, then we either have a valid handle for a DLL
178 * which does provide the requisite wspiapi witness function, in
179 * which case we return that handle, otherwise we return the NULL
180 * resulting from a failed DLL load request.
185 /* __wspiapi_lib(): a thin wrapper, through which all calls to
186 * __wspiapi_module_handle() are directed; it passes a system DLL
187 * search path, wherein the specified DLL name is substituted, (at
188 * the substring offset specified by "subst"), requiring that the
189 * designated system DLL should provide freeaddrinfo() as witness
190 * that it may be a suitable candidate provider for all of those
191 * functions which must otherwise be replaced by <wspiapi.h>
192 * fall-back implementations.
194 static __inline__ __attribute__((__always_inline__))
195 HMODULE __wspiapi_lib( char *path, char *subst, const char *name )
197 /* This requires nothing more than appending the wspiapi dictionary
198 * reference for the freeaddrinfo() function, to the arguments which
199 * have already been specified, and forwarding the request onward,
200 * to __wspiapi_module_handle().
202 return __wspiapi_module_handle(
203 path, subst, name, __wspiapi_reference(__WSPIAPI_FREEADDRINFO__)
207 /* __wspiapi_entry(): helper to retrieve the entry point address for
208 * a specified wspiapi function, by indexed look-up within the wspiapi
209 * reference dictionary; invokes __wspiapi_lib(), as may be required,
210 * to initialize the reference dictionary entries.
213 void *__wspiapi_entry( enum __wspiapi index )
214 # define __wspiapi_call( index ) (call)(__wspiapi_entry( index ))
216 /* First, check that the reference dictionary has been initialized,
217 * using the freeaddrinfo() entry point reference as witness.
219 if( __wspiapi_reference(__WSPIAPI_FREEADDRINFO__)->entry == (void *)(-1) )
221 /* The dictionary appears to be uninitialized; set up to perform
222 * entry point searches within DLLs in the system directory...
225 char sys_path[MAX_PATH], *dllname;
226 dllname = sys_path + GetSystemDirectory( sys_path, MAX_PATH - 11 );
227 if( dllname > sys_path )
228 { /* ...then, preferring WS2_32.DLL, but accepting WSHIP6.DLL as
229 * a second choice alternative, initialize the dictionary entry
230 * for the freeaddrinfo() witness function...
232 if( ((dll = __wspiapi_lib( sys_path, dllname, "\\ws2_32" )) != NULL)
233 || ((dll = __wspiapi_lib( sys_path, dllname, "\\wship6" )) != NULL) )
235 /* ...and, when that resolves to a valid entry point address,
236 * also initialize the entry point references, using the same
237 * DLL, for the getaddrinfo() and getnameinfo() functions...
239 __wspiapi_set_entry( dll, __wspiapi_reference(__WSPIAPI_GETADDRINFO__) );
240 __wspiapi_set_entry( dll, __wspiapi_reference(__WSPIAPI_GETNAMEINFO__) );
244 { /* ...otherwise, initialize these remaining references, such
245 * that all three functions are marked as unsupported by any
246 * system DLL, and thus must be emulated, on demand, by use
247 * of <wspiapi.h> in-line code.
249 __wspiapi_reference(__WSPIAPI_GETADDRINFO__)->entry = NULL;
250 __wspiapi_reference(__WSPIAPI_GETNAMEINFO__)->entry = NULL;
254 /* Irrespective of whether initialization was performed on this
255 * occasion, or had been performed previously, we return the entry
256 * point address for the requested function, as it is now recorded
257 * in the wspiapi reference dictionary.
259 return __wspiapi_reference( index )->entry;
262 /* __wspiapi_freeaddrinfo(): fall-back implementation for freeaddrinfo(),
263 * invoked by WspiapiFreeAddrInfo(), if (and only if), there is no native
264 * implementation provided in WS2_32.DLL, or by way of WSHIP6.DLL, from
265 * the Win2K IPv6 Technology Preview.
268 WSAAPI void __wspiapi_freeaddrinfo( struct addrinfo *ai_chain )
270 /* This must free all addrinfo records on a single chain, which has been
271 * allocated by a prior call of __wspiapi_getaddrinfo(); note that it is
272 * necessary to free any associated ai_canonname records, which have been
273 * independently allocated, but not any ai_addr records, as these are all
274 * allocated as integral elements of the owner addrinfo record itself.
276 while( ai_chain != NULL )
277 { struct addrinfo *next = ai_chain->ai_next;
278 free( ai_chain->ai_canonname ); free( ai_chain );
283 /* __wspiapi_addrinfo_cleanup(): a local helper function, called only by
284 * __wspiapi_getaddrinfo(), to clean up any partially allocated addrinfo
285 * record chain, in the event of __wspiapi_getaddrinfo() failure.
287 static __inline__ __attribute__((__always_inline__))
288 struct addrinfo *__wspiapi_addrinfo_cleanup( struct addrinfo *ai_chain )
289 { __wspiapi_freeaddrinfo( ai_chain ); return NULL; }
291 /* __wspiapi_getaddrinfo_internal(): core implementation for, and called
292 * exclusively by, __wspiapi_getaddrinfo(); returns zero on success, or
293 * an EAI error code, (but without updating WSAGetLastError() status),
297 __attribute__((__always_inline__))
298 int __wspiapi_getaddrinfo_internal
299 ( const char *__restrict__ nodename, const char *__restrict__ servname,
300 const struct addrinfo *__restrict__ hints, struct addrinfo **__restrict__ res
302 { /* Either nodename, or servname, but not both, may be NULL; initially
303 * assign status to reflect the invalid condition of both being NULL.
305 int status = EAI_NONAME;
307 /* Initialize a local template, from which each allocated resultant
308 * addrinfo record may be derived.
310 struct ai { struct addrinfo ai; struct sockaddr_in sa; } ai_data;
311 memset( &ai_data, 0, sizeof( struct ai ) );
313 /* Ensure that the state of the resultant addrinfo record chain will
314 * be sane, in the event of early failure.
318 /* The hints may be NULL, (in which case the initial template state
319 * will prevail), but if specified...
322 { /* ...then its ai_addr, ai_canonname, and ai_next fields MUST all
323 * be NULL, and ai_addrlen MUST be zero.
325 if( (hints->ai_addr != NULL) || (hints->ai_addrlen != 0)
326 || (hints->ai_next != NULL) || (hints->ai_canonname != NULL) )
329 /* Only the IPv4 AF_INET ai_family is supported, (but we tolerate
330 * AF_UNSPEC as implying AF_INET).
332 switch( ai_data.ai.ai_family = hints->ai_family )
333 { case AF_UNSPEC: case AF_INET: break; default: return EAI_FAMILY; }
335 /* Protocol and socket type may each be specified explicitly, or
336 * implicitly, (by default, or by wild-card assignment; supported
337 * protocols are TCP and UDP...
339 switch( ai_data.ai.ai_protocol = hints->ai_protocol )
342 /* ...where an explicit choice of TCP must be associated with
343 * a stream type socket...
345 switch( hints->ai_socktype )
346 { /* ...which again, may be either explicitly assigned, or
347 * implicitly deduced.
349 case SOCK_STREAM: case __WSPIAPI_SOCK_ANY:
350 ai_data.ai.ai_socktype = SOCK_STREAM;
353 /* Any other explicit pairing results in failure.
355 default: return EAI_SOCKTYPE;
360 /* Similarly, an explicit protocol choice must be paired,
361 * explicitly or implicitly, with a datagram socket.
363 switch( hints->ai_socktype )
364 { case SOCK_DGRAM: case __WSPIAPI_SOCK_ANY:
365 ai_data.ai.ai_socktype = SOCK_DGRAM;
368 /* Once again, any other explicit pairing is invalid.
370 default: return EAI_SOCKTYPE;
374 case __WSPIAPI_IPPROTO_ANY:
375 /* Without an explicit protocol specification, we may need
376 * to infer a match for the socket type...
378 switch( ai_data.ai.ai_socktype = hints->ai_socktype )
380 /* ...pairing TCP with an explicit stream socket...
383 ai_data.ai.ai_protocol = IPPROTO_TCP;
386 /* ...UDP with a datagram socket...
389 ai_data.ai.ai_protocol = IPPROTO_UDP;
391 /* ...or fall through, to enable generation of an addrinfo
392 * list, with all supported valid pairings.
394 case __WSPIAPI_SOCK_ANY: break;
396 /* Bail out, if any unsupported socket type is explicitly
399 default: return EAI_SOCKTYPE;
403 /* ...and likewise, for any unsupported protocol.
405 default: return EAI_SOCKTYPE;
408 /* Simply propagate whatever flags may have been specified, but
409 * defer any validation of them, until later.
411 ai_data.ai.ai_flags = hints->ai_flags;
414 /* Only the IPv4 address family is supported; whether confirmed in
415 * the hints, or left unspecified, we may stipulate that now.
417 ai_data.ai.ai_family = ai_data.sa.sin_family = AF_INET;
419 /* The servname argument may be NULL, but when it is specified, and
420 * it is a non-empty string...
422 if( (servname != NULL) && (*servname != '\0') )
423 { /* ...first try to interpret it as a textual representation of a
424 * service port number...
426 struct servent *pi; char *brk;
427 ai_data.sa.sin_port = strtoul( servname, &brk, 0 );
428 if( *brk == '\0' ) pi = getservbyport( htons( ai_data.sa.sin_port ), NULL );
430 /* ...or, failing that, a well known service name, which may be
431 * mapped to such a port number, or else bail out.
433 else pi = getservbyname( servname, NULL );
434 if( pi == NULL ) return EAI_SERVICE;
436 /* When the servname argument has been successfully interpreted,
437 * store the port number within the addrinfo template, and reset
438 * the return status, to indicate that the minimal requirement
439 * for at least one of servname and nodename is non-NULL.
441 ai_data.sa.sin_port = pi->s_port;
445 /* Similarly, the nodename argument may be NULL, but when it is
446 * specified, and is non-empty...
448 if( (nodename != NULL) && (*nodename != '\0') )
449 { /* ...then we first attempt to interpret it as a representation,
450 * in textual format, of an IPv4 address.
452 unsigned long *addr = (unsigned long *)(&(ai_data.sa.sin_addr));
453 if( (*addr = inet_addr( nodename )) != INADDR_NONE )
455 /* We've interpreted, and stored, a valid IPv4 address; this
456 * isn't, strictly, a node name; it is valid, in this context,
457 * but association with a canonical name is disallowed.
459 if( (ai_data.ai.ai_flags & AI_CANONNAME) == AI_CANONNAME )
462 /* When the IPv4 address form is accepted, we may immediately
463 * reset the return status, since the requirement for at least
464 * one nodename, or servname, to be non-NULL is satisfied.
468 else if( (ai_data.ai.ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST )
470 /* No numeric IPv4 address was specified, but with this flag
471 * one becomes a mandatory requirement; bail out.
476 { /* The specified nodename could not be interpreted as an IPv4
477 * address, (but was not required to be); resolve it as a host
478 * name, to obtain the corresponding IPv4 address.
480 struct hostent *hi = gethostbyname( nodename );
483 /* Name resolution was successful; update the template data
484 * to reflect the size of an IPv4 socket data structure, and
485 * store the resolved IPv4 address.
487 * FIXME: is it necessary to adapt this, to process a list
488 * comprising more than one resolved IPv4 address?
490 ai_data.ai.ai_addrlen = sizeof( struct sockaddr );
491 ai_data.sa.sin_addr = **(struct in_addr **)(hi->h_addr_list);
493 /* Also, if requested, capture the resolved canonical host
494 * name, but fail if there is insufficient memory.
496 if( ((ai_data.ai.ai_flags & AI_CANONNAME) == AI_CANONNAME)
497 && ((ai_data.ai.ai_canonname = strdup( hi->h_name )) == NULL) )
500 /* On successfully updating the template, to reflect all
501 * data associated with the resolved nodename, reset the
502 * exit status to indicate success.
508 else if( status == 0 )
509 { /* The nodename argument was effectively NULL, but we are able
510 * to proceed due to prior interpretation of a non-NULL servname
511 * argument; assign default addresses...
513 if( ((ai_data.ai.ai_flags & AI_PASSIVE) == AI_PASSIVE) )
514 { /* ...corresponding to the wild-card address for any passive
517 ai_data.sa.sin_addr.s_addr = INADDR_ANY;
520 { /* ...or the loopback address, for non-passive connections.
522 ai_data.sa.sin_addr.s_addr = INADDR_LOOPBACK;
526 /* Provided the return status code has been reset to zero, from
527 * its initial EAI_NONAME value...
530 { /* ...we should now have a suitably initialized template, from
531 * which we may construct the linked list of matching addrinfo
532 * structures to be returned. Each list entry is separately
533 * allocated, using the local pai pointer to track insertion
534 * point, selecting protocol and socket type pairings from the
535 * indexed list, working from TCP (at index two), back towards
536 * the wild-card protocol match (at index zero), and passing
537 * through UDP (at index one), until we reach the protocol as
538 * specified in the template; note that this will generate a
539 * single entry of TCP, or UDP, when either is specified as an
540 * explicit match requirement, but will generate three entries,
541 * matching each of TCP, UDP, and ANY, when a wild-card match
544 struct ai *pai = NULL;
545 int ref = (ai_data.ai.ai_protocol == IPPROTO_UDP) ? 1 : 2;
546 struct { int protocol; int socktype; } map[] =
547 { { __WSPIAPI_IPPROTO_ANY, __WSPIAPI_SOCK_ANY },
548 { IPPROTO_UDP, SOCK_DGRAM }, { IPPROTO_TCP, SOCK_STREAM }
550 do { if( pai == NULL )
551 { /* When pai is in its initial NULL state, the entry to
552 * be generated may be assigned directly to the head of
555 pai = ((struct ai *)(malloc( sizeof ai_data )));
556 *res = (struct addrinfo *)(pai);
558 /* ...otherwise we link it as ai_next successor to the
559 * previously allocated entry.
562 { pai->ai.ai_next = (struct addrinfo *)(malloc( sizeof ai_data ));
563 pai = (struct ai *)(pai->ai.ai_next);
566 { /* When pai remains in, or reverts to, the NULL state,
567 * then allocation of memory for the list entry failed;
568 * clean up any partially allocated return data, before
571 *res = __wspiapi_addrinfo_cleanup( *res );
574 /* We got a successfully allocated block of memory for a
575 * list entry; populate it by copying the template...
579 /* ...then fix up the embedded sockaddr data reference,
580 * its protocol, and the socket type indicators.
582 pai->ai.ai_addr = (struct sockaddr *)(&(pai->sa.sin_family));
583 pai->ai.ai_protocol = map[ref].protocol;
584 pai->ai.ai_socktype = map[ref].socktype;
586 /* The template may initially include a canonical name
587 * reference; this is propagated to the first list entry
588 * only, so clear it prior to generating any more.
590 ai_data.ai.ai_canonname = NULL;
592 /* Go round again, until the addrinfo list has become
595 } while( map[ref--].protocol != ai_data.ai.ai_protocol );
597 /* Ultimately, return either the initially assumed EAI_NONAME
598 * failure status, or success.
603 /* __wspiapi_getaddrinfo(): a thin wrapper around the preceding
604 * in-line implementation; invoked by WspiapiGetAddrInfo() if, and
605 * only if, no getaddrinfo() implementation is identifiable within
606 * the host system's WS2_32.DLL, or WSHIP6.DLL
608 WSAAPI int __wspiapi_getaddrinfo (
609 const char *__restrict__ nodenam, const char *__restrict__ servnam,
610 const struct addrinfo *__restrict__ hints, struct addrinfo **__restrict__ res
612 { /* First ensure that a non-NULL reference pointer is provided, to
613 * pass the addrinfo result back to the caller, then delegate the
614 * call to the in-line handler, capturing its exit status, which
615 * is then propagated through the WSAGetLastError() API.
617 if( res == NULL ) return __wspiapi_syserrout( EINVAL );
618 { int status = __wspiapi_getaddrinfo_internal( nodenam, servnam, hints, res );
619 return (status == 0) ? 0 : __wspiapi_errout( status );
623 /* WspiapiGetAddrInfo(): getaddrinfo() function redirector, as
624 * prescribed by Microsoft's on-line documentation.
627 WSAAPI int WspiapiGetAddrInfo
628 ( const char *node, const char *service, const struct addrinfo *hints,
629 struct addrinfo **response_list
631 { /* Initialized to NULL, the redirector hook will be updated on
632 * first call, within the containing translation unit. This call
633 * will determine if it can be directed to an actual getaddrinfo()
634 * function implementation, provided by the system's WS2_32.DLL or
635 * WSHIP6.DLL libraries, initializing redirection for this first,
636 * and any subsequent call, to delegate to any such existing
637 * implementation, if available...
639 typedef WSAAPI int (*call)
640 ( const char *, const char *, const struct addrinfo *, struct addrinfo **
642 static call redirector_hook = NULL;
643 if( (redirector_hook == NULL)
644 && ((redirector_hook = __wspiapi_call(__WSPIAPI_GETADDRINFO__)) == NULL) )
646 /* ...or otherwise, to substitute the above fallback.
648 redirector_hook = __wspiapi_getaddrinfo;
650 /* Ultimately, every call is redirected to whichever handler has
651 * been selected by the preceding initialization.
653 return redirector_hook( node, service, hints, response_list );
656 /* getaddrinfo(): a static inline override for any external
657 * implementation of getaddrinfo(); ensures that corresponding
658 * function calls, within the translation unit file scope, are
659 * delegated to the fallback WspiapiGetAddrInfo() redirector.
661 static __inline__ __attribute__((__always_inline__))
662 WSAAPI int getaddrinfo( const char *node, const char *service,
663 const struct addrinfo *hints, struct addrinfo **response_list )
664 { return WspiapiGetAddrInfo( node, service, hints, response_list ); }
666 /* WspiapiFreeAddrInfo(): freeaddrinfo() function redirector, as
667 * prescribed by Microsoft's on-line documentation.
670 WSAAPI void WspiapiFreeAddrInfo( struct addrinfo *ai_chain )
672 /* Initialized to NULL, the redirector hook will be updated on
673 * first call, within the containing translation unit. This call
674 * will determine if it can be directed to an actual freeaddrinfo()
675 * function implementation, provided by the system's WS2_32.DLL or
676 * WSHIP6.DLL libraries, initializing redirection for this first,
677 * and any subsequent call, to delegate to any such existing
678 * implementation, if available...
680 typedef WSAAPI void (*call)(struct addrinfo *);
681 static call redirector_hook = NULL;
682 if( (redirector_hook == NULL)
683 && ((redirector_hook = __wspiapi_call(__WSPIAPI_FREEADDRINFO__)) == NULL) )
685 /* ...or otherwise, to substitute the above fallback.
687 redirector_hook = __wspiapi_freeaddrinfo;
689 /* Ultimately, every call is redirected to whichever handler has
690 * been selected by the preceding initialization.
692 redirector_hook( ai_chain );
695 /* freeaddrinfo(): a static inline override for any external
696 * implementation of freeaddrinfo(); ensures that corresponding
697 * function calls, within the translation unit file scope, are
698 * delegated to the fallback WspiapiFreeAddrInfo() redirector.
700 static __inline__ __attribute__((__always_inline__))
701 WSAAPI void freeaddrinfo (struct addrinfo *ai_chain)
702 { WspiapiFreeAddrInfo (ai_chain); }
704 /* __wspiapi_getservname(): helper to retrieve the standard name,
705 * if any, for the service nominally associated with any port which
706 * is specified by its number in network byte order.
708 static __inline__ __attribute__((__always_inline__))
709 char *__wspiapi_getservname( u_short port, int flags, char *service,
710 socklen_t servlen, socklen_t *retlen
712 { /* This look-up is suppressed, if NI_NUMERICSERV is included
713 * within the specified flags...
715 if( (flags & NI_NUMERICSERV) == 0 )
717 /* ...but, when allowed to proceed, we use the legacy windows
718 * getservbyport() function to perform the look-up...
720 struct servent *service_info;
721 service_info = getservbyport( port, (flags & NI_DGRAM) ? "udp" : NULL );
723 /* ...and then, provided a valid service name has been found,
724 * we transcribe it into the supplied buffer, for return.
726 if( (service_info != NULL) && (service_info->s_name != NULL) )
727 { *retlen = snprintf( service, servlen, "%s", service_info->s_name );
731 /* If, for whatever reason, no service name is to be returned,
732 * returning NULL will signal this.
737 /* __wspiapi_getnodename(): helper to perform a reverse DNS look-up,
738 * to retrieve, and nominally return, the fully qualified domain name
739 * which is associated with a specified IPv4 address.
741 static __inline__ __attribute__((__always_inline__))
742 char *__wspiapi_getnodename( struct in_addr *addr, int flags,
743 char *nodename, socklen_t nodelen, socklen_t *retlen
745 { /* This look-up is suppressed, when NI_NUMERICHOST is included
746 * within the specified flags...
748 if( (flags & NI_NUMERICHOST) == 0 )
750 /* ...but, when allowed to proceed, we use the legacy windows
751 * gethostbyaddr() function to perform the look-up...
753 struct hostent *node_info = gethostbyaddr(
754 (const char *)(addr), sizeof( struct in_addr ), AF_INET
757 /* ...and then, provided a valid host name has been found,
758 * we transcribe it into the supplied buffer, for return.
760 if( (node_info != NULL) && (node_info->h_name != NULL) )
761 { *retlen = snprintf( nodename, nodelen, "%s", node_info->h_name );
763 /* A special case arises, when NI_NOFQDN is included
764 * within the specified flags.
766 if( (flags & NI_NOFQDN) != 0 )
768 /* In this case, we must check for any period, as
769 * punctuation separating the host name itself from
772 char *brk = strchr( nodename, '.' );
775 /* ...and, when such punctuation is present, we
776 * truncate the return string at the first period,
777 * so leaving only the bare host name for return.
780 *retlen = brk - nodename;
783 /* Truncated, or otherwise, we may now return the host
784 * name, as retrieved.
789 /* If, for whatever reason, no host name is to be returned,
790 * returning NULL will signal this.
795 /* __wspiapi_getnameinfo_internal(): core implementation for, and called
796 * exclusively by, __wspiapi_getnameinfo(); returns zero on success, or
797 * an EAI error code, (but without updating WSAGetLastError() status),
801 __attribute__((__always_inline__))
802 int __wspiapi_getnameinfo_internal
803 ( const struct sockaddr *__restrict__ sa, socklen_t len,
804 char *__restrict__ node, socklen_t nodelen, char *__restrict__ service,
805 socklen_t servlen, int flags
807 { /* Either the service name, or the node name look-up may be omitted,
808 * but at least one MUST be performed; if neither is performed, as we
809 * may establish later, then we should fail with status EAI_NONAME.
811 int status = EAI_NONAME;
813 /* If support for IPv6 is available, then the system DLL will provide
814 * its own getnameinfo() implementation, and this fallback handler is
815 * not invoked; thus, we need only support the IPv4 address family.
817 if( sa->sa_family != AF_INET ) return EAI_FAMILY;
819 /* The "service" argument may be NULL, or its associated "servlen"
820 * may be zero; a service name look-up is performed, only if neither
821 * of these excluding conditions is satisfied.
823 if( (service != NULL) && (servlen > 0) )
825 /* When look-up is NOT excluded, we delegate it to our internal
826 * __wspiapi_getservname() helper, capturing the result into an
827 * intermediate buffer of the same length as has been declared
828 * for the returned result...
830 char servname[servlen];
831 u_short port = ((const struct sockaddr_in *)(sa))->sin_port;
832 if( __wspiapi_getservname( port, flags, servname, servlen, &len ) == NULL )
834 /* ...while noting that, if the look-up was unsuccessful, (or it
835 * was suppressed, because NI_NUMERICSERV was included within the
836 * specified flags), we substitute a string representation of the
837 * service port number.
839 len = snprintf( servname, servlen, "%u", ntohs( port ) );
841 /* Provided the declared buffer length is sufficient to accommodate
842 * the result of the look-up, we copy that result from intermediate
843 * storage to the designated return buffer...
845 if( servlen > len ) strcpy( service, servname );
847 /* ...but if it doesn't fit, we bail out, reporting overflow.
849 else return EAI_OVERFLOW;
851 /* We HAVE now performed a successful service name look-up, so we
852 * may clear our initial EAI_NONAME presumption.
857 /* The "node" argument may be NULL, or its associated "nodelen" may
858 * be zero; a node name look-up is performed, only if neither of
859 * these excluding conditions is satisfied.
861 if( (node != NULL) && (nodelen > 0) )
863 /* Perform the node name look-up, based on the IPv4 address as
864 * specified in the "sa" structure argument...
866 char nodename[nodelen];
867 struct in_addr addr = ((const struct sockaddr_in *)(sa))->sin_addr;
868 if( __wspiapi_getnodename( &addr, flags, nodename, nodelen, &len ) == NULL )
870 /* ...but on look-up failure, and if not required to succeed,
871 * (by specification of the NI_NAMEREQD flag)...
873 if( (flags & NI_NAMEREQD) != 0 ) return EAI_NONAME;
875 /* ...substitute the textual representation of the address.
877 len = snprintf( nodename, nodelen, "%s", inet_ntoa( addr ) );
879 /* Whether the name look-up was successful, or the address was
880 * substituted, if the return "node" buffer size is sufficient,
881 * copy the look-up result into place...
883 if( nodelen > len ) strcpy( node, nodename );
885 /* ...otherwise, bail out.
887 else return EAI_OVERFLOW;
889 /* If we get this far, the function has completed successfully.
893 /* If we didn't perform "node" name look-up, then the return state
894 * must be either the result of successful "service" resolution, or
895 * the initially assumed failure state.
900 /* __wspiapi_getnameinfo(): a thin wrapper around the preceding
901 * in-line implementation; invoked by WspiapiGetNameInfo() if, and
902 * only if, no getnameinfo() implementation is identifiable within
903 * the host system's WS2_32.DLL, or WSHIP6.DLL
906 WSAAPI int __wspiapi_getnameinfo
907 ( const struct sockaddr *__restrict__ sa, socklen_t len,
908 char *__restrict__ node, socklen_t nodelen, char *__restrict__ service,
909 socklen_t servlen, int flags
911 { /* The "sa" argument MUST NOT be NULL, and its declared length MUST
912 * match that of struct sockaddr. RFC 3493 doesn't prescribe how we
913 * should handle this case, but we choose to emulate the behaviour of
914 * Microsoft's invalid parameter handler, while reporting it as an
915 * EAI_SYSTEM exception.
917 if( (sa == NULL) || (len < (socklen_t)(sizeof( struct sockaddr ))) )
918 return __wspiapi_syserrout( EINVAL );
920 { /* When the "sa" argument is valid, we delegate the call to the
921 * preceding in-line handler, simply capturing its return status,
922 * and propagating it through the WSAGetLastError() API, as may
925 int status = __wspiapi_getnameinfo_internal
926 ( sa, len, node, nodelen, service, servlen, flags );
927 return (status == 0) ? 0 : __wspiapi_errout( status );
931 /* WspiapiGetNameInfo(): getnameinfo() function redirector, as
932 * prescribed by Microsoft's on-line documentation.
935 WSAAPI int WspiapiGetNameInfo
936 ( const struct sockaddr *__restrict__ addr, socklen_t len,
937 char *__restrict__ node, socklen_t nodelen, char *__restrict__ service,
938 socklen_t servlen, int flags
940 { /* Initialized to NULL, the redirector hook will be updated on
941 * first call, within the containing translation unit. This call
942 * will determine if it can be directed to an actual getnameinfo()
943 * function implementation, provided by the system's WS2_32.DLL or
944 * WSHIP6.DLL libraries, initializing redirection for this first,
945 * and any subsequent call, to delegate to any such existing
946 * implementation, if available...
948 typedef WSAAPI int (*call)
949 (const SOCKADDR *, socklen_t, char *, socklen_t, char *, socklen_t, int
951 static call redirector_hook = NULL;
952 if( (redirector_hook == NULL)
953 && ((redirector_hook = __wspiapi_call(__WSPIAPI_GETNAMEINFO__)) == NULL) )
955 /* ...or otherwise, to substitute the above fallback.
957 redirector_hook = __wspiapi_getnameinfo;
959 /* Ultimately, every call is redirected to whichever handler has
960 * been selected by the preceding initialization.
962 return redirector_hook( addr, len, node, nodelen, service, servlen, flags );
965 /* getnameinfo(): a static inline override for any external
966 * implementation of getnameinfo(); ensures that corresponding
967 * function calls, within the translation unit file scope, are
968 * delegated to the fallback WspiapiGetNameInfo() redirector.
970 static __inline__ __attribute__((__always_inline__))
971 WSAAPI int getnameinfo( const SOCKADDR *addr, socklen_t addrlen,
972 char *node, socklen_t nb_size, char *service, socklen_t sb_size, int flags
974 { return WspiapiGetNameInfo
975 (addr, addrlen, node, nb_size, service, sb_size, flags);
980 #endif /* !_WSPIAPI_H: $RCSfile$: end of file */