/*
- * ws2tcpip.h : TCP/IP specific extensions in Windows Sockets 2
+ * ws2tcpip.h
+ *
+ * TCP/IP specific extensions to the Windows Sockets API v2
+ *
+ *
+ * $Id$
+ *
+ * Contributed by Danny Smith <dannysmith@users.sourceforge.net>
+ * Copyright (C) 2001-2003, 2005-2008, 2020, MinGW.org Project
*
* Portions Copyright (c) 1980, 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
*/
-
#ifndef _WS2TCPIP_H
-#define _WS2TCPIP_H
-#if __GNUC__ >=3
#pragma GCC system_header
-#endif
+#define _WS2TCPIP_H
-#if (defined _WINSOCK_H && !defined _WINSOCK2_H)
-#error "ws2tcpip.h is not compatible with winsock.h. Include winsock2.h instead."
+#if defined _WINSOCK_H && ! defined _WINSOCK2_H
+#error "ws2tcpip.h is not compatible with winsock.h; include winsock2.h instead."
#endif
#include <winsock2.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * The IP_* macros are also defined in winsock.h, but some values are different there.
- * The values defined in winsock.h for 1.1 and used in wsock32.dll are consistent
- * with the original values Steve Deering defined in his document "IP Multicast Extensions
- * for 4.3BSD UNIX related systems (MULTICAST 1.2 Release)." However, these conflicted with
- * the definitions for some IPPROTO_IP level socket options already assigned by BSD,
- * so Berkeley changed all the values by adding 7. WinSock2 (ws2_32.dll) uses
+_BEGIN_C_DECLS
+
+/* The IP_* macros are also defined in winsock.h, but some values are different there.
+ * The values defined in winsock.h for 1.1 and used in wsock32.dll are consistent with
+ * the original values Steve Deering defined in his document, "IP Multicast Extensions
+ * for 4.3BSD UNIX related systems (MULTICAST 1.2 Release)". However, these conflict
+ * with the definitions for some IPPROTO_IP level socket options already assigned by
+ * BSD, so Berkeley changed all the values by adding 7. WinSock2 (ws2_32.dll) uses
* the BSD 4.4 compatible values defined here.
*
* See also: msdn kb article Q257460
* http://support.microsoft.com/support/kb/articles/Q257/4/60.asp
*/
-
-/* This is also defined in winsock.h; value hasn't changed */
-#define IP_OPTIONS 1
-
-#define IP_HDRINCL 2
-/*
- * These are also be defined in winsock.h,
- * but values have changed for WinSock2 interface
- */
-#define IP_TOS 3 /* old (winsock 1.1) value 8 */
-#define IP_TTL 4 /* old value 7 */
-#define IP_MULTICAST_IF 9 /* old value 2 */
-#define IP_MULTICAST_TTL 10 /* old value 3 */
-#define IP_MULTICAST_LOOP 11 /* old value 4 */
-#define IP_ADD_MEMBERSHIP 12 /* old value 5 */
-#define IP_DROP_MEMBERSHIP 13 /* old value 6 */
-#define IP_DONTFRAGMENT 14 /* old value 9 */
-#define IP_ADD_SOURCE_MEMBERSHIP 15
-#define IP_DROP_SOURCE_MEMBERSHIP 16
-#define IP_BLOCK_SOURCE 17
-#define IP_UNBLOCK_SOURCE 18
-#define IP_PKTINFO 19
-
-/*
- * As with BSD implementation, IPPROTO_IPV6 level socket options have
- * same values as IPv4 counterparts.
+#define IP_OPTIONS 1 /* unchanged from WinSock v1.1 */
+#define IP_HDRINCL 2 /* unchanged from WinSock v1.1 */
+#define IP_TOS 3 /* had value 8 in WinSock v1.1 */
+#define IP_TTL 4 /* had value 7 in WinSock v1.1 */
+#define IP_MULTICAST_IF 9 /* had value 2 in WinSock v1.1 */
+#define IP_MULTICAST_TTL 10 /* had value 3 in WinSock v1.1 */
+#define IP_MULTICAST_LOOP 11 /* had value 4 in WinSock v1.1 */
+#define IP_ADD_MEMBERSHIP 12 /* had value 5 in WinSock v1.1 */
+#define IP_DROP_MEMBERSHIP 13 /* had value 6 in WinSock v1.1 */
+#define IP_DONTFRAGMENT 14 /* had value 9 in WinSock v1.1 */
+#define IP_ADD_SOURCE_MEMBERSHIP 15 /* undefined in WinSock v1.1 */
+#define IP_DROP_SOURCE_MEMBERSHIP 16 /* undefined in WinSock v1.1 */
+#define IP_BLOCK_SOURCE 17 /* undefined in WinSock v1.1 */
+#define IP_UNBLOCK_SOURCE 18 /* undefined in WinSock v1.1 */
+#define IP_PKTINFO 19 /* undefined in WinSock v1.1 */
+
+/* As with BSD implementation, IPPROTO_IPV6 level socket options have
+ * the same values as their IPv4 counterparts.
*/
-#define IPV6_UNICAST_HOPS 4
-#define IPV6_MULTICAST_IF 9
-#define IPV6_MULTICAST_HOPS 10
-#define IPV6_MULTICAST_LOOP 11
-#define IPV6_ADD_MEMBERSHIP 12
-#define IPV6_DROP_MEMBERSHIP 13
-#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
-#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
-#define IPV6_PKTINFO 19
+#define IPV6_UNICAST_HOPS 4
+#define IPV6_MULTICAST_IF 9
+#define IPV6_MULTICAST_HOPS 10
+#define IPV6_MULTICAST_LOOP 11
+#define IPV6_ADD_MEMBERSHIP 12
+#define IPV6_DROP_MEMBERSHIP 13
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#define IPV6_PKTINFO 19
-#define IP_DEFAULT_MULTICAST_TTL 1
-#define IP_DEFAULT_MULTICAST_LOOP 1
-#define IP_MAX_MEMBERSHIPS 20
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+#define IP_MAX_MEMBERSHIPS 20
-#define TCP_EXPEDITED_1122 2
+#define TCP_EXPEDITED_1122 2
-#define UDP_NOCHECKSUM 1
+#define UDP_NOCHECKSUM 1
-/* INTERFACE_INFO iiFlags */
-#define IFF_UP 1
-#define IFF_BROADCAST 2
-#define IFF_LOOPBACK 4
-#define IFF_POINTTOPOINT 8
-#define IFF_MULTICAST 16
+/* INTERFACE_INFO iiFlags
+ */
+#define IFF_UP 1
+#define IFF_BROADCAST 2
+#define IFF_LOOPBACK 4
+#define IFF_POINTTOPOINT 8
+#define IFF_MULTICAST 16
-#define SIO_GET_INTERFACE_LIST _IOR('t', 127, u_long)
+#define SIO_GET_INTERFACE_LIST _IOR('t', 127, u_long)
-#define INET_ADDRSTRLEN 16
-#define INET6_ADDRSTRLEN 46
+/* Minimum buffer sizes required, to store any arbitrary IPv4,
+ * or IPv6 address, respectively, in string format.
+ */
+#define INET_ADDRSTRLEN 16
+#define INET6_ADDRSTRLEN 46
-/* getnameinfo constants */
-#define NI_MAXHOST 1025
-#define NI_MAXSERV 32
+/* Constants for use when calling the getnameinfo() function;
+ * first, the recommended lengths for host-name and service-name
+ * return data buffers...
+ */
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+/* ...and also, symbolic names for the flags argument bits.
+ */
#define NI_NOFQDN 0x01
#define NI_NUMERICHOST 0x02
#define NI_NAMEREQD 0x04
#define NI_NUMERICSERV 0x08
#define NI_DGRAM 0x10
-/* getaddrinfo constants */
-#define AI_PASSIVE 1
-#define AI_CANONNAME 2
-#define AI_NUMERICHOST 4
-
-/* getaddrinfo error codes */
-#define EAI_AGAIN WSATRY_AGAIN
-#define EAI_BADFLAGS WSAEINVAL
-#define EAI_FAIL WSANO_RECOVERY
-#define EAI_FAMILY WSAEAFNOSUPPORT
-#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
-#define EAI_NODATA WSANO_DATA
-#define EAI_NONAME WSAHOST_NOT_FOUND
-#define EAI_SERVICE WSATYPE_NOT_FOUND
-#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
-
-/*
- * ip_mreq also in winsock.h for WinSock1.1,
- * but online msdn docs say it is defined here for WinSock2.
+/* Options which may be passed, as inclusive-or bit flags, in
+ * the hints->ai_flags argument, to getaddrinfo()
*/
-
-struct ip_mreq {
- struct in_addr imr_multiaddr;
- struct in_addr imr_interface;
+#define AI_PASSIVE 1
+#define AI_CANONNAME 2
+#define AI_NUMERICHOST 4
+
+/* Error codes which may be returned by the getaddrinfo() and
+ * getnameinfo() functions. These are the symbolic names which
+ * conform to IETF convention; each represents, and is mapped
+ * to, a corresponding WinSock error condition.
+ */
+#define EAI_AGAIN WSATRY_AGAIN
+#define EAI_BADFLAGS WSAEINVAL
+#define EAI_FAIL WSANO_RECOVERY
+#define EAI_FAMILY WSAEAFNOSUPPORT
+#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
+#define EAI_NODATA WSANO_DATA
+#define EAI_NONAME WSAHOST_NOT_FOUND
+#define EAI_OVERFLOW WSAENAMETOOLONG
+#define EAI_SERVICE WSATYPE_NOT_FOUND
+#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
+#define EAI_SYSTEM WSASYSCALLFAILURE
+
+/* The ip_mreq structure is also required by WinSock v1.1, for
+ * which case it is declared in <winsock.h>, since the definition
+ * here is visible only to WinSock v2 applications which include
+ * this <ws2tcpip.h> header file.
+ */
+struct ip_mreq
+{ struct in_addr imr_multiaddr;
+ struct in_addr imr_interface;
};
-struct ip_mreq_source {
- struct in_addr imr_multiaddr;
- struct in_addr imr_sourceaddr;
- struct in_addr imr_interface;
+struct ip_mreq_source
+{ struct in_addr imr_multiaddr;
+ struct in_addr imr_sourceaddr;
+ struct in_addr imr_interface;
};
-struct ip_msfilter {
- struct in_addr imsf_multiaddr;
- struct in_addr imsf_interface;
- u_long imsf_fmode;
- u_long imsf_numsrc;
- struct in_addr imsf_slist[1];
+struct ip_msfilter
+{ struct in_addr imsf_multiaddr;
+ struct in_addr imsf_interface;
+ u_long imsf_fmode;
+ u_long imsf_numsrc;
+ struct in_addr imsf_slist[1];
};
-#define IP_MSFILTER_SIZE(numsrc) \
- (sizeof(struct ip_msfilter) - sizeof(struct in_addr) \
- + (numsrc) * sizeof(struct in_addr))
-
-struct in_pktinfo {
- IN_ADDR ipi_addr;
- UINT ipi_ifindex;
-};
-typedef struct in_pktinfo IN_PKTINFO;
+#define IP_MSFILTER_SIZE(numsrc) \
+ ( sizeof( struct ip_msfilter ) - sizeof( struct in_addr ) \
+ + (numsrc) * sizeof( struct in_addr ) \
+ )
+typedef
+struct in_pktinfo
+{ IN_ADDR ipi_addr;
+ UINT ipi_ifindex;
+} IN_PKTINFO;
-/* ipv6 */
-/* These require XP or .NET Server or use of add-on IPv6 stacks on NT 4
- or higher */
-
-/* This is based on the example given in RFC 2553 with stdint types
- changed to BSD types. For now, use these field names until there
- is some consistency in MS docs. In this file, we only use the
- in6_addr structure start address, with casts to get the right offsets
- when testing addresses */
-
-struct in6_addr {
- union {
- u_char _S6_u8[16];
- u_short _S6_u16[8];
- u_long _S6_u32[4];
- } _S6_un;
+/* IPv6
+ *
+ * This implementation requires WinXP or .NET Server or use of add-on
+ * IPv6 stacks on WinNT4 and Win2K legacy platforms.
+ *
+ * The following in6_addr definition is based on the example given in
+ * RFC 3493, with stdint types replaced by BSD types. For now, we use
+ * these field names until there is some consistency in MS docs; Within
+ * this file, we only use the in6_addr structure start address, with
+ * casts to get the right offsets when testing addresses.
+ */
+struct in6_addr
+{ union
+ { u_char _S6_u8[16];
+ u_short _S6_u16[8];
+ u_long _S6_u32[4];
+ } _S6_un;
+# define s6_addr _S6_un._S6_u8 /* RFC 3493 standard name */
};
-/* s6_addr is the standard name */
-#define s6_addr _S6_un._S6_u8
-/* These are GLIBC names */
+/* The following are GLIBC specific field names...
+ */
#define s6_addr16 _S6_un._S6_u16
#define s6_addr32 _S6_un._S6_u32
-/* These are used in some MS code */
-#define in_addr6 in6_addr
+/* ...while these may be found in some Microsoft code.
+ */
+#define in_addr6 in6_addr
#define _s6_bytes _S6_un._S6_u8
#define _s6_words _S6_un._S6_u16
typedef struct in6_addr IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR;
-struct sockaddr_in6 {
- short sin6_family; /* AF_INET6 */
- u_short sin6_port; /* transport layer port # */
- u_long sin6_flowinfo; /* IPv6 traffic class & flow info */
- struct in6_addr sin6_addr; /* IPv6 address */
- u_long sin6_scope_id; /* set of interfaces for a scope */
-};
-typedef struct sockaddr_in6 SOCKADDR_IN6, *PSOCKADDR_IN6, *LPSOCKADDR_IN6;
+typedef
+struct sockaddr_in6
+{ short sin6_family; /* AF_INET6 */
+ u_short sin6_port; /* transport layer port # */
+ u_long sin6_flowinfo; /* IPv6 traffic class & flow info */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ u_long sin6_scope_id; /* set of interfaces for a scope */
+} SOCKADDR_IN6, *PSOCKADDR_IN6, *LPSOCKADDR_IN6;
extern const struct in6_addr in6addr_any;
extern const struct in6_addr in6addr_loopback;
-/* the above can get initialised using: */
+
#define IN6ADDR_ANY_INIT { 0 }
#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
-/* Described in RFC 2292, but not in 2553 */
-/* int IN6_ARE_ADDR_EQUAL(const struct in6_addr * a, const struct in6_addr * b) */
-#define IN6_ARE_ADDR_EQUAL(a, b) \
- (memcmp ((void*)(a), (void*)(b), sizeof (struct in6_addr)) == 0)
-
-/* Address Testing Macros
-
- These macro functions all take const struct in6_addr* as arg.
- Static inlines would allow type checking, but RFC 2553 says they
- macros.
- NB: These are written specifically for little endian host */
-
-#define IN6_IS_ADDR_UNSPECIFIED(_addr) \
- ( (((const u_long *)(_addr))[0] == 0) \
- && (((const u_long *)(_addr))[1] == 0) \
- && (((const u_long *)(_addr))[2] == 0) \
- && (((const u_long *)(_addr))[3] == 0))
-
-#define IN6_IS_ADDR_LOOPBACK(_addr) \
- ( (((const u_long *)(_addr))[0] == 0) \
- && (((const u_long *)(_addr))[1] == 0) \
- && (((const u_long *)(_addr))[2] == 0) \
- && (((const u_long *)(_addr))[3] == 0x01000000)) /* Note byte order reversed */
-/* (((const u_long *)(_addr))[3] == ntohl(1)) */
-
-#define IN6_IS_ADDR_MULTICAST(_addr) (((const u_char *) (_addr))[0] == 0xff)
-
-#define IN6_IS_ADDR_LINKLOCAL(_addr) \
- ( (((const u_char *)(_addr))[0] == 0xfe) \
- && ((((const u_char *)(_addr))[1] & 0xc0) == 0x80))
-
-#define IN6_IS_ADDR_SITELOCAL(_addr) \
- ( (((const u_char *)(_addr))[0] == 0xfe) \
- && ((((const u_char *)(_addr))[1] & 0xc0) == 0xc0))
-
-#define IN6_IS_ADDR_V4MAPPED(_addr) \
- ( (((const u_long *)(_addr))[0] == 0) \
- && (((const u_long *)(_addr))[1] == 0) \
- && (((const u_long *)(_addr))[2] == 0xffff0000)) /* Note byte order reversed */
-/* (((const u_long *)(_addr))[2] == ntohl(0x0000ffff))) */
-
-#define IN6_IS_ADDR_V4COMPAT(_addr) \
- ( (((const u_long *)(_addr))[0] == 0) \
- && (((const u_long *)(_addr))[1] == 0) \
- && (((const u_long *)(_addr))[2] == 0) \
- && (((const u_long *)(_addr))[3] != 0) \
- && (((const u_long *)(_addr))[3] != 0x01000000)) /* Note byte order reversed */
-/* (ntohl (((const u_long *)(_addr))[3]) > 1 ) */
-
-
-#define IN6_IS_ADDR_MC_NODELOCAL(_addr) \
- ( IN6_IS_ADDR_MULTICAST(_addr) \
- && ((((const u_char *)(_addr))[1] & 0xf) == 0x1))
-
-#define IN6_IS_ADDR_MC_LINKLOCAL(_addr) \
- ( IN6_IS_ADDR_MULTICAST (_addr) \
- && ((((const u_char *)(_addr))[1] & 0xf) == 0x2))
-
-#define IN6_IS_ADDR_MC_SITELOCAL(_addr) \
- ( IN6_IS_ADDR_MULTICAST(_addr) \
- && ((((const u_char *)(_addr))[1] & 0xf) == 0x5))
-
-#define IN6_IS_ADDR_MC_ORGLOCAL(_addr) \
- ( IN6_IS_ADDR_MULTICAST(_addr) \
- && ((((const u_char *)(_addr))[1] & 0xf) == 0x8))
-
-#define IN6_IS_ADDR_MC_GLOBAL(_addr) \
- ( IN6_IS_ADDR_MULTICAST(_addr) \
- && ((((const u_char *)(_addr))[1] & 0xf) == 0xe))
-
-
-typedef int socklen_t;
-
-struct ipv6_mreq {
- struct in6_addr ipv6mr_multiaddr;
- unsigned int ipv6mr_interface;
+/* IPv6 Address Testing Macros
+ *
+ * Each of these macros, as specified in RFC 3493, exhibits semantics
+ * of a function taking a "const struct in6_addr *" argument; (static
+ * inline functions would allow type checking, but RFC 3493 stipulates
+ * that they are macros, so we implement them as such).
+ *
+ * Note that IPv6 addresses are expressed in big-endian byte order.
+ * Host-native addressing is little-endian; thus, we implement each of
+ * these macros to interpret its argument as a byte array, stored in
+ * big-endian order, (reversing byte order throughout the quad-byte
+ * representation of the array).
+ *
+ * Further note that, while each of the following macros is named as
+ * specified in RFC 3493, the bit patterns, on which classification of
+ * the addresses is based, are specified in RFC 4291.
+ */
+#define IN6_IS_ADDR_UNSPECIFIED(_addr) \
+/* All 16 bytes of the IPv6 unspecified (i.e. the wildcard) \
+ * address MUST be zero. \
+ */ \
+ ( (((const u_long *)(_addr))[0] == 0) \
+ && (((const u_long *)(_addr))[1] == 0) \
+ && (((const u_long *)(_addr))[2] == 0) \
+ && (((const u_long *)(_addr))[3] == 0) \
+ )
+
+#define IN6_IS_ADDR_LOOPBACK(_addr) \
+/* Loopback address is ::1; for big-endian storage, the least \
+ * significant byte, with value one, must be moved to the most \
+ * significant byte of the most significant quad-byte, giving \
+ * it an effective value of 0x01000000 \
+ */ \
+ ( (((const u_long *)(_addr))[0] == 0) \
+ && (((const u_long *)(_addr))[1] == 0) \
+ && (((const u_long *)(_addr))[2] == 0) \
+ && (((const u_long *)(_addr))[3] == 0x01000000) \
+ )
+
+#define IN6_IS_ADDR_LINKLOCAL(_addr) \
+/* IPv6 link-local addresses are identified by having their \
+ * ten most significant bits equal to 1111111010b \
+ */ \
+ ( (((const u_char *)(_addr))[0] == 0xfe) \
+ && ((((const u_char *)(_addr))[1] & 0xc0) == 0x80) \
+ )
+
+#define IN6_IS_ADDR_SITELOCAL(_addr) \
+/* RFC 4291 says that IPv6 site-local addresses are obsolete, \
+ * and forbids their use in new applications; nonetheless they \
+ * are still permitted in pre-existing applications, in which \
+ * they may be indentified by having their most significant \
+ * ten bits equal to 1111111011b \
+ */ \
+ ( (((const u_char *)(_addr))[0] == 0xfe) \
+ && ((((const u_char *)(_addr))[1] & 0xc0) == 0xc0) \
+ )
+
+#define IN6_IS_ADDR_V4MAPPED(_addr) \
+/* An IPv4 mapped address reserves the least significant four \
+ * bytes, (most significant in big-endian equivalent storage), \
+ * for the IPv4 address; the immediately adjacent two bytes \
+ * MUST be 0xffff, with the remaining ten bytes all zero. \
+ */ \
+ ( (((const u_long *)(_addr))[0] == 0) \
+ && (((const u_long *)(_addr))[1] == 0) \
+ && (((const u_long *)(_addr))[2] == 0xffff0000) \
+ )
+
+#define IN6_IS_ADDR_V4COMPAT(_addr) \
+/* IPv4 compatible address format is effectively obsolete; \
+ * nonetheless, it may be recognized as being the same as the \
+ * IPv4 mapped format, but with 0x0000 in place of the 0xffff \
+ * byte pair, and the IPv4 address represented being neither \
+ * 0.0.0.0, nor 0.0.0.1, (again noting the byte reversal for \
+ * big-endian storage order). \
+ */ \
+ ( (((const u_long *)(_addr))[0] == 0) \
+ && (((const u_long *)(_addr))[1] == 0) \
+ && (((const u_long *)(_addr))[2] == 0) \
+ && (((const u_long *)(_addr))[3] != 0) \
+ && (((const u_long *)(_addr))[3] != 0x01000000) \
+ )
+
+#define IN6_IS_ADDR_MULTICAST(_addr) \
+/* Any IPv6 address in which the most significant byte, (least \
+ * significant in host storage order), has a value of 0xff, is \
+ * a multicast address. \
+ */ \
+ (((const u_char *)(_addr))[0] == 0xff)
+
+/* IPv6 multicast addresses may be further classified into
+ * "scope" groups, based on the value of the low order four
+ * bits of the second most significant byte; as above, the
+ * following macro names are specified in RFC 3493, but the
+ * scope indices are specified in RFC 4291.
+ */
+#define IN6_IS_ADDR_MC_NODELOCAL(_addr) \
+/* IPv6 multicast addresses with a scope index of one refer \
+ * only to interfaces of the originating host node; (this is \
+ * a multicast equivalent to the loopback address). \
+ */ \
+ ( IN6_IS_ADDR_MULTICAST(_addr) \
+ && ((((const u_char *)(_addr))[1] & 0xf) == 0x1) \
+ )
+
+#define IN6_IS_ADDR_MC_LINKLOCAL(_addr) \
+/* IPv6 multicast addresses with a scope index of two refer \
+ * to interfaces on the same subnet as the originating host. \
+ */ \
+ ( IN6_IS_ADDR_MULTICAST(_addr) \
+ && ((((const u_char *)(_addr))[1] & 0xf) == 0x2) \
+ )
+
+#define IN6_IS_ADDR_MC_SITELOCAL(_addr) \
+/* IPv6 multicast addresses with a scope index of five refer \
+ * to interfaces, possibly spanning multiple subnets, but all \
+ * within the confines of a single geographical location. \
+ */ \
+ ( IN6_IS_ADDR_MULTICAST(_addr) \
+ && ((((const u_char *)(_addr))[1] & 0xf) == 0x5) \
+ )
+
+#define IN6_IS_ADDR_MC_ORGLOCAL(_addr) \
+/* IPv6 multicast addresses with a scope index of eight refer \
+ * to interfaces which are geographically distributed across \
+ * multiple sites, all belonging to a single organization. \
+ */ \
+ ( IN6_IS_ADDR_MULTICAST(_addr) \
+ && ((((const u_char *)(_addr))[1] & 0xf) == 0x8) \
+ )
+
+#define IN6_IS_ADDR_MC_GLOBAL(_addr) \
+/* IPv6 multicast addresses with a scope index of fourteen \
+ * refer to interfaces which may be globally distributed over \
+ * the public internet. \
+ */ \
+ ( IN6_IS_ADDR_MULTICAST(_addr) \
+ && ((((const u_char *)(_addr))[1] & 0xf) == 0xe) \
+ )
+
+/* RFC 3542 augments the preceding set of address testing macros, by the
+ * addition of one more, intended for use in "advanced" applications; it
+ * is semantically equivalent to a function with prototype:
+ *
+ * int IN6_ARE_ADDR_EQUAL
+ * ( const struct in6_addr *, const struct in6_addr * )
+ *
+ * and returns non-zero if its two IPv6 address arguments are the same,
+ * or zero, if they differ.
+ */
+#define IN6_ARE_ADDR_EQUAL(_addr1, _addr2) \
+ ( memcmp( (void *)(_addr1), (void *)(_addr2), \
+ sizeof( struct in6_addr ) \
+ ) == 0 \
+ )
+
+typedef unsigned int socklen_t;
+
+typedef
+struct ipv6_mreq
+{ struct in6_addr ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
+} IPV6_MREQ;
+
+typedef
+struct in6_pktinfo
+{ IN6_ADDR ipi6_addr;
+ UINT ipi6_ifindex;
+} IN6_PKTINFO;
+
+struct addrinfo
+{ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
};
-typedef struct ipv6_mreq IPV6_MREQ;
-struct in6_pktinfo {
- IN6_ADDR ipi6_addr;
- UINT ipi6_ifindex;
-};
-typedef struct in6_pktinfo IN6_PKTINFO;
-
-struct addrinfo {
- int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- size_t ai_addrlen;
- char *ai_canonname;
- struct sockaddr *ai_addr;
- struct addrinfo *ai_next;
-};
+#if _WIN32_WINNT >= _WIN32_WINNT_WINXP && ! defined _WSPIAPI_H
+/* The following three functions are required by RFC 3493, (formerly
+ * RFC 2553), but MS-Windows did not support them natively, prior to
+ * Win-XP. On earlier Windows versions, they may be supported, (but
+ * without IPv6 support), by including <wspiapi.h>; (on Win-2K, IPv6
+ * support may be attainable, if the IPv6 Technology Preview kit has
+ * been installed, and the application is linked with WSHIP6.DLL).
+ *
+ * We expose these declarations only if we are compiling for Win-XP
+ * or later, and then only if <wspiapi.h> has not been included.
+ */
+WSAAPI int getaddrinfo
+(const char *, const char *, const struct addrinfo *, struct addrinfo **);
+
+WSAAPI int getnameinfo
+(const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, int);
-#if (_WIN32_WINNT >= 0x0501)
-void WSAAPI freeaddrinfo (struct addrinfo*);
-int WSAAPI getaddrinfo (const char*,const char*,const struct addrinfo*,
- struct addrinfo**);
-int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
- char*,DWORD,int);
-#else
-/* FIXME: Need WS protocol-independent API helpers. */
+WSAAPI void freeaddrinfo (struct addrinfo *);
#endif
-static __inline char*
-gai_strerrorA(int ecode)
+#define gai_strerror __AW_SUFFIXED__( gai_strerror )
+
+static __inline__
+char *gai_strerrorA (int ecode)
{
- static char message[1024+1];
- DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM
- | FORMAT_MESSAGE_IGNORE_INSERTS
- | FORMAT_MESSAGE_MAX_WIDTH_MASK;
- DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
- FormatMessageA(dwFlags, NULL, ecode, dwLanguageId, (LPSTR)message, 1024, NULL);
- return message;
+ static char message[1024+1];
+ DWORD Flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS
+ | FORMAT_MESSAGE_MAX_WIDTH_MASK;
+ DWORD LanguageId = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT);
+ FormatMessageA (Flags, NULL, ecode, LanguageId, message, 1024, NULL);
+ return message;
}
-static __inline WCHAR*
-gai_strerrorW(int ecode)
+
+static __inline__
+WCHAR *gai_strerrorW (int ecode)
{
- static WCHAR message[1024+1];
- DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM
- | FORMAT_MESSAGE_IGNORE_INSERTS
- | FORMAT_MESSAGE_MAX_WIDTH_MASK;
- DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
- FormatMessageW(dwFlags, NULL, ecode, dwLanguageId, (LPWSTR)message, 1024, NULL);
- return message;
+ static WCHAR message[1024+1];
+ DWORD Flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS
+ | FORMAT_MESSAGE_MAX_WIDTH_MASK;
+ DWORD LanguageId = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT);
+ FormatMessageW (Flags, NULL, ecode, LanguageId, message, 1024, NULL);
+ return message;
}
-#ifdef UNICODE
-#define gai_strerror gai_strerrorW
-#else
-#define gai_strerror gai_strerrorA
-#endif
/* Some older IPv4/IPv6 compatibility stuff */
/* This struct lacks sin6_scope_id; retained for use in sockaddr_gen */
-struct sockaddr_in6_old {
- short sin6_family;
- u_short sin6_port;
- u_long sin6_flowinfo;
- struct in6_addr sin6_addr;
+struct sockaddr_in6_old
+{ short sin6_family;
+ u_short sin6_port;
+ u_long sin6_flowinfo;
+ struct in6_addr sin6_addr;
};
-typedef union sockaddr_gen{
- struct sockaddr Address;
- struct sockaddr_in AddressIn;
- struct sockaddr_in6_old AddressIn6;
+typedef
+union sockaddr_gen
+{ struct sockaddr Address;
+ struct sockaddr_in AddressIn;
+ struct sockaddr_in6_old AddressIn6;
} sockaddr_gen;
-
-typedef struct _INTERFACE_INFO {
- u_long iiFlags;
- sockaddr_gen iiAddress;
- sockaddr_gen iiBroadcastAddress;
- sockaddr_gen iiNetmask;
+typedef
+struct _INTERFACE_INFO
+{ u_long iiFlags;
+ sockaddr_gen iiAddress;
+ sockaddr_gen iiBroadcastAddress;
+ sockaddr_gen iiNetmask;
} INTERFACE_INFO, *LPINTERFACE_INFO;
-/*
- The definition above can cause problems on NT4,prior to sp4.
- To workaround, include the following struct and typedef and
- #define INTERFACE_INFO OLD_INTERFACE_INFO
- See: FIX: WSAIoctl SIO_GET_INTERFACE_LIST Option Problem
- (Q181520) in MSDN KB.
-
- The old definition causes problems on newer NT and on XP.
-
-typedef struct _OLD_INTERFACE_INFO {
- u_long iiFlags;
- struct sockaddr iiAddress;
- struct sockaddr iiBroadcastAddress;
- struct sockaddr iiNetmask;
+#if 0
+/* The definition above may cause problems on WinNT4, prior to
+ * service pack 4. To work around this, if necessary, include
+ * the following typedef and struct definition, and
+ *
+ * #define INTERFACE_INFO OLD_INTERFACE_INFO
+ *
+ * See FIX: WSAIoctl SIO_GET_INTERFACE_LIST Option Problem
+ * (Q181520) in MSDN KB. Do note, however, that exposure of
+ * the old definition may cause problems on newer variants of
+ * WinNT, and on WinXP and later.
+ */
+typedef struct _OLD_INTERFACE_INFO
+{ u_long iiFlags;
+ struct sockaddr iiAddress;
+ struct sockaddr iiBroadcastAddress;
+ struct sockaddr iiNetmask;
} OLD_INTERFACE_INFO;
-*/
-
-#ifdef __cplusplus
-}
-#endif
#endif
+
+_END_C_DECLS
+
+#endif /* !_WS2TCPIP_H: $RCSfile$: end of file */
--- /dev/null
+/*
+ * wspiapi.h
+ *
+ * Implementation for pre-WinXP getaddrinfo() and getnameinfo() APIs.
+ *
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keith@users.osdn.me>
+ * Copyright (C) 2020, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author's Note:
+ * I have written this implementation of <wspiapi.h> from scratch, based
+ * entirely on hints from publicly visible Microsoft documentation, my own
+ * interpretation of IETF's RFC 3493, the corresponding POSIX.1 specification,
+ * and observation of the behaviour of example code from Microsoft's publicly
+ * visible documentation, which I have adapted to run on my GNU/Linux host.
+ * I have never seen code for Microsoft's <wspiapi.h> implementation; nor
+ * have I copied code from any other implementation, however licensed.
+ *
+ * This implementation servs as a fall-back for use on those legacy versions
+ * of Windows which do not support the getaddrinfo() and getnameinfo() APIs,
+ * through WS2_32.DLL on WinXP and later, or through WSHIP6.DLL on Win2K
+ * (with the IPv6 Preview Kit). Since such legacy Windows versions do not
+ * otherwise support IPv6, there is no attempt to support the AF_INET6
+ * address family; AF_INET is supported, as is AF_UNSPEC, but only to
+ * the extent that it is interpreted as AF_INET alone.
+ *
+ * It should be noted that, as described in Microsoft's documentation, the
+ * fall-back code is implemented in the form of in-line functions. This
+ * has a potentially disadvantageous side effect, in that every translation
+ * unit which calls any of the fall-back functions will incur a substantial
+ * overhead of potentially duplicated fall-back code. To mitigate this, it
+ * is recommended that all such calls be encapsulated within one translation
+ * unit, and exposed globally through public wrapper functions; an example
+ * of this technique may be found in the gcc/ada/socket.c implementation
+ * within recent GCC sources, wherein the public API is exposed via the
+ * __gnat_getaddrinfo(), __gnat_freeaddrinfo(), and __gnat_getnameinfo()
+ * function wrappers.
+ *
+ */
+#ifndef _WSPIAPI_H
+#pragma GCC system_header
+#define _WSPIAPI_H
+
+#include <stdio.h>
+#include <ws2tcpip.h>
+
+/* Symbolic constants are useful as wild-card identifiers for socket types
+ * and protocols, but these are non-standard; we don't want to pollute the
+ * public namespace, so we add the reserved __WSPIAPI_ prefix for these.
+ */
+#define __WSPIAPI_SOCK_ANY 0
+#define __WSPIAPI_IPPROTO_ANY 0
+
+_BEGIN_C_DECLS
+
+/* __wspiapi_errout(): a helper to assign a WSA error code, via the
+ * WSASetLastError() function, and also return it for immediate use
+ * as the exit status for any wspiapi function.
+ */
+static __inline__ __attribute__((__always_inline__))
+int __wspiapi_errout( int status ){ WSASetLastError( status ); return status; }
+
+/* __wspiapi_syserrout(): variation on __wspiapi_errout(), returning
+ * EAI_SYSTEM, after assigning a specific system errno value.
+ */
+static __inline__
+__attribute__((__always_inline__))
+int __wspiapi_syserrout( int errcode )
+{ errno = errcode; return __wspiapi_errout( EAI_SYSTEM ); }
+
+/* enum __wspiapi: generate symbolic names for the entry point indices
+ * within the wspapi function reference dictionary.
+ */
+enum __wspiapi
+{ __WSPIAPI_FREEADDRINFO__,
+ __WSPIAPI_GETADDRINFO__,
+ __WSPIAPI_GETNAMEINFO__
+};
+
+/* __wspiapi_t: a private use data type, describing the structure of
+ * each individual function reference within the dictionary.
+ */
+typedef struct
+{ const char *name;
+ void *entry;
+} __wspiapi_t;
+
+/* __wspiapi_reference(): a helper function to retrieve a function
+ * entry point address, by indexed function name look-up within the
+ * reference dictionary.
+ */
+static __inline__ __attribute__((__always_inline__))
+__wspiapi_t *__wspiapi_reference( enum __wspiapi index )
+{
+ /* The dictionary, itself, is statically encapsulated within this
+ * helper function, (and thus, is not publicly visible). Note that,
+ * initially, all entry point vectors are specified as (void *)(-1),
+ * and will be fixed-up on first call to any related function.
+ */
+ static __wspiapi_t dictionary[] =
+ { { "freeaddrinfo", (void *)(-1) },
+ { "getaddrinfo", (void *)(-1) },
+ { "getnameinfo", (void *)(-1) }
+ };
+
+ /* The return value is simply a pointer to the dictionary entry
+ * corresponding to the specified index.
+ */
+ return dictionary + index;
+}
+
+/* __wspiapi_set_entry(): helper function to perform the dictionary
+ * fix-up, for a single function entry point reference, as described
+ * for the __wspiapi_reference() function above. Note that this is
+ * called, only after a candidate DLL, which may be expected to
+ * provide the associated function, has been identified.
+ */
+static __inline__ __attribute__((__always_inline__))
+void __wspiapi_set_entry( HMODULE dll, __wspiapi_t *api )
+{ api->entry = (void *)(GetProcAddress( dll, api->name )); }
+
+/* __wspiapi_module_handle(): helper to obtain a module handle for
+ * a candidate DLL, which is expected to provide all of the wspiapi
+ * functions, based on it satisfying one dictionary reference.
+ */
+static __inline__
+HMODULE __wspiapi_module_handle
+( char *path, char *subst, const char *name, __wspiapi_t *api )
+{
+ HMODULE ref;
+
+ /* "subst" points to the offset, within the "path" buffer, at which
+ * the system directory path name ends, and the DLL file name should
+ * be inserted; append the specified DLL file "name", and attempt to
+ * load a system DLL of that name.
+ */
+ strcpy( subst, name );
+ if( (ref = LoadLibraryA( path )) != NULL )
+ {
+ /* We successfully obtained a reference handle for the named DLL;
+ * check that we can also obtain an entry point reference, within
+ * this DLL, for the specified wspiapi function, recording the
+ * result in the wspiapi reference dictionary...
+ */
+ if( (api->entry = (void *)(GetProcAddress( ref, api->name ))) == NULL )
+ {
+ /* ...and declaring no further wspiapi interest in this DLL, if
+ * the requisite entry point is unavailable.
+ */
+ FreeLibrary( ref );
+ return NULL;
+ }
+ }
+ /* If we get to here, then we either have a valid handle for a DLL
+ * which does provide the requisite wspiapi witness function, in
+ * which case we return that handle, otherwise we return the NULL
+ * resulting from a failed DLL load request.
+ */
+ return ref;
+}
+
+/* __wspiapi_lib(): a thin wrapper, through which all calls to
+ * __wspiapi_module_handle() are directed; it passes a system DLL
+ * search path, wherein the specified DLL name is substituted, (at
+ * the substring offset specified by "subst"), requiring that the
+ * designated system DLL should provide freeaddrinfo() as witness
+ * that it may be a suitable candidate provider for all of those
+ * functions which must otherwise be replaced by <wspiapi.h>
+ * fall-back implementations.
+ */
+static __inline__ __attribute__((__always_inline__))
+HMODULE __wspiapi_lib( char *path, char *subst, const char *name )
+{
+ /* This requires nothing more than appending the wspiapi dictionary
+ * reference for the freeaddrinfo() function, to the arguments which
+ * have already been specified, and forwarding the request onward,
+ * to __wspiapi_module_handle().
+ */
+ return __wspiapi_module_handle(
+ path, subst, name, __wspiapi_reference(__WSPIAPI_FREEADDRINFO__)
+ );
+}
+
+/* __wspiapi_entry(): helper to retrieve the entry point address for
+ * a specified wspiapi function, by indexed look-up within the wspiapi
+ * reference dictionary; invokes __wspiapi_lib(), as may be required,
+ * to initialize the reference dictionary entries.
+ */
+static __inline__
+void *__wspiapi_entry( enum __wspiapi index )
+# define __wspiapi_call( index ) (call)(__wspiapi_entry( index ))
+{
+ /* First, check that the reference dictionary has been initialized,
+ * using the freeaddrinfo() entry point reference as witness.
+ */
+ if( __wspiapi_reference(__WSPIAPI_FREEADDRINFO__)->entry == (void *)(-1) )
+ {
+ /* The dictionary appears to be uninitialized; set up to perform
+ * entry point searches within DLLs in the system directory...
+ */
+ HMODULE dll;
+ char sys_path[MAX_PATH], *dllname;
+ dllname = sys_path + GetSystemDirectory( sys_path, MAX_PATH - 11 );
+ if( dllname > sys_path )
+ { /* ...then, preferring WS2_32.DLL, but accepting WSHIP6.DLL as
+ * a second choice alternative, initialize the dictionary entry
+ * for the freeaddrinfo() witness function...
+ */
+ if( ((dll = __wspiapi_lib( sys_path, dllname, "\\ws2_32" )) != NULL)
+ || ((dll = __wspiapi_lib( sys_path, dllname, "\\wship6" )) != NULL) )
+ {
+ /* ...and, when that resolves to a valid entry point address,
+ * also initialize the entry point references, using the same
+ * DLL, for the getaddrinfo() and getnameinfo() functions...
+ */
+ __wspiapi_set_entry( dll, __wspiapi_reference(__WSPIAPI_GETADDRINFO__) );
+ __wspiapi_set_entry( dll, __wspiapi_reference(__WSPIAPI_GETNAMEINFO__) );
+ FreeLibrary( dll );
+ }
+ else
+ { /* ...otherwise, initialize these remaining references, such
+ * that all three functions are marked as unsupported by any
+ * system DLL, and thus must be emulated, on demand, by use
+ * of <wspiapi.h> in-line code.
+ */
+ __wspiapi_reference(__WSPIAPI_GETADDRINFO__)->entry = NULL;
+ __wspiapi_reference(__WSPIAPI_GETNAMEINFO__)->entry = NULL;
+ }
+ }
+ }
+ /* Irrespective of whether initialization was performed on this
+ * occasion, or had been performed previously, we return the entry
+ * point address for the requested function, as it is now recorded
+ * in the wspiapi reference dictionary.
+ */
+ return __wspiapi_reference( index )->entry;
+}
+
+/* __wspiapi_freeaddrinfo(): fall-back implementation for freeaddrinfo(),
+ * invoked by WspiapiFreeAddrInfo(), if (and only if), there is no native
+ * implementation provided in WS2_32.DLL, or by way of WSHIP6.DLL, from
+ * the Win2K IPv6 Technology Preview.
+ */
+static __inline__
+WSAAPI void __wspiapi_freeaddrinfo( struct addrinfo *ai_chain )
+{
+ /* This must free all addrinfo records on a single chain, which has been
+ * allocated by a prior call of __wspiapi_getaddrinfo(); note that it is
+ * necessary to free any associated ai_canonname records, which have been
+ * independently allocated, but not any ai_addr records, as these are all
+ * allocated as integral elements of the owner addrinfo record itself.
+ */
+ while( ai_chain != NULL )
+ { struct addrinfo *next = ai_chain->ai_next;
+ free( ai_chain->ai_canonname ); free( ai_chain );
+ ai_chain = next;
+ }
+}
+
+/* __wspiapi_addrinfo_cleanup(): a local helper function, called only by
+ * __wspiapi_getaddrinfo(), to clean up any partially allocated addrinfo
+ * record chain, in the event of __wspiapi_getaddrinfo() failure.
+ */
+static __inline__ __attribute__((__always_inline__))
+struct addrinfo *__wspiapi_addrinfo_cleanup( struct addrinfo *ai_chain )
+{ __wspiapi_freeaddrinfo( ai_chain ); return NULL; }
+
+/* __wspiapi_getaddrinfo_internal(): core implementation for, and called
+ * exclusively by, __wspiapi_getaddrinfo(); returns zero on success, or
+ * an EAI error code, (but without updating WSAGetLastError() status),
+ * on failure.
+ */
+static __inline__
+__attribute__((__always_inline__))
+int __wspiapi_getaddrinfo_internal
+( const char *__restrict__ nodename, const char *__restrict__ servname,
+ const struct addrinfo *__restrict__ hints, struct addrinfo **__restrict__ res
+)
+{ /* Either nodename, or servname, but not both, may be NULL; initially
+ * assign status to reflect the invalid condition of both being NULL.
+ */
+ int status = EAI_NONAME;
+
+ /* Initialize a local template, from which each allocated resultant
+ * addrinfo record may be derived.
+ */
+ struct ai { struct addrinfo ai; struct sockaddr_in sa; } ai_data;
+ memset( &ai_data, 0, sizeof( struct ai ) );
+
+ /* Ensure that the state of the resultant addrinfo record chain will
+ * be sane, in the event of early failure.
+ */
+ *res = NULL;
+
+ /* The hints may be NULL, (in which case the initial template state
+ * will prevail), but if specified...
+ */
+ if( hints != NULL )
+ { /* ...then its ai_addr, ai_canonname, and ai_next fields MUST all
+ * be NULL, and ai_addrlen MUST be zero.
+ */
+ if( (hints->ai_addr != NULL) || (hints->ai_addrlen != 0)
+ || (hints->ai_next != NULL) || (hints->ai_canonname != NULL) )
+ return EAI_FAIL;
+
+ /* Only the IPv4 AF_INET ai_family is supported, (but we tolerate
+ * AF_UNSPEC as implying AF_INET).
+ */
+ switch( ai_data.ai.ai_family = hints->ai_family )
+ { case AF_UNSPEC: case AF_INET: break; default: return EAI_FAMILY; }
+
+ /* Protocol and socket type may each be specified explicitly, or
+ * implicitly, (by default, or by wild-card assignment; supported
+ * protocols are TCP and UDP...
+ */
+ switch( ai_data.ai.ai_protocol = hints->ai_protocol )
+ {
+ case IPPROTO_TCP:
+ /* ...where an explicit choice of TCP must be associated with
+ * a stream type socket...
+ */
+ switch( hints->ai_socktype )
+ { /* ...which again, may be either explicitly assigned, or
+ * implicitly deduced.
+ */
+ case SOCK_STREAM: case __WSPIAPI_SOCK_ANY:
+ ai_data.ai.ai_socktype = SOCK_STREAM;
+ break;
+
+ /* Any other explicit pairing results in failure.
+ */
+ default: return EAI_SOCKTYPE;
+ }
+ break;
+
+ case IPPROTO_UDP:
+ /* Similarly, an explicit protocol choice must be paired,
+ * explicitly or implicitly, with a datagram socket.
+ */
+ switch( hints->ai_socktype )
+ { case SOCK_DGRAM: case __WSPIAPI_SOCK_ANY:
+ ai_data.ai.ai_socktype = SOCK_DGRAM;
+ break;
+
+ /* Once again, any other explicit pairing is invalid.
+ */
+ default: return EAI_SOCKTYPE;
+ }
+ break;
+
+ case __WSPIAPI_IPPROTO_ANY:
+ /* Without an explicit protocol specification, we may need
+ * to infer a match for the socket type...
+ */
+ switch( ai_data.ai.ai_socktype = hints->ai_socktype )
+ {
+ /* ...pairing TCP with an explicit stream socket...
+ */
+ case SOCK_STREAM:
+ ai_data.ai.ai_protocol = IPPROTO_TCP;
+ break;
+
+ /* ...UDP with a datagram socket...
+ */
+ case SOCK_DGRAM:
+ ai_data.ai.ai_protocol = IPPROTO_UDP;
+
+ /* ...or fall through, to enable generation of an addrinfo
+ * list, with all supported valid pairings.
+ */
+ case __WSPIAPI_SOCK_ANY: break;
+
+ /* Bail out, if any unsupported socket type is explicitly
+ * specified...
+ */
+ default: return EAI_SOCKTYPE;
+ }
+ break;
+
+ /* ...and likewise, for any unsupported protocol.
+ */
+ default: return EAI_SOCKTYPE;
+ }
+
+ /* Simply propagate whatever flags may have been specified, but
+ * defer any validation of them, until later.
+ */
+ ai_data.ai.ai_flags = hints->ai_flags;
+ }
+
+ /* Only the IPv4 address family is supported; whether confirmed in
+ * the hints, or left unspecified, we may stipulate that now.
+ */
+ ai_data.ai.ai_family = ai_data.sa.sin_family = AF_INET;
+
+ /* The servname argument may be NULL, but when it is specified, and
+ * it is a non-empty string...
+ */
+ if( (servname != NULL) && (*servname != '\0') )
+ { /* ...first try to interpret it as a textual representation of a
+ * service port number...
+ */
+ struct servent *pi; char *brk;
+ ai_data.sa.sin_port = strtoul( servname, &brk, 0 );
+ if( *brk == '\0' ) pi = getservbyport( htons( ai_data.sa.sin_port ), NULL );
+
+ /* ...or, failing that, a well known service name, which may be
+ * mapped to such a port number, or else bail out.
+ */
+ else pi = getservbyname( servname, NULL );
+ if( pi == NULL ) return EAI_SERVICE;
+
+ /* When the servname argument has been successfully interpreted,
+ * store the port number within the addrinfo template, and reset
+ * the return status, to indicate that the minimal requirement
+ * for at least one of servname and nodename is non-NULL.
+ */
+ ai_data.sa.sin_port = pi->s_port;
+ status = 0;
+ }
+
+ /* Similarly, the nodename argument may be NULL, but when it is
+ * specified, and is non-empty...
+ */
+ if( (nodename != NULL) && (*nodename != '\0') )
+ { /* ...then we first attempt to interpret it as a representation,
+ * in textual format, of an IPv4 address.
+ */
+ unsigned long *addr = (unsigned long *)(&(ai_data.sa.sin_addr));
+ if( (*addr = inet_addr( nodename )) != INADDR_NONE )
+ {
+ /* We've interpreted, and stored, a valid IPv4 address; this
+ * isn't, strictly, a node name; it is valid, in this context,
+ * but association with a canonical name is disallowed.
+ */
+ if( (ai_data.ai.ai_flags & AI_CANONNAME) == AI_CANONNAME )
+ return EAI_BADFLAGS;
+
+ /* When the IPv4 address form is accepted, we may immediately
+ * reset the return status, since the requirement for at least
+ * one nodename, or servname, to be non-NULL is satisfied.
+ */
+ status = 0;
+ }
+ else if( (ai_data.ai.ai_flags & AI_NUMERICHOST) == AI_NUMERICHOST )
+ {
+ /* No numeric IPv4 address was specified, but with this flag
+ * one becomes a mandatory requirement; bail out.
+ */
+ return EAI_NONAME;
+ }
+ else
+ { /* The specified nodename could not be interpreted as an IPv4
+ * address, (but was not required to be); resolve it as a host
+ * name, to obtain the corresponding IPv4 address.
+ */
+ struct hostent *hi = gethostbyname( nodename );
+ if( hi != NULL )
+ {
+ /* Name resolution was successful; update the template data
+ * to reflect the size of an IPv4 socket data structure, and
+ * store the resolved IPv4 address.
+ *
+ * FIXME: is it necessary to adapt this, to process a list
+ * comprising more than one resolved IPv4 address?
+ */
+ ai_data.ai.ai_addrlen = sizeof( struct sockaddr );
+ ai_data.sa.sin_addr = **(struct in_addr **)(hi->h_addr_list);
+
+ /* Also, if requested, capture the resolved canonical host
+ * name, but fail if there is insufficient memory.
+ */
+ if( ((ai_data.ai.ai_flags & AI_CANONNAME) == AI_CANONNAME)
+ && ((ai_data.ai.ai_canonname = strdup( hi->h_name )) == NULL) )
+ return EAI_MEMORY;
+
+ /* On successfully updating the template, to reflect all
+ * data associated with the resolved nodename, reset the
+ * exit status to indicate success.
+ */
+ status = 0;
+ }
+ }
+ }
+ else if( status == 0 )
+ { /* The nodename argument was effectively NULL, but we are able
+ * to proceed due to prior interpretation of a non-NULL servname
+ * argument; assign default addresses...
+ */
+ if( ((ai_data.ai.ai_flags & AI_PASSIVE) == AI_PASSIVE) )
+ { /* ...corresponding to the wild-card address for any passive
+ * connection...
+ */
+ ai_data.sa.sin_addr.s_addr = INADDR_ANY;
+ }
+ else
+ { /* ...or the loopback address, for non-passive connections.
+ */
+ ai_data.sa.sin_addr.s_addr = INADDR_LOOPBACK;
+ }
+ }
+
+ /* Provided the return status code has been reset to zero, from
+ * its initial EAI_NONAME value...
+ */
+ if( status == 0 )
+ { /* ...we should now have a suitably initialized template, from
+ * which we may construct the linked list of matching addrinfo
+ * structures to be returned. Each list entry is separately
+ * allocated, using the local pai pointer to track insertion
+ * point, selecting protocol and socket type pairings from the
+ * indexed list, working from TCP (at index two), back towards
+ * the wild-card protocol match (at index zero), and passing
+ * through UDP (at index one), until we reach the protocol as
+ * specified in the template; note that this will generate a
+ * single entry of TCP, or UDP, when either is specified as an
+ * explicit match requirement, but will generate three entries,
+ * matching each of TCP, UDP, and ANY, when a wild-card match
+ * is specified.
+ */
+ struct ai *pai = NULL;
+ int ref = (ai_data.ai.ai_protocol == IPPROTO_UDP) ? 1 : 2;
+ struct { int protocol; int socktype; } map[] =
+ { { __WSPIAPI_IPPROTO_ANY, __WSPIAPI_SOCK_ANY },
+ { IPPROTO_UDP, SOCK_DGRAM }, { IPPROTO_TCP, SOCK_STREAM }
+ };
+ do { if( pai == NULL )
+ { /* When pai is in its initial NULL state, the entry to
+ * be generated may be assigned directly to the head of
+ * the return list...
+ */
+ pai = ((struct ai *)(malloc( sizeof ai_data )));
+ *res = (struct addrinfo *)(pai);
+ }
+ /* ...otherwise we link it as ai_next successor to the
+ * previously allocated entry.
+ */
+ else
+ { pai->ai.ai_next = (struct addrinfo *)(malloc( sizeof ai_data ));
+ pai = (struct ai *)(pai->ai.ai_next);
+ }
+ if( pai == NULL )
+ { /* When pai remains in, or reverts to, the NULL state,
+ * then allocation of memory for the list entry failed;
+ * clean up any partially allocated return data, before
+ * bailing out.
+ */
+ *res = __wspiapi_addrinfo_cleanup( *res );
+ return EAI_MEMORY;
+ }
+ /* We got a successfully allocated block of memory for a
+ * list entry; populate it by copying the template...
+ */
+ *pai = ai_data;
+
+ /* ...then fix up the embedded sockaddr data reference,
+ * its protocol, and the socket type indicators.
+ */
+ pai->ai.ai_addr = (struct sockaddr *)(&(pai->sa.sin_family));
+ pai->ai.ai_protocol = map[ref].protocol;
+ pai->ai.ai_socktype = map[ref].socktype;
+
+ /* The template may initially include a canonical name
+ * reference; this is propagated to the first list entry
+ * only, so clear it prior to generating any more.
+ */
+ ai_data.ai.ai_canonname = NULL;
+
+ /* Go round again, until the addrinfo list has become
+ * fully populated.
+ */
+ } while( map[ref--].protocol != ai_data.ai.ai_protocol );
+ }
+ /* Ultimately, return either the initially assumed EAI_NONAME
+ * failure status, or success.
+ */
+ return status;
+}
+
+/* __wspiapi_getaddrinfo(): a thin wrapper around the preceding
+ * in-line implementation; invoked by WspiapiGetAddrInfo() if, and
+ * only if, no getaddrinfo() implementation is identifiable within
+ * the host system's WS2_32.DLL, or WSHIP6.DLL
+ */
+WSAAPI int __wspiapi_getaddrinfo (
+ const char *__restrict__ nodenam, const char *__restrict__ servnam,
+ const struct addrinfo *__restrict__ hints, struct addrinfo **__restrict__ res
+)
+{ /* First ensure that a non-NULL reference pointer is provided, to
+ * pass the addrinfo result back to the caller, then delegate the
+ * call to the in-line handler, capturing its exit status, which
+ * is then propagated through the WSAGetLastError() API.
+ */
+ if( res == NULL ) return __wspiapi_syserrout( EINVAL );
+ { int status = __wspiapi_getaddrinfo_internal( nodenam, servnam, hints, res );
+ return (status == 0) ? 0 : __wspiapi_errout( status );
+ }
+}
+
+/* WspiapiGetAddrInfo(): getaddrinfo() function redirector, as
+ * prescribed by Microsoft's on-line documentation.
+ */
+static __inline__
+WSAAPI int WspiapiGetAddrInfo
+( const char *node, const char *service, const struct addrinfo *hints,
+ struct addrinfo **response_list
+)
+{ /* Initialized to NULL, the redirector hook will be updated on
+ * first call, within the containing translation unit. This call
+ * will determine if it can be directed to an actual getaddrinfo()
+ * function implementation, provided by the system's WS2_32.DLL or
+ * WSHIP6.DLL libraries, initializing redirection for this first,
+ * and any subsequent call, to delegate to any such existing
+ * implementation, if available...
+ */
+ typedef WSAAPI int (*call)
+ ( const char *, const char *, const struct addrinfo *, struct addrinfo **
+ );
+ static call redirector_hook = NULL;
+ if( (redirector_hook == NULL)
+ && ((redirector_hook = __wspiapi_call(__WSPIAPI_GETADDRINFO__)) == NULL) )
+
+ /* ...or otherwise, to substitute the above fallback.
+ */
+ redirector_hook = __wspiapi_getaddrinfo;
+
+ /* Ultimately, every call is redirected to whichever handler has
+ * been selected by the preceding initialization.
+ */
+ return redirector_hook( node, service, hints, response_list );
+}
+
+/* getaddrinfo(): a static inline override for any external
+ * implementation of getaddrinfo(); ensures that corresponding
+ * function calls, within the translation unit file scope, are
+ * delegated to the fallback WspiapiGetAddrInfo() redirector.
+ */
+static __inline__ __attribute__((__always_inline__))
+WSAAPI int getaddrinfo( const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **response_list )
+{ return WspiapiGetAddrInfo( node, service, hints, response_list ); }
+
+/* WspiapiFreeAddrInfo(): freeaddrinfo() function redirector, as
+ * prescribed by Microsoft's on-line documentation.
+ */
+static __inline__
+WSAAPI void WspiapiFreeAddrInfo( struct addrinfo *ai_chain )
+{
+ /* Initialized to NULL, the redirector hook will be updated on
+ * first call, within the containing translation unit. This call
+ * will determine if it can be directed to an actual freeaddrinfo()
+ * function implementation, provided by the system's WS2_32.DLL or
+ * WSHIP6.DLL libraries, initializing redirection for this first,
+ * and any subsequent call, to delegate to any such existing
+ * implementation, if available...
+ */
+ typedef WSAAPI void (*call)(struct addrinfo *);
+ static call redirector_hook = NULL;
+ if( (redirector_hook == NULL)
+ && ((redirector_hook = __wspiapi_call(__WSPIAPI_FREEADDRINFO__)) == NULL) )
+
+ /* ...or otherwise, to substitute the above fallback.
+ */
+ redirector_hook = __wspiapi_freeaddrinfo;
+
+ /* Ultimately, every call is redirected to whichever handler has
+ * been selected by the preceding initialization.
+ */
+ redirector_hook( ai_chain );
+}
+
+/* freeaddrinfo(): a static inline override for any external
+ * implementation of freeaddrinfo(); ensures that corresponding
+ * function calls, within the translation unit file scope, are
+ * delegated to the fallback WspiapiFreeAddrInfo() redirector.
+ */
+static __inline__ __attribute__((__always_inline__))
+WSAAPI void freeaddrinfo (struct addrinfo *ai_chain)
+{ WspiapiFreeAddrInfo (ai_chain); }
+
+/* __wspiapi_getservname(): helper to retrieve the standard name,
+ * if any, for the service nominally associated with any port which
+ * is specified by its number in network byte order.
+ */
+static __inline__ __attribute__((__always_inline__))
+char *__wspiapi_getservname( u_short port, int flags, char *service,
+ socklen_t servlen, socklen_t *retlen
+)
+{ /* This look-up is suppressed, if NI_NUMERICSERV is included
+ * within the specified flags...
+ */
+ if( (flags & NI_NUMERICSERV) == 0 )
+ {
+ /* ...but, when allowed to proceed, we use the legacy windows
+ * getservbyport() function to perform the look-up...
+ */
+ struct servent *service_info;
+ service_info = getservbyport( port, (flags & NI_DGRAM) ? "udp" : NULL );
+
+ /* ...and then, provided a valid service name has been found,
+ * we transcribe it into the supplied buffer, for return.
+ */
+ if( (service_info != NULL) && (service_info->s_name != NULL) )
+ { *retlen = snprintf( service, servlen, "%s", service_info->s_name );
+ return service;
+ }
+ }
+ /* If, for whatever reason, no service name is to be returned,
+ * returning NULL will signal this.
+ */
+ return NULL;
+}
+
+/* __wspiapi_getnodename(): helper to perform a reverse DNS look-up,
+ * to retrieve, and nominally return, the fully qualified domain name
+ * which is associated with a specified IPv4 address.
+ */
+static __inline__ __attribute__((__always_inline__))
+char *__wspiapi_getnodename( struct in_addr *addr, int flags,
+ char *nodename, socklen_t nodelen, socklen_t *retlen
+)
+{ /* This look-up is suppressed, when NI_NUMERICHOST is included
+ * within the specified flags...
+ */
+ if( (flags & NI_NUMERICHOST) == 0 )
+ {
+ /* ...but, when allowed to proceed, we use the legacy windows
+ * gethostbyaddr() function to perform the look-up...
+ */
+ struct hostent *node_info = gethostbyaddr(
+ (const char *)(addr), sizeof( struct in_addr ), AF_INET
+ );
+
+ /* ...and then, provided a valid host name has been found,
+ * we transcribe it into the supplied buffer, for return.
+ */
+ if( (node_info != NULL) && (node_info->h_name != NULL) )
+ { *retlen = snprintf( nodename, nodelen, "%s", node_info->h_name );
+
+ /* A special case arises, when NI_NOFQDN is included
+ * within the specified flags.
+ */
+ if( (flags & NI_NOFQDN) != 0 )
+ {
+ /* In this case, we must check for any period, as
+ * punctuation separating the host name itself from
+ * its domain name...
+ */
+ char *brk = strchr( nodename, '.' );
+ if( brk != NULL )
+ {
+ /* ...and, when such punctuation is present, we
+ * truncate the return string at the first period,
+ * so leaving only the bare host name for return.
+ */
+ *brk = '\0';
+ *retlen = brk - nodename;
+ }
+ }
+ /* Truncated, or otherwise, we may now return the host
+ * name, as retrieved.
+ */
+ return nodename;
+ }
+ }
+ /* If, for whatever reason, no host name is to be returned,
+ * returning NULL will signal this.
+ */
+ return NULL;
+}
+
+/* __wspiapi_getnameinfo_internal(): core implementation for, and called
+ * exclusively by, __wspiapi_getnameinfo(); returns zero on success, or
+ * an EAI error code, (but without updating WSAGetLastError() status),
+ * on failure.
+ */
+static __inline__
+__attribute__((__always_inline__))
+int __wspiapi_getnameinfo_internal
+( const struct sockaddr *__restrict__ sa, socklen_t len,
+ char *__restrict__ node, socklen_t nodelen, char *__restrict__ service,
+ socklen_t servlen, int flags
+)
+{ /* Either the service name, or the node name look-up may be omitted,
+ * but at least one MUST be performed; if neither is performed, as we
+ * may establish later, then we should fail with status EAI_NONAME.
+ */
+ int status = EAI_NONAME;
+
+ /* If support for IPv6 is available, then the system DLL will provide
+ * its own getnameinfo() implementation, and this fallback handler is
+ * not invoked; thus, we need only support the IPv4 address family.
+ */
+ if( sa->sa_family != AF_INET ) return EAI_FAMILY;
+
+ /* The "service" argument may be NULL, or its associated "servlen"
+ * may be zero; a service name look-up is performed, only if neither
+ * of these excluding conditions is satisfied.
+ */
+ if( (service != NULL) && (servlen > 0) )
+ {
+ /* When look-up is NOT excluded, we delegate it to our internal
+ * __wspiapi_getservname() helper, capturing the result into an
+ * intermediate buffer of the same length as has been declared
+ * for the returned result...
+ */
+ char servname[servlen];
+ u_short port = ((const struct sockaddr_in *)(sa))->sin_port;
+ if( __wspiapi_getservname( port, flags, servname, servlen, &len ) == NULL )
+
+ /* ...while noting that, if the look-up was unsuccessful, (or it
+ * was suppressed, because NI_NUMERICSERV was included within the
+ * specified flags), we substitute a string representation of the
+ * service port number.
+ */
+ len = snprintf( servname, servlen, "%u", ntohs( port ) );
+
+ /* Provided the declared buffer length is sufficient to accommodate
+ * the result of the look-up, we copy that result from intermediate
+ * storage to the designated return buffer...
+ */
+ if( servlen > len ) strcpy( service, servname );
+
+ /* ...but if it doesn't fit, we bail out, reporting overflow.
+ */
+ else return EAI_OVERFLOW;
+
+ /* We HAVE now performed a successful service name look-up, so we
+ * may clear our initial EAI_NONAME presumption.
+ */
+ status = 0;
+ }
+
+ /* The "node" argument may be NULL, or its associated "nodelen" may
+ * be zero; a node name look-up is performed, only if neither of
+ * these excluding conditions is satisfied.
+ */
+ if( (node != NULL) && (nodelen > 0) )
+ {
+ /* Perform the node name look-up, based on the IPv4 address as
+ * specified in the "sa" structure argument...
+ */
+ char nodename[nodelen];
+ struct in_addr addr = ((const struct sockaddr_in *)(sa))->sin_addr;
+ if( __wspiapi_getnodename( &addr, flags, nodename, nodelen, &len ) == NULL )
+ {
+ /* ...but on look-up failure, and if not required to succeed,
+ * (by specification of the NI_NAMEREQD flag)...
+ */
+ if( (flags & NI_NAMEREQD) != 0 ) return EAI_NONAME;
+
+ /* ...substitute the textual representation of the address.
+ */
+ len = snprintf( nodename, nodelen, "%s", inet_ntoa( addr ) );
+ }
+ /* Whether the name look-up was successful, or the address was
+ * substituted, if the return "node" buffer size is sufficient,
+ * copy the look-up result into place...
+ */
+ if( nodelen > len ) strcpy( node, nodename );
+
+ /* ...otherwise, bail out.
+ */
+ else return EAI_OVERFLOW;
+
+ /* If we get this far, the function has completed successfully.
+ */
+ return 0;
+ }
+ /* If we didn't perform "node" name look-up, then the return state
+ * must be either the result of successful "service" resolution, or
+ * the initially assumed failure state.
+ */
+ return status;
+}
+
+/* __wspiapi_getnameinfo(): a thin wrapper around the preceding
+ * in-line implementation; invoked by WspiapiGetNameInfo() if, and
+ * only if, no getnameinfo() implementation is identifiable within
+ * the host system's WS2_32.DLL, or WSHIP6.DLL
+ */
+static __inline__
+WSAAPI int __wspiapi_getnameinfo
+( const struct sockaddr *__restrict__ sa, socklen_t len,
+ char *__restrict__ node, socklen_t nodelen, char *__restrict__ service,
+ socklen_t servlen, int flags
+)
+{ /* The "sa" argument MUST NOT be NULL, and its declared length MUST
+ * match that of struct sockaddr. RFC 3493 doesn't prescribe how we
+ * should handle this case, but we choose to emulate the behaviour of
+ * Microsoft's invalid parameter handler, while reporting it as an
+ * EAI_SYSTEM exception.
+ */
+ if( (sa == NULL) || (len < sizeof( struct sockaddr )) )
+ return __wspiapi_syserrout( EINVAL );
+
+ { /* When the "sa" argument is valid, we delegate the call to the
+ * preceding in-line handler, simply capturing its return status,
+ * and propagating it through the WSAGetLastError() API, as may
+ * be appropriate.
+ */
+ int status = __wspiapi_getnameinfo_internal
+ ( sa, len, node, nodelen, service, servlen, flags );
+ return (status == 0) ? 0 : __wspiapi_errout( status );
+ }
+}
+
+/* WspiapiGetNameInfo(): getnameinfo() function redirector, as
+ * prescribed by Microsoft's on-line documentation.
+ */
+static __inline__
+WSAAPI int WspiapiGetNameInfo
+( const struct sockaddr *__restrict__ addr, socklen_t len,
+ char *__restrict__ node, socklen_t nodelen, char *__restrict__ service,
+ socklen_t servlen, int flags
+)
+{ /* Initialized to NULL, the redirector hook will be updated on
+ * first call, within the containing translation unit. This call
+ * will determine if it can be directed to an actual getnameinfo()
+ * function implementation, provided by the system's WS2_32.DLL or
+ * WSHIP6.DLL libraries, initializing redirection for this first,
+ * and any subsequent call, to delegate to any such existing
+ * implementation, if available...
+ */
+ typedef WSAAPI int (*call)
+ (const SOCKADDR *, socklen_t, char *, socklen_t, char *, socklen_t, int
+ );
+ static call redirector_hook = NULL;
+ if( (redirector_hook == NULL)
+ && ((redirector_hook = __wspiapi_call(__WSPIAPI_GETNAMEINFO__)) == NULL) )
+
+ /* ...or otherwise, to substitute the above fallback.
+ */
+ redirector_hook = __wspiapi_getnameinfo;
+
+ /* Ultimately, every call is redirected to whichever handler has
+ * been selected by the preceding initialization.
+ */
+ return redirector_hook( addr, len, node, nodelen, service, servlen, flags );
+}
+
+/* getnameinfo(): a static inline override for any external
+ * implementation of getnameinfo(); ensures that corresponding
+ * function calls, within the translation unit file scope, are
+ * delegated to the fallback WspiapiGetNameInfo() redirector.
+ */
+static __inline__ __attribute__((__always_inline__))
+WSAAPI int getnameinfo( const SOCKADDR *addr, socklen_t addrlen,
+ char *node, socklen_t nb_size, char *service, socklen_t sb_size, int flags
+)
+{ return WspiapiGetNameInfo
+ (addr, addrlen, node, nb_size, service, sb_size, flags);
+}
+
+_END_C_DECLS
+
+#endif /* !_WSPIAPI_H: $RCSfile$: end of file */