OSDN Git Service

d192e609dcffb9516b73afe4c95496069ac3e8ab
[mingw/mingw-org-wsl.git] / w32api / include / wspiapi.h
1 /*
2  * wspiapi.h
3  *
4  * Implementation for pre-WinXP getaddrinfo() and getnameinfo() APIs.
5  *
6  *
7  * $Id$
8  *
9  * Written by Keith Marshall <keith@users.osdn.me>
10  * Copyright (C) 2020, 2022, MinGW.OSDN Project
11  *
12  *
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:
19  *
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
22  * Software.
23  *
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.
31  *
32  *
33  * Author's Note:
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.
41  *
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.
49  *
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()
60  * function wrappers.
61  *
62  */
63 #ifndef _WSPIAPI_H
64 #pragma GCC system_header
65 #define _WSPIAPI_H
66
67 #include <stdio.h>
68 #include <ws2tcpip.h>
69
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.
73  */
74 #define __WSPIAPI_SOCK_ANY     0
75 #define __WSPIAPI_IPPROTO_ANY  0
76
77 _BEGIN_C_DECLS
78
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.
82  */
83 static __inline__ __attribute__((__always_inline__))
84 int __wspiapi_errout( int status ){ WSASetLastError( status ); return status; }
85
86 /* __wspiapi_syserrout(): variation on __wspiapi_errout(), returning
87  * EAI_SYSTEM, after assigning a specific system errno value.
88  */
89 static __inline__
90 __attribute__((__always_inline__))
91 int __wspiapi_syserrout( int errcode )
92 { errno = errcode; return __wspiapi_errout( EAI_SYSTEM ); }
93
94 /* enum __wspiapi: generate symbolic names for the entry point indices
95  * within the wspapi function reference dictionary.
96  */
97 enum __wspiapi
98 { __WSPIAPI_FREEADDRINFO__,
99   __WSPIAPI_GETADDRINFO__,
100   __WSPIAPI_GETNAMEINFO__
101 };
102
103 /* __wspiapi_t: a private use data type, describing the structure of
104  * each individual function reference within the dictionary.
105  */
106 typedef struct
107 { const char    *name;
108   void          *entry;
109 } __wspiapi_t;
110
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.
114  */
115 static __inline__ __attribute__((__always_inline__))
116 __wspiapi_t *__wspiapi_reference( enum __wspiapi index )
117 {
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.
122    */
123   static __wspiapi_t dictionary[] =
124   { { "freeaddrinfo", (void *)(-1) },
125     { "getaddrinfo",  (void *)(-1) },
126     { "getnameinfo",  (void *)(-1) }
127   };
128
129   /* The return value is simply a pointer to the dictionary entry
130    * corresponding to the specified index.
131    */
132   return dictionary + index;
133 }
134
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.
140  */
141 static __inline__ __attribute__((__always_inline__))
142 void __wspiapi_set_entry( HMODULE dll, __wspiapi_t *api )
143 { api->entry = (void *)(GetProcAddress( dll, api->name )); }
144
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.
148  */
149 static __inline__
150 HMODULE __wspiapi_module_handle
151 ( char *path, char *subst, const char *name, __wspiapi_t *api )
152 {
153   HMODULE ref;
154
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.
159    */
160   strcpy( subst, name );
161   if( (ref = LoadLibraryA( path )) != NULL )
162   {
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...
167      */
168     if( (api->entry = (void *)(GetProcAddress( ref, api->name ))) == NULL )
169     {
170       /* ...and declaring no further wspiapi interest in this DLL, if
171        * the requisite entry point is unavailable.
172        */
173       FreeLibrary( ref );
174       return NULL;
175     }
176   }
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.
181    */
182   return ref;
183 }
184
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.
193  */
194 static __inline__ __attribute__((__always_inline__))
195 HMODULE __wspiapi_lib( char *path, char *subst, const char *name )
196 {
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().
201    */
202   return  __wspiapi_module_handle(
203       path, subst, name, __wspiapi_reference(__WSPIAPI_FREEADDRINFO__)
204     );
205 }
206
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.
211  */
212 static __inline__
213 void *__wspiapi_entry( enum __wspiapi index )
214 # define __wspiapi_call( index ) (call)(__wspiapi_entry( index ))
215 {
216   /* First, check that the reference dictionary has been initialized,
217    * using the freeaddrinfo() entry point reference as witness.
218    */
219   if( __wspiapi_reference(__WSPIAPI_FREEADDRINFO__)->entry == (void *)(-1) )
220   {
221     /* The dictionary appears to be uninitialized; set up to perform
222      * entry point searches within DLLs in the system directory...
223      */
224     HMODULE dll;
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...
231        */
232       if( ((dll = __wspiapi_lib( sys_path, dllname, "\\ws2_32" )) != NULL)
233       ||  ((dll = __wspiapi_lib( sys_path, dllname, "\\wship6" )) != NULL)  )
234       {
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...
238          */
239         __wspiapi_set_entry( dll, __wspiapi_reference(__WSPIAPI_GETADDRINFO__) );
240         __wspiapi_set_entry( dll, __wspiapi_reference(__WSPIAPI_GETNAMEINFO__) );
241         FreeLibrary( dll );
242       }
243       else
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.
248          */
249         __wspiapi_reference(__WSPIAPI_GETADDRINFO__)->entry = NULL;
250         __wspiapi_reference(__WSPIAPI_GETNAMEINFO__)->entry = NULL;
251       }
252     }
253   }
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.
258    */
259   return __wspiapi_reference( index )->entry;
260 }
261
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.
266  */
267 static __inline__
268 WSAAPI void __wspiapi_freeaddrinfo( struct addrinfo *ai_chain )
269 {
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.
275    */
276   while( ai_chain != NULL )
277   { struct addrinfo *next = ai_chain->ai_next;
278     free( ai_chain->ai_canonname ); free( ai_chain );
279     ai_chain = next;
280   }
281 }
282
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.
286  */
287 static __inline__ __attribute__((__always_inline__))
288 struct addrinfo *__wspiapi_addrinfo_cleanup( struct addrinfo *ai_chain )
289 { __wspiapi_freeaddrinfo( ai_chain ); return NULL; }
290
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),
294  * on failure.
295  */
296 static __inline__
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
301 )
302 { /* Either nodename, or servname, but not both, may be NULL; initially
303    * assign status to reflect the invalid condition of both being NULL.
304    */
305   int status = EAI_NONAME;
306
307   /* Initialize a local template, from which each allocated resultant
308    * addrinfo record may be derived.
309    */
310   struct ai { struct addrinfo ai; struct sockaddr_in sa; } ai_data;
311   memset( &ai_data, 0, sizeof( struct ai ) );
312
313   /* Ensure that the state of the resultant addrinfo record chain will
314    * be sane, in the event of early failure.
315    */
316   *res = NULL;
317
318   /* The hints may be NULL, (in which case the initial template state
319    * will prevail), but if specified...
320    */
321   if( hints != NULL )
322   { /* ...then its ai_addr, ai_canonname, and ai_next fields MUST all
323      * be NULL, and ai_addrlen MUST be zero.
324      */
325     if( (hints->ai_addr != NULL) || (hints->ai_addrlen != 0)
326     ||  (hints->ai_next != NULL) || (hints->ai_canonname != NULL)  )
327       return EAI_FAIL;
328
329     /* Only the IPv4 AF_INET ai_family is supported, (but we tolerate
330      * AF_UNSPEC as implying AF_INET).
331      */
332     switch( ai_data.ai.ai_family = hints->ai_family )
333     { case AF_UNSPEC: case AF_INET: break; default: return EAI_FAMILY; }
334
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...
338      */
339     switch( ai_data.ai.ai_protocol = hints->ai_protocol )
340     {
341       case IPPROTO_TCP:
342         /* ...where an explicit choice of TCP must be associated with
343          * a stream type socket...
344          */
345         switch( hints->ai_socktype )
346         { /* ...which again, may be either explicitly assigned, or
347            * implicitly deduced.
348            */
349           case SOCK_STREAM: case __WSPIAPI_SOCK_ANY:
350             ai_data.ai.ai_socktype = SOCK_STREAM;
351             break;
352
353           /* Any other explicit pairing results in failure.
354            */
355           default: return EAI_SOCKTYPE;
356         }
357         break;
358
359       case IPPROTO_UDP:
360         /* Similarly, an explicit protocol choice must be paired,
361          * explicitly or implicitly, with a datagram socket.
362          */
363         switch( hints->ai_socktype )
364         { case SOCK_DGRAM: case __WSPIAPI_SOCK_ANY:
365             ai_data.ai.ai_socktype = SOCK_DGRAM;
366             break;
367
368           /* Once again, any other explicit pairing is invalid.
369            */
370           default: return EAI_SOCKTYPE;
371         }
372         break;
373
374       case __WSPIAPI_IPPROTO_ANY:
375         /* Without an explicit protocol specification, we may need
376          * to infer a match for the socket type...
377          */
378         switch( ai_data.ai.ai_socktype = hints->ai_socktype )
379         {
380           /* ...pairing TCP with an explicit stream socket...
381            */
382           case SOCK_STREAM:
383             ai_data.ai.ai_protocol = IPPROTO_TCP;
384             break;
385
386           /* ...UDP with a datagram socket...
387            */
388           case SOCK_DGRAM:
389             ai_data.ai.ai_protocol = IPPROTO_UDP;
390
391           /* ...or fall through, to enable generation of an addrinfo
392            * list, with all supported valid pairings.
393            */
394           case __WSPIAPI_SOCK_ANY: break;
395
396           /* Bail out, if any unsupported socket type is explicitly
397            * specified...
398            */
399           default: return EAI_SOCKTYPE;
400         }
401         break;
402
403       /* ...and likewise, for any unsupported protocol.
404        */
405       default: return EAI_SOCKTYPE;
406     }
407
408     /* Simply propagate whatever flags may have been specified, but
409      * defer any validation of them, until later.
410      */
411     ai_data.ai.ai_flags = hints->ai_flags;
412   }
413
414   /* Only the IPv4 address family is supported; whether confirmed in
415    * the hints, or left unspecified, we may stipulate that now.
416    */
417   ai_data.ai.ai_family = ai_data.sa.sin_family = AF_INET;
418
419   /* The servname argument may be NULL, but when it is specified, and
420    * it is a non-empty string...
421    */
422   if( (servname != NULL) && (*servname != '\0') )
423   { /* ...first try to interpret it as a textual representation of a
424      * service port number...
425      */
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 );
429
430     /* ...or, failing that, a well known service name, which may be
431      * mapped to such a port number, or else bail out.
432      */
433     else pi = getservbyname( servname, NULL );
434     if( pi == NULL ) return EAI_SERVICE;
435
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.
440      */
441     ai_data.sa.sin_port = pi->s_port;
442     status = 0;
443   }
444
445   /* Similarly, the nodename argument may be NULL, but when it is
446    * specified, and is non-empty...
447    */
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.
451      */
452     unsigned long *addr = (unsigned long *)(&(ai_data.sa.sin_addr));
453     if( (*addr = inet_addr( nodename )) != INADDR_NONE )
454     {
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.
458        */
459       if( (ai_data.ai.ai_flags & AI_CANONNAME) == AI_CANONNAME )
460         return EAI_BADFLAGS;
461
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.
465        */
466       status = 0;
467     }
468     else if( (ai_data.ai.ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST )
469     {
470       /* No numeric IPv4 address was specified, but with this flag
471        * one becomes a mandatory requirement; bail out.
472        */
473       return EAI_NONAME;
474     }
475     else
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.
479        */
480       struct hostent *hi = gethostbyname( nodename );
481       if( hi != NULL )
482       {
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.
486          *
487          * FIXME: is it necessary to adapt this, to process a list
488          * comprising more than one resolved IPv4 address?
489          */
490         ai_data.ai.ai_addrlen = sizeof( struct sockaddr );
491         ai_data.sa.sin_addr = **(struct in_addr **)(hi->h_addr_list);
492
493         /* Also, if requested, capture the resolved canonical host
494          * name, but fail if there is insufficient memory.
495          */
496         if( ((ai_data.ai.ai_flags & AI_CANONNAME) == AI_CANONNAME)
497         &&  ((ai_data.ai.ai_canonname = strdup( hi->h_name )) == NULL) )
498           return EAI_MEMORY;
499
500         /* On successfully updating the template, to reflect all
501          * data associated with the resolved nodename, reset the
502          * exit status to indicate success.
503          */
504         status = 0;
505       }
506     }
507   }
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...
512      */
513     if( ((ai_data.ai.ai_flags & AI_PASSIVE) == AI_PASSIVE) )
514     { /* ...corresponding to the wild-card address for any passive
515        * connection...
516        */
517       ai_data.sa.sin_addr.s_addr = INADDR_ANY;
518     }
519     else
520     { /* ...or the loopback address, for non-passive connections.
521        */
522       ai_data.sa.sin_addr.s_addr = INADDR_LOOPBACK;
523     }
524   }
525
526   /* Provided the return status code has been reset to zero, from
527    * its initial EAI_NONAME value...
528    */
529   if( status == 0 )
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
542      * is specified.
543      */
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 }
549     };
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
553             * the return list...
554             */
555            pai = ((struct ai *)(malloc( sizeof ai_data )));
556            *res = (struct addrinfo *)(pai);
557          }
558          /* ...otherwise we link it as ai_next successor to the
559           * previously allocated entry.
560           */
561          else
562          { pai->ai.ai_next = (struct addrinfo *)(malloc( sizeof ai_data ));
563            pai = (struct ai *)(pai->ai.ai_next);
564          }
565          if( pai == NULL )
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
569             * bailing out.
570             */
571            *res = __wspiapi_addrinfo_cleanup( *res );
572            return EAI_MEMORY;
573          }
574          /* We got a successfully allocated block of memory for a
575           * list entry; populate it by copying the template...
576           */
577          *pai = ai_data;
578
579          /* ...then fix up the embedded sockaddr data reference,
580           * its protocol, and the socket type indicators.
581           */
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;
585
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.
589           */
590          ai_data.ai.ai_canonname = NULL;
591
592          /* Go round again, until the addrinfo list has become
593           * fully populated.
594           */
595        } while( map[ref--].protocol != ai_data.ai.ai_protocol );
596   }
597   /* Ultimately, return either the initially assumed EAI_NONAME
598    * failure status, or success.
599    */
600   return status;
601 }
602
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
607  */
608 WSAAPI int __wspiapi_getaddrinfo (
609   const char *__restrict__ nodenam, const char *__restrict__ servnam,
610   const struct addrinfo *__restrict__ hints, struct addrinfo **__restrict__ res
611 )
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.
616    */
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 );
620   }
621 }
622
623 /* WspiapiGetAddrInfo(): getaddrinfo() function redirector, as
624  * prescribed by Microsoft's on-line documentation.
625  */
626 static __inline__
627 WSAAPI int WspiapiGetAddrInfo
628 ( const char *node, const char *service, const struct addrinfo *hints,
629   struct addrinfo **response_list
630 )
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...
638    */
639   typedef WSAAPI int (*call)
640     ( const char *, const char *, const struct addrinfo *, struct addrinfo **
641     );
642   static call redirector_hook = NULL;
643   if(  (redirector_hook == NULL)
644   &&  ((redirector_hook = __wspiapi_call(__WSPIAPI_GETADDRINFO__)) == NULL)  )
645
646     /* ...or otherwise, to substitute the above fallback.
647      */
648     redirector_hook = __wspiapi_getaddrinfo;
649
650   /* Ultimately, every call is redirected to whichever handler has
651    * been selected by the preceding initialization.
652    */
653   return redirector_hook( node, service, hints, response_list );
654 }
655
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.
660  */
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 ); }
665
666 /* WspiapiFreeAddrInfo(): freeaddrinfo() function redirector, as
667  * prescribed by Microsoft's on-line documentation.
668  */
669 static __inline__
670 WSAAPI void WspiapiFreeAddrInfo( struct addrinfo *ai_chain )
671 {
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...
679    */
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)  )
684
685     /* ...or otherwise, to substitute the above fallback.
686      */
687     redirector_hook = __wspiapi_freeaddrinfo;
688
689   /* Ultimately, every call is redirected to whichever handler has
690    * been selected by the preceding initialization.
691    */
692   redirector_hook( ai_chain );
693 }
694
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.
699  */
700 static __inline__ __attribute__((__always_inline__))
701 WSAAPI void freeaddrinfo (struct addrinfo *ai_chain)
702 { WspiapiFreeAddrInfo (ai_chain); }
703
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.
707  */
708 static __inline__ __attribute__((__always_inline__))
709 char *__wspiapi_getservname( u_short port, int flags, char *service,
710   socklen_t servlen, socklen_t *retlen
711 )
712 { /* This look-up is suppressed, if NI_NUMERICSERV is included
713    * within the specified flags...
714    */
715   if( (flags & NI_NUMERICSERV) == 0 )
716   {
717     /* ...but, when allowed to proceed, we use the legacy windows
718      * getservbyport() function to perform the look-up...
719      */
720     struct servent *service_info;
721     service_info = getservbyport( port, (flags & NI_DGRAM) ? "udp" : NULL );
722
723     /* ...and then, provided a valid service name has been found,
724      * we transcribe it into the supplied buffer, for return.
725      */
726     if( (service_info != NULL) && (service_info->s_name != NULL) )
727     { *retlen = snprintf( service, servlen, "%s", service_info->s_name );
728       return service;
729     }
730   }
731   /* If, for whatever reason, no service name is to be returned,
732    * returning NULL will signal this.
733    */
734   return NULL;
735 }
736
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.
740  */
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
744 )
745 { /* This look-up is suppressed, when NI_NUMERICHOST is included
746    * within the specified flags...
747    */
748   if( (flags & NI_NUMERICHOST) == 0 )
749   {
750     /* ...but, when allowed to proceed, we use the legacy windows
751      * gethostbyaddr() function to perform the look-up...
752      */
753     struct hostent *node_info = gethostbyaddr(
754         (const char *)(addr), sizeof( struct in_addr ), AF_INET
755       );
756
757     /* ...and then, provided a valid host name has been found,
758      * we transcribe it into the supplied buffer, for return.
759      */
760     if( (node_info != NULL) && (node_info->h_name != NULL) )
761     { *retlen = snprintf( nodename, nodelen, "%s", node_info->h_name );
762
763       /* A special case arises, when NI_NOFQDN is included
764        * within the specified flags.
765        */
766       if( (flags & NI_NOFQDN) != 0 )
767       {
768         /* In this case, we must check for any period, as
769          * punctuation separating the host name itself from
770          * its domain name...
771          */
772         char *brk = strchr( nodename, '.' );
773         if( brk != NULL )
774         {
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.
778            */
779           *brk = '\0';
780           *retlen = brk - nodename;
781         }
782       }
783       /* Truncated, or otherwise, we may now return the host
784        * name, as retrieved.
785        */
786       return nodename;
787     }
788   }
789   /* If, for whatever reason, no host name is to be returned,
790    * returning NULL will signal this.
791    */
792   return NULL;
793 }
794
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),
798  * on failure.
799  */
800 static __inline__
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
806 )
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.
810    */
811   int status = EAI_NONAME;
812
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.
816    */
817   if( sa->sa_family != AF_INET ) return EAI_FAMILY;
818
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.
822    */
823   if( (service != NULL) && (servlen > 0) )
824   {
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...
829      */
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 )
833
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.
838        */
839       len = snprintf( servname, servlen, "%u", ntohs( port ) );
840
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...
844      */
845     if( servlen > len ) strcpy( service, servname );
846
847     /* ...but if it doesn't fit, we bail out, reporting overflow.
848      */
849     else return EAI_OVERFLOW;
850
851     /* We HAVE now performed a successful service name look-up, so we
852      * may clear our initial EAI_NONAME presumption.
853      */
854     status = 0;
855   }
856
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.
860    */
861   if( (node != NULL) && (nodelen > 0) )
862   {
863     /* Perform the node name look-up, based on the IPv4 address as
864      * specified in the "sa" structure argument...
865      */
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 )
869     {
870       /* ...but on look-up failure, and if not required to succeed,
871        * (by specification of the NI_NAMEREQD flag)...
872        */
873       if( (flags & NI_NAMEREQD) != 0 ) return  EAI_NONAME;
874
875       /* ...substitute the textual representation of the address.
876        */
877       len = snprintf( nodename, nodelen, "%s", inet_ntoa( addr ) );
878     }
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...
882      */
883     if( nodelen > len ) strcpy( node, nodename );
884
885     /* ...otherwise, bail out.
886      */
887     else return EAI_OVERFLOW;
888
889     /* If we get this far, the function has completed successfully.
890      */
891     return 0;
892   }
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.
896    */
897   return status;
898 }
899
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
904  */
905 static __inline__
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
910 )
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.
916    */
917   if( (sa == NULL) || (len < (socklen_t)(sizeof( struct sockaddr ))) )
918     return __wspiapi_syserrout( EINVAL );
919
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
923      * be appropriate.
924      */
925     int status = __wspiapi_getnameinfo_internal
926     ( sa, len, node, nodelen, service, servlen, flags );
927     return (status == 0) ? 0 : __wspiapi_errout( status );
928   }
929 }
930
931 /* WspiapiGetNameInfo(): getnameinfo() function redirector, as
932  * prescribed by Microsoft's on-line documentation.
933  */
934 static __inline__
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
939 )
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...
947    */
948   typedef WSAAPI int (*call)
949     (const SOCKADDR *, socklen_t, char *, socklen_t, char *, socklen_t, int
950     );
951   static call redirector_hook = NULL;
952   if(  (redirector_hook == NULL)
953   &&  ((redirector_hook = __wspiapi_call(__WSPIAPI_GETNAMEINFO__)) == NULL)  )
954
955     /* ...or otherwise, to substitute the above fallback.
956      */
957     redirector_hook = __wspiapi_getnameinfo;
958
959   /* Ultimately, every call is redirected to whichever handler has
960    * been selected by the preceding initialization.
961    */
962   return redirector_hook( addr, len, node, nodelen, service, servlen, flags );
963 }
964
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.
969  */
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
973 )
974 { return WspiapiGetNameInfo
975   (addr, addrlen, node, nb_size, service, sb_size, flags);
976 }
977
978 _END_C_DECLS
979
980 #endif  /* !_WSPIAPI_H: $RCSfile$: end of file */