diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2006-07-06 14:04:33 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2006-07-06 14:04:33 +0000 |
commit | 96a233ec15869bfdb32a3c0b2b5f0fb4ff5151a3 (patch) | |
tree | b227e0e01bcfeaf05842ef1bd8188eba5e159cee | |
parent | a89783347f2487a943a10003548b26cba3367a00 (diff) | |
download | newlib-96a233ec15869bfdb32a3c0b2b5f0fb4ff5151a3.zip newlib-96a233ec15869bfdb32a3c0b2b5f0fb4ff5151a3.tar.gz newlib-96a233ec15869bfdb32a3c0b2b5f0fb4ff5151a3.tar.bz2 |
* cygwin.din: Export in6addr_any, in6addr_loopback, freeaddrinfo,
gai_strerror, getaddrinfo, getnameinfo.
* fhandler_socket.cc: Include cygwin/in6.h.
(get_inet_addr): Accomodate AF_INET6 usage.
(fhandler_socket::connect): Ditto.
(fhandler_socket::listen): Ditto.
(fhandler_socket::sendto): Ditto.
* net.cc: Include cygwin/in6.h.
(in6addr_any): Define.
(in6addr_loopback): Define.
(cygwin_socket): Accomodate AF_INET6 usage.
(socketpair): Bind socketpairs only to loopback for security.
(inet_pton4): New static function.
(inet_pton6): Ditto.
(cygwin_inet_pton): New AF_INET6 aware inet_pton implementation.
(inet_ntop4): New static function.
(inet_ntop6): Ditto.
(cygwin_inet_ntop): New AF_INET6 aware inet_ntop implementation.
(ga_aistruct): New static function.
(ga_clone): Ditto.
(ga_echeck): Ditto.
(ga_nsearch): Ditto.
(ga_port): Ditto.
(ga_serv): Ditto.
(ga_unix): Ditto.
(gn_ipv46): Ditto.
(ipv4_freeaddrinfo): Ditto.
(ipv4_getaddrinfo): Ditto.
(ipv4_getnameinfo): Ditto.
(gai_errmap_t): New structure holding error code - error string mapping.
(cygwin_gai_strerror): New function implementing gai_strerror.
(w32_to_gai_err): New static function.
(get_ipv6_funcs): Ditto.
(load_ipv6_funcs): Ditto.
(cygwin_freeaddrinfo): New function implementing freeaddrinfo.
(cygwin_getaddrinfo): New function implementing getaddrinfo.
(cygwin_getnameinfo): New function implementing getnameinfo.
* include/netdb.h: Include stdint.h and cygwin/socket.h. Define
data types and macros used by getaddrinfo and friends. Declare
freeaddrinfo, gai_strerror, getaddrinfo and getnameinfo.
* include/cygwin/in.h: Add IPv6 related IPPROTOs. Remove definition
of struct sockaddr_in6. Include cygwin/in6.h instead.
* include/cygwin/in6.h: New header file defining IPv6 releated
data types and macros.
* include/cygwin/socket.h: Enable AF_INET6 and PF_INET6. Add
IPv6 related socket options.
* include/cygwin/version.h: Bump API minor number.
-rw-r--r-- | winsup/cygwin/ChangeLog | 50 | ||||
-rw-r--r-- | winsup/cygwin/cygwin.din | 6 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_socket.cc | 53 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/in.h | 36 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/in6.h | 119 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/socket.h | 15 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/version.h | 4 | ||||
-rw-r--r-- | winsup/cygwin/include/netdb.h | 61 | ||||
-rw-r--r-- | winsup/cygwin/net.cc | 1403 |
9 files changed, 1674 insertions, 73 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 9ab0c2c..f4c954d 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,55 @@ 2006-07-06 Corinna Vinschen <corinna@vinschen.de> + * cygwin.din: Export in6addr_any, in6addr_loopback, freeaddrinfo, + gai_strerror, getaddrinfo, getnameinfo. + * fhandler_socket.cc: Include cygwin/in6.h. + (get_inet_addr): Accomodate AF_INET6 usage. + (fhandler_socket::connect): Ditto. + (fhandler_socket::listen): Ditto. + (fhandler_socket::sendto): Ditto. + * net.cc: Include cygwin/in6.h. + (in6addr_any): Define. + (in6addr_loopback): Define. + (cygwin_socket): Accomodate AF_INET6 usage. + (socketpair): Bind socketpairs only to loopback for security. + (inet_pton4): New static function. + (inet_pton6): Ditto. + (cygwin_inet_pton): New AF_INET6 aware inet_pton implementation. + (inet_ntop4): New static function. + (inet_ntop6): Ditto. + (cygwin_inet_ntop): New AF_INET6 aware inet_ntop implementation. + (ga_aistruct): New static function. + (ga_clone): Ditto. + (ga_echeck): Ditto. + (ga_nsearch): Ditto. + (ga_port): Ditto. + (ga_serv): Ditto. + (ga_unix): Ditto. + (gn_ipv46): Ditto. + (ipv4_freeaddrinfo): Ditto. + (ipv4_getaddrinfo): Ditto. + (ipv4_getnameinfo): Ditto. + (gai_errmap_t): New structure holding error code - error string mapping. + (cygwin_gai_strerror): New function implementing gai_strerror. + (w32_to_gai_err): New static function. + (get_ipv6_funcs): Ditto. + (load_ipv6_funcs): Ditto. + (cygwin_freeaddrinfo): New function implementing freeaddrinfo. + (cygwin_getaddrinfo): New function implementing getaddrinfo. + (cygwin_getnameinfo): New function implementing getnameinfo. + * include/netdb.h: Include stdint.h and cygwin/socket.h. Define + data types and macros used by getaddrinfo and friends. Declare + freeaddrinfo, gai_strerror, getaddrinfo and getnameinfo. + * include/cygwin/in.h: Add IPv6 related IPPROTOs. Remove definition + of struct sockaddr_in6. Include cygwin/in6.h instead. + * include/cygwin/in6.h: New header file defining IPv6 releated + data types and macros. + * include/cygwin/socket.h: Enable AF_INET6 and PF_INET6. Add + IPv6 related socket options. + * include/cygwin/version.h: Bump API minor number. + +2006-07-06 Corinna Vinschen <corinna@vinschen.de> + * autoload.cc (DsGetDcNameA): Define. (NetGetAnyDCName): Define. * security.cc: Include dsgetdc.h. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 09b3445..7d00b78 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -11,6 +11,8 @@ __cygwin_user_data DATA _daylight DATA h_errno DATA _impure_ptr DATA +in6addr_any DATA +in6addr_loopback DATA __mb_cur_max DATA optarg DATA opterr DATA @@ -471,6 +473,7 @@ fread SIGFE _fread = fread SIGFE free SIGFE _free = free SIGFE +freeaddrinfo = cygwin_freeaddrinfo SIGFE freopen SIGFE _freopen = freopen SIGFE _freopen64 = freopen64 SIGFE @@ -524,6 +527,7 @@ funlockfile SIGFE futimes SIGFE fwrite SIGFE _fwrite = fwrite SIGFE +gai_strerror = cygwin_gai_strerror NOSIGFE gamma NOSIGFE _gamma = gamma NOSIGFE gamma_r NOSIGFE @@ -538,6 +542,7 @@ gcvtf SIGFE _gcvtf = gcvtf SIGFE get_osfhandle SIGFE _get_osfhandle = get_osfhandle SIGFE +getaddrinfo = cygwin_getaddrinfo SIGFE getc SIGFE _getc = getc SIGFE getc_unlocked SIGFE @@ -594,6 +599,7 @@ getmntent SIGFE _getmntent = getmntent SIGFE getmode SIGFE _getmode = getmode SIGFE +getnameinfo = cygwin_getnameinfo SIGFE getopt SIGFE getopt_long SIGFE getopt_long_only SIGFE diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index c3c24d2..51d72fc 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -37,6 +37,7 @@ #include <unistd.h> #include <sys/acl.h> #include "cygtls.h" +#include "cygwin/in6.h" #define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT) @@ -50,15 +51,15 @@ fhandler_dev_random* entropy_source; /* cygwin internal: map sockaddr into internet domain address */ static int get_inet_addr (const struct sockaddr *in, int inlen, - struct sockaddr_in *out, int *outlen, + struct sockaddr_storage *out, int *outlen, int *type = NULL, int *secret = NULL) { int secret_buf [4]; int* secret_ptr = (secret ? : secret_buf); - if (in->sa_family == AF_INET) + if (in->sa_family == AF_INET || in->sa_family == AF_INET6) { - *out = * (struct sockaddr_in *)in; + memcpy (out, in, inlen); *outlen = inlen; return 1; } @@ -102,7 +103,7 @@ get_inet_addr (const struct sockaddr *in, int inlen, secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3); sin.sin_port = htons (sin.sin_port); sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - *out = sin; + memcpy (out, &sin, sizeof sin); *outlen = sizeof sin; if (type) *type = (ctype == 's' ? SOCK_STREAM : @@ -739,11 +740,11 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) { int res = -1; bool in_progress = false; - struct sockaddr_in sin; + struct sockaddr_storage sst; DWORD err; int type; - if (!get_inet_addr (name, namelen, &sin, &namelen, &type, connect_secret)) + if (!get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret)) return -1; if (get_addr_family () == AF_LOCAL && get_socket_type () != type) @@ -753,7 +754,7 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) return -1; } - res = ::connect (get_socket (), (struct sockaddr *) &sin, namelen); + res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen); if (!res) err = 0; @@ -804,19 +805,35 @@ int fhandler_socket::listen (int backlog) { int res = ::listen (get_socket (), backlog); - if (res && WSAGetLastError () == WSAEINVAL && get_addr_family () == AF_INET) + if (res && WSAGetLastError () == WSAEINVAL) { /* It's perfectly valid to call listen on an unbound INET socket. In this case the socket is automatically bound to an unused port number, listening on all interfaces. On Winsock, listen fails with WSAEINVAL when it's called on an unbound socket. So we have to bind manually here to have POSIX semantics. */ - struct sockaddr_in sa; - sa.sin_family = AF_INET; - sa.sin_port = 0; - sa.sin_addr.s_addr = INADDR_ANY; - if (!::bind (get_socket (), (struct sockaddr *) &sa, sizeof sa)) - res = ::listen (get_socket (), backlog); + if (get_addr_family () == AF_INET) + { + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + if (!::bind (get_socket (), (struct sockaddr *) &sin, sizeof sin)) + res = ::listen (get_socket (), backlog); + } + else if (get_addr_family () == AF_INET6) + { + struct sockaddr_in6 sin6 = + { + sin6_family: AF_INET6, + sin6_port: 0, + sin6_flowinfo: 0, + sin6_addr: IN6ADDR_ANY_INIT, + sin6_scope_id: 0 + }; + if (!::bind (get_socket (), (struct sockaddr *) &sin6, sizeof sin6)) + res = ::listen (get_socket (), backlog); + } } if (!res) { @@ -1256,9 +1273,9 @@ int fhandler_socket::sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen) { - struct sockaddr_in sin; + struct sockaddr_storage sst; - if (to && !get_inet_addr (to, tolen, &sin, &tolen)) + if (to && !get_inet_addr (to, tolen, &sst, &tolen)) return SOCKET_ERROR; int res = SOCKET_ERROR; @@ -1269,7 +1286,7 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, if (is_nonblocking () || closed () || async_io ()) res = WSASendTo (get_socket (), &wsabuf, 1, &ret, flags & MSG_WINMASK, - (to ? (const struct sockaddr *) &sin : NULL), tolen, + (to ? (const struct sockaddr *) &sst : NULL), tolen, NULL, NULL); else { @@ -1280,7 +1297,7 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, { res = WSASendTo (get_socket (), &wsabuf, 1, &ret, flags & MSG_WINMASK, - (to ? (const struct sockaddr *) &sin : NULL), + (to ? (const struct sockaddr *) &sst : NULL), tolen, NULL, NULL); } while (res == SOCKET_ERROR diff --git a/winsup/cygwin/include/cygwin/in.h b/winsup/cygwin/include/cygwin/in.h index a932ec6..619d47a 100644 --- a/winsup/cygwin/include/cygwin/in.h +++ b/winsup/cygwin/include/cygwin/in.h @@ -28,6 +28,7 @@ typedef uint32_t in_addr_t; enum { IPPROTO_IP = 0, /* Dummy protocol for TCP */ + IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options */ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ IPPROTO_IGMP = 2, /* Internet Gateway Management Protocol */ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ @@ -36,12 +37,21 @@ enum IPPROTO_PUP = 12, /* PUP protocol */ IPPROTO_UDP = 17, /* User Datagram Protocol */ IPPROTO_IDP = 22, /* XNS IDP protocol */ + IPPROTO_IPV6 = 41, /* IPv6 header */ + IPPROTO_ROUTING = 43, /* IPv6 Routing header */ + IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header */ + IPPROTO_ESP = 50, /* encapsulating security payload */ + IPPROTO_AH = 51, /* authentication header */ + IPPROTO_ICMPV6 = 58, /* ICMPv6 */ + IPPROTO_NONE = 59, /* IPv6 no next header */ + IPPROTO_DSTOPTS = 60, /* IPv6 Destination options */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX }; /* Define IPPROTO_xxx values to accomodate SUSv3 */ #define IPPROTO_IP IPPROTO_IP +#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS #define IPPROTO_ICMP IPPROTO_ICMP #define IPPROTO_IGMP IPPROTO_IGMP #define IPPROTO_IPIP IPPROTO_IPIP @@ -51,6 +61,14 @@ enum #define IPPROTO_UDP IPPROTO_UDP #define IPPROTO_IDP IPPROTO_IDP #define IPPROTO_RAW IPPROTO_RAW +#define IPPROTO_IPV6 IPPROTO_IPV6 +#define IPPROTO_ROUTING IPPROTO_ROUTING +#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT +#define IPPROTO_ESP IPPROTO_ESP +#define IPPROTO_AH IPPROTO_AH +#define IPPROTO_ICMPV6 IPPROTO_ICMPV6 +#define IPPROTO_NONE IPPROTO_NONE +#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS /* Standard well-known ports. *//* from winsup/include/netinet/in.h */ enum @@ -185,21 +203,7 @@ struct sockaddr_in #endif -#ifdef USE_IPV6 -/* IPv6 definitions as we start to include them. This is just - a beginning dont get excited 8) */ -struct in6_addr -{ - uint8_t s6_addr[16]; -}; - -struct sockaddr_in6 -{ - sa_family_t sin6_family; /* AF_INET6 */ - in_port_t sin6_port; /* Port number. */ - uint32_t sin6_flowinfo; /* Traffic class and flow inf. */ - struct in6_addr sin6_addr; /* IPv6 address. */ - uint32_t sin6_scope_id; /* Set of interfaces for a scope. */ -}; +#ifdef AF_INET6 +#include <cygwin/in6.h> #endif #endif /* _CYGWIN_IN_H */ diff --git a/winsup/cygwin/include/cygwin/in6.h b/winsup/cygwin/include/cygwin/in6.h new file mode 100644 index 0000000..ef73588 --- /dev/null +++ b/winsup/cygwin/include/cygwin/in6.h @@ -0,0 +1,119 @@ +/* cygwin/in6.h + + Copyright 2006 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* NOTE: This file is NOT for direct inclusion. Use netinet/in.h. */ + +#ifndef _CYGWIN_IN6_H +#define _CYGWIN_IN6_H + +#define INET6_ADDRSTRLEN 46 + +#define IN6_ARE_ADDR_EQUAL(a, b) \ + (((const uint32_t *)(a))[0] == ((const uint32_t *)(b))[0] \ + && ((const uint32_t *)(a))[1] == ((const uint32_t *)(b))[1] \ + && ((const uint32_t *)(a))[2] == ((const uint32_t *)(b))[2] \ + && ((const uint32_t *)(a))[3] == ((const uint32_t *)(b))[3]) + +#define IN6_IS_ADDR_UNSPECIFIED(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == 0 \ + && ((const uint32_t *)(addr))[3] == 0) + +#define IN6_IS_ADDR_LOOPBACK(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == 0 \ + && ((const uint32_t *)(addr))[3] == htonl (1)) + +#define IN6_IS_ADDR_MULTICAST(addr) (((const uint8_t *) (addr))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(addr) \ + ((((const uint16_t *)(addr))[0] & htons (0xffc0)) == htons (0xfe80)) + +#define IN6_IS_ADDR_SITELOCAL(addr) \ + ((((const uint16_t *)(addr))[0] & htons (0xffc0)) == htons (0xfec0)) + +#define IN6_IS_ADDR_V4MAPPED(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == htonl (0xffff)) + +#define IN6_IS_ADDR_V4COMPAT(addr) \ + (((const uint32_t *)(addr))[0] == 0 \ + && ((const uint32_t *)(addr))[1] == 0 \ + && ((const uint32_t *)(addr))[2] == 0 \ + && ntohl (((const uint32_t *)(addr))[3]) > 1) + +#define IN6_IS_ADDR_MC_NODELOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x1) + +#define IN6_IS_ADDR_MC_LINKLOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST (addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x2) + +#define IN6_IS_ADDR_MC_SITELOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x5) + +#define IN6_IS_ADDR_MC_ORGLOCAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0x8) + +#define IN6_IS_ADDR_MC_GLOBAL(addr) \ + (IN6_IS_ADDR_MULTICAST(addr) \ + && (((const uint8_t *)(addr))[1] & 0xf) == 0xe) + +struct in6_addr +{ + union + { + uint8_t __s6_addr_u[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __u6; +#define s6_addr __u6.__s6_addr +#define s6_addr16 __u6.__s6_addr16 +#define s6_addr32 __u6.__s6_addr32 +}; + +struct ipv6_mreq +{ + struct in6_addr ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +}; + +struct in6_pktinfo +{ + struct in6_addr ipi6_addr; + unsigned int ipi6_ifindex; +}; + +#ifdef __INSIDE_CYGWIN__ +typedef uint16_t in_port_t; +#endif + +struct sockaddr_in6 +{ + sa_family_t sin6_family; /* AF_INET6 */ + in_port_t sin6_port; /* Port number. */ + uint32_t sin6_flowinfo; /* Traffic class and flow inf. */ + struct in6_addr sin6_addr; /* IPv6 address. */ + uint32_t sin6_scope_id; /* Set of interfaces for a scope. */ +}; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } + +extern const struct in6_addr in6addr_any; +extern const struct in6_addr in6addr_loopback; + +#endif /* _CYGWIN_IN6_H */ diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h index 11dc659..33aec8c 100644 --- a/winsup/cygwin/include/cygwin/socket.h +++ b/winsup/cygwin/include/cygwin/socket.h @@ -152,9 +152,7 @@ struct OLD_msghdr #define AF_HYLINK 15 /* NSC Hyperchannel */ #define AF_APPLETALK 16 /* AppleTalk */ #define AF_NETBIOS 17 /* NetBios-style addresses */ -#if 0 /* Not yet */ #define AF_INET6 23 /* IP version 6 */ -#endif #define AF_MAX 32 /* @@ -180,9 +178,7 @@ struct OLD_msghdr #define PF_HYLINK AF_HYLINK #define PF_APPLETALK AF_APPLETALK #define PF_NETBIOS AF_NETBIOS -#if 0 #define PF_INET6 AF_INET6 -#endif #define PF_MAX AF_MAX @@ -236,6 +232,17 @@ struct OLD_msghdr #define IP_UNBLOCK_SOURCE 18 #define IP_PKTINFO 19 +/* IPv6 options for use with getsockopt/setsockopt */ +#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 + /* Old WinSock1 values, needed internally */ #ifdef __INSIDE_CYGWIN__ #define _WS1_IP_OPTIONS 1 diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index aeb5d75..ab2de7a 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -289,12 +289,14 @@ details. */ 154: Export sigset, sigignore. 155: Export __isinff, __isinfd, __isnanf, __isnand. 156: Export __srbuf_r, __swget_r. + 157: Export gai_strerror, getaddrinfo, getnameinfo, freeaddrinfo, + in6addr_any, in6addr_loopback. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 156 +#define CYGWIN_VERSION_API_MINOR 157 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/netdb.h b/winsup/cygwin/include/netdb.h index f49a943..89bb1e7 100644 --- a/winsup/cygwin/include/netdb.h +++ b/winsup/cygwin/include/netdb.h @@ -63,6 +63,9 @@ extern "C" { #endif +#include <stdint.h> +#include <cygwin/socket.h> + /* * Structures returned by network data base library. All addresses are * supplied in host order, and returned in network order (suitable for @@ -88,7 +91,7 @@ struct netent { char *n_name; /* official name of net */ char **n_aliases; /* alias list */ short n_addrtype; /* net address type */ - unsigned long n_net; /* network # */ + uint32_t n_net; /* network # */ }; struct servent { @@ -111,6 +114,17 @@ struct rpcent { int r_number; /* rpc program number */ }; +struct addrinfo { + int ai_flags; /* input flags */ + int ai_family; /* address family of socket */ + int ai_socktype; /* socket type */ + int ai_protocol; /* ai_protocol */ + socklen_t ai_addrlen; /* length of socket address */ + char *ai_canonname; /* canonical name of service location */ + struct sockaddr *ai_addr; /* socket address of socket */ + struct addrinfo *ai_next; /* pointer to next in list */ +}; + /* * Error return codes from gethostbyname() and gethostbyaddr() * (left in extern int h_errno). @@ -130,6 +144,45 @@ extern __declspec(dllimport) int h_errno; #define NO_DATA 4 /* Valid name, no data record of requested type */ #define NO_ADDRESS NO_DATA /* no address, look for MX record */ +#define AI_PASSIVE 1 +#define AI_CANONNAME 2 +#define AI_NUMERICHOST 4 +/* + * These are not available in the WinSock implementation. It wouldn't make + * sense to support them in the ipv4 only case, so we drop them entirely. + * We can define them if we run into problems but they are non-functional, so... + */ +#if 0 +#define AI_V4MAPPED 16 +#define AI_ALL 32 +#define AI_ADDRCONFIG 64 +#endif + +#define NI_NOFQDN 1 +#define NI_NUMERICHOST 2 +#define NI_NAMEREQD 4 +#define NI_NUMERICSERV 8 +#define NI_DGRAM 16 + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +#define EAI_ADDRFAMILY 1 +#define EAI_AGAIN 2 +#define EAI_BADFLAGS 3 +#define EAI_FAIL 4 +#define EAI_FAMILY 5 +#define EAI_MEMORY 6 +#define EAI_NODATA 7 +#define EAI_NONAME 8 +#define EAI_SERVICE 9 +#define EAI_SOCKTYPE 10 +#define EAI_SYSTEM 11 +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 + +#define EAI_MAX 14 + #ifndef __INSIDE_CYGWIN_NET__ void endhostent (void); void endnetent (void); @@ -158,6 +211,12 @@ void setnetent (int); void setprotoent (int); void setservent (int); void setrpcent (int); +void freeaddrinfo (struct addrinfo *); +const char *gai_strerror (int); +int getaddrinfo (const char *, const char *, + const struct addrinfo *, struct addrinfo **); +int getnameinfo (const struct sockaddr *, socklen_t, char *, + socklen_t, char *, socklen_t, int); #endif #ifdef __cplusplus diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 5856534..6391aee 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -40,6 +40,7 @@ details. */ #include "pinfo.h" #include "registry.h" #include "cygtls.h" +#include "cygwin/in6.h" extern "C" { @@ -50,6 +51,9 @@ extern "C" int sscanf (const char *, const char *, ...); } /* End of "C" section */ +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + static fhandler_socket * get (const int fd) { @@ -582,7 +586,8 @@ cygwin_socket (int af, int type, int protocol) debug_printf ("socket (%d, %d, %d)", af, type, protocol); - soc = socket (AF_INET, type, af == AF_LOCAL ? 0 : protocol); + soc = socket (af == AF_LOCAL ? AF_INET : af, type, + af == AF_LOCAL ? 0 : protocol); if (soc == INVALID_SOCKET) { @@ -592,10 +597,10 @@ cygwin_socket (int af, int type, int protocol) const device *dev; - if (af == AF_INET) - dev = type == SOCK_STREAM ? tcp_dev : udp_dev; - else + if (af == AF_LOCAL) dev = type == SOCK_STREAM ? stream_dev : dgram_dev; + else + dev = type == SOCK_STREAM ? tcp_dev : udp_dev; { cygheap_fdnew fd; @@ -2075,7 +2080,7 @@ socketpair (int family, int type, int protocol, int *sb) { sock_out.sin_family = AF_INET; sock_out.sin_port = 0; - sock_out.sin_addr.s_addr = INADDR_ANY; + sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0) { debug_printf ("bind failed"); @@ -2244,49 +2249,1381 @@ cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) return res; } -/* See "UNIX Network Programming, Networing APIs: Sockets and XTI", - W. Richard Stevens, Prentice Hall PTR, 1998. */ +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4 (const char *src, u_char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') + { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) + { + u_int ret = *tp * 10 + (pch - digits); + + if (ret > 255) + return (0); + *tp = ret; + if (! saw_digit) + { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } + else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6 (const char *src, u_char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), 0, IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') + { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) + { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) + { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) + { + if (tp + INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) + { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ extern "C" int -cygwin_inet_pton (int family, const char *strptr, void *addrptr) +cygwin_inet_pton (int af, const char *src, void *dst) +{ + switch (af) + { + case AF_INET: + return (inet_pton4(src, (u_char *) dst)); + case AF_INET6: + return (inet_pton6(src, (u_char *) dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4 (const u_char *src, char *dst, size_t size) { - if (family == AF_INET) + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + __small_sprintf(tmp, fmt, src[0], src[1], src[2], src[3]); + if (strlen(tmp) > size) { - struct in_addr in_val; + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} - if (cygwin_inet_aton (strptr, &in_val)) +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6 (const u_char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[IN6ADDRSZ / INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, 0, sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else + { + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && i < (best.base + best.len)) + { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { - memcpy (addrptr, &in_val, sizeof (struct in_addr)); - return 1; + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; } - return 0; + __small_sprintf(tp, "%x", words[i]); + tp += strlen(tp); } - set_errno (EAFNOSUPPORT); - return -1; + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t) (tp - tmp) > size) + { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); } -/* See "UNIX Network Programming, Networing APIs: Sockets and XTI", - W. Richard Stevens, Prentice Hall PTR, 1998. */ +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ extern "C" const char * -cygwin_inet_ntop (int family, const void *addrptr, char *strptr, socklen_t len) +cygwin_inet_ntop (int af, const void *src, char *dst, size_t size) { - const u_char *p = (const u_char *) addrptr; + switch (af) + { + case AF_INET: + return (inet_ntop4((const u_char *) src, dst, size)); + case AF_INET6: + return (inet_ntop6((const u_char *) src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - if (family == AF_INET) +/* W. Richard STEVENS libgai implementation, slightly tweaked for inclusion + into Cygwin as pure IPv4 replacement. Please note that the code is + kept intact as much as possible. Especially the IPv6 and AF_UNIX code + is kept in, even though we can support neither of them. Please don't + activate them, they won't work correctly. */ + +#define IPv4 +#undef IPv6 +#undef UNIXdomain + +#undef HAVE_SOCKADDR_SA_LEN +#define gethostbyname2(host,family) cygwin_gethostbyname((host)) + +#define AI_CLONE 0x8000 /* Avoid collision with AI_ values in netdb.h */ + +/* + * Create and fill in an addrinfo{}. + */ + +/* include ga_aistruct1 */ +static int +ga_aistruct (struct addrinfo ***paipnext, const struct addrinfo *hintsp, + const void *addr, int family) +{ + struct addrinfo *ai; + + if ((ai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) + return (EAI_MEMORY); + ai->ai_next = NULL; + ai->ai_canonname = NULL; + **paipnext = ai; + *paipnext = &ai->ai_next; + + if ((ai->ai_socktype = hintsp->ai_socktype) == 0) + ai->ai_flags |= AI_CLONE; + + ai->ai_protocol = hintsp->ai_protocol; +/* end ga_aistruct1 */ + +/* include ga_aistruct2 */ + switch ((ai->ai_family = family)) + { +#ifdef IPv4 + case AF_INET: + { + struct sockaddr_in *sinptr; + + /* 4allocate sockaddr_in{} and fill in all but port */ + if ((sinptr = (struct sockaddr_in *) + calloc (1, sizeof (struct sockaddr_in))) == NULL) + return (EAI_MEMORY); +#ifdef HAVE_SOCKADDR_SA_LEN + sinptr->sin_len = sizeof (struct sockaddr_in); +#endif + sinptr->sin_family = AF_INET; + memcpy (&sinptr->sin_addr, addr, sizeof (struct in_addr)); + ai->ai_addr = (struct sockaddr *) sinptr; + ai->ai_addrlen = sizeof (struct sockaddr_in); + break; + } +#endif /* IPV4 */ +#ifdef IPv6 + case AF_INET6: + { + struct sockaddr_in6 *sin6ptr; + + /* 4allocate sockaddr_in6{} and fill in all but port */ + if ((sin6ptr = calloc (1, sizeof (struct sockaddr_in6))) == NULL) + return (EAI_MEMORY); +#ifdef HAVE_SOCKADDR_SA_LEN + sin6ptr->sin6_len = sizeof (struct sockaddr_in6); +#endif + sin6ptr->sin6_family = AF_INET6; + memcpy (&sin6ptr->sin6_addr, addr, sizeof (struct in6_addr)); + ai->ai_addr = (struct sockaddr *) sin6ptr; + ai->ai_addrlen = sizeof (struct sockaddr_in6); + break; + } +#endif /* IPV6 */ +#ifdef UNIXdomain + case AF_LOCAL: + { + struct sockaddr_un *unp; + + /* 4allocate sockaddr_un{} and fill in */ +/* *INDENT-OFF* */ + if (strlen(addr) >= sizeof(unp->sun_path)) + return(EAI_SERVICE); + if ( (unp = calloc(1, sizeof(struct sockaddr_un))) == NULL) + return(EAI_MEMORY); +/* *INDENT-ON* */ + unp->sun_family = AF_LOCAL; + strcpy (unp->sun_path, addr); +#ifdef HAVE_SOCKADDR_SA_LEN + unp->sun_len = SUN_LEN (unp); +#endif + ai->ai_addr = (struct sockaddr *) unp; + ai->ai_addrlen = sizeof (struct sockaddr_un); + if (hintsp->ai_flags & AI_PASSIVE) + unlink (unp->sun_path); /* OK if this fails */ + break; + } +#endif /* UNIXDOMAIN */ + } + return (0); +} + +/* end ga_aistruct2 */ + +/* + * Clone a new addrinfo structure from an existing one. + */ + +/* include ga_clone */ +static struct addrinfo * +ga_clone (struct addrinfo *ai) +{ + struct addrinfo *nai; + + if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) + return (NULL); + + nai->ai_next = ai->ai_next; + ai->ai_next = nai; + + nai->ai_flags = 0; /* make sure AI_CLONE is off */ + nai->ai_family = ai->ai_family; + nai->ai_socktype = ai->ai_socktype; + nai->ai_protocol = ai->ai_protocol; + nai->ai_canonname = NULL; + nai->ai_addrlen = ai->ai_addrlen; + if ((nai->ai_addr = (struct sockaddr *) malloc (ai->ai_addrlen)) == NULL) + return (NULL); + memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return (nai); +} + +/* end ga_clone */ + +/* + * Basic error checking of flags, family, socket type, and protocol. + */ + +/* include ga_echeck */ +static int +ga_echeck (const char *hostname, const char *servname, + int flags, int family, int socktype, int protocol) +{ + if (flags & ~(AI_PASSIVE | AI_CANONNAME)) + return (EAI_BADFLAGS); /* unknown flag bits */ + + if (hostname == NULL || hostname[0] == '\0') { - char temp[64]; /* Big enough for 4 ints ... */ + if (servname == NULL || servname[0] == '\0') + return (EAI_NONAME); /* host or service must be specified */ + } + + switch (family) + { + case AF_UNSPEC: + break; +#ifdef IPv4 + case AF_INET: + if (socktype != 0 && + (socktype != SOCK_STREAM && + socktype != SOCK_DGRAM && socktype != SOCK_RAW)) + return (EAI_SOCKTYPE); /* invalid socket type */ + break; +#endif +#ifdef IPv6 + case AF_INET6: + if (socktype != 0 && + (socktype != SOCK_STREAM && + socktype != SOCK_DGRAM && socktype != SOCK_RAW)) + return (EAI_SOCKTYPE); /* invalid socket type */ + break; +#endif +#ifdef UNIXdomain + case AF_LOCAL: + if (socktype != 0 && + (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)) + return (EAI_SOCKTYPE); /* invalid socket type */ + break; +#endif + default: + return (EAI_FAMILY); /* unknown protocol family */ + } + return (0); +} + +/* end ga_echeck */ + +struct search { + const char *host; /* hostname or address string */ + int family; /* AF_xxx */ +}; + +/* + * Set up the search[] array with the hostnames and address families + * that we are to look up. + */ - __small_sprintf (temp, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]); - if (strlen (temp) >= (size_t) len) +/* include ga_nsearch1 */ +static int +ga_nsearch (const char *hostname, const struct addrinfo *hintsp, + struct search *search) +{ + int nsearch = 0; + + if (hostname == NULL || hostname[0] == '\0') + { + if (hintsp->ai_flags & AI_PASSIVE) { - set_errno (ENOSPC); - return NULL; + /* 4no hostname and AI_PASSIVE: implies wildcard bind */ + switch (hintsp->ai_family) + { +#ifdef IPv4 + case AF_INET: + search[nsearch].host = "0.0.0.0"; + search[nsearch].family = AF_INET; + nsearch++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + search[nsearch].host = "0::0"; + search[nsearch].family = AF_INET6; + nsearch++; + break; +#endif + case AF_UNSPEC: +#ifdef IPv6 + search[nsearch].host = "0::0"; /* IPv6 first, then IPv4 */ + search[nsearch].family = AF_INET6; + nsearch++; +#endif +#ifdef IPv4 + search[nsearch].host = "0.0.0.0"; + search[nsearch].family = AF_INET; + nsearch++; +#endif + break; + } +/* end ga_nsearch1 */ +/* include ga_nsearch2 */ + } + else + { + /* 4no host and not AI_PASSIVE: connect to local host */ + switch (hintsp->ai_family) + { +#ifdef IPv4 + case AF_INET: + search[nsearch].host = "localhost"; /* 127.0.0.1 */ + search[nsearch].family = AF_INET; + nsearch++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + search[nsearch].host = "0::1"; + search[nsearch].family = AF_INET6; + nsearch++; + break; +#endif + case AF_UNSPEC: +#ifdef IPv6 + search[nsearch].host = "0::1"; /* IPv6 first, then IPv4 */ + search[nsearch].family = AF_INET6; + nsearch++; +#endif +#ifdef IPv4 + search[nsearch].host = "localhost"; + search[nsearch].family = AF_INET; + nsearch++; +#endif + break; + } + } +/* end ga_nsearch2 */ +/* include ga_nsearch3 */ + } + else + { /* host is specified */ + switch (hintsp->ai_family) + { +#ifdef IPv4 + case AF_INET: + search[nsearch].host = hostname; + search[nsearch].family = AF_INET; + nsearch++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + search[nsearch].host = hostname; + search[nsearch].family = AF_INET6; + nsearch++; + break; +#endif + case AF_UNSPEC: +#ifdef IPv6 + search[nsearch].host = hostname; + search[nsearch].family = AF_INET6; /* IPv6 first */ + nsearch++; +#endif +#ifdef IPv4 + search[nsearch].host = hostname; + search[nsearch].family = AF_INET; /* then IPv4 */ + nsearch++; +#endif + break; + } + } + if (nsearch < 1 || nsearch > 2) + return -1; + return (nsearch); +} + +/* end ga_nsearch3 */ + +/* + * Go through all the addrinfo structures, checking for a match of the + * socket type and filling in the socket type, and then the port number + * in the corresponding socket address structures. + * + * The AI_CLONE flag works as follows. Consider a multihomed host with + * two IP addresses and no socket type specified by the caller. After + * the "host" search there are two addrinfo structures, one per IP address. + * Assuming a service supported by both TCP and UDP (say the daytime + * service) we need to return *four* addrinfo structures: + * IP#1, SOCK_STREAM, TCP port, + * IP#1, SOCK_DGRAM, UDP port, + * IP#2, SOCK_STREAM, TCP port, + * IP#2, SOCK_DGRAM, UDP port. + * To do this, when the "host" loop creates an addrinfo structure, if the + * caller has not specified a socket type (hintsp->ai_socktype == 0), the + * AI_CLONE flag is set. When the following function finds an entry like + * this it is handled as follows: If the entry's ai_socktype is still 0, + * this is the first use of the structure, and the ai_socktype field is set. + * But, if the entry's ai_socktype is nonzero, then we clone a new addrinfo + * structure and set it's ai_socktype to the new value. Although we only + * need two socket types today (SOCK_STREAM and SOCK_DGRAM) this algorithm + * will handle any number. Also notice that Posix.1g requires all socket + * types to be nonzero. + */ + +/* include ga_port */ +static int +ga_port (struct addrinfo *aihead, int port, int socktype) + /* port must be in network byte order */ +{ + int nfound = 0; + struct addrinfo *ai; + + for (ai = aihead; ai != NULL; ai = ai->ai_next) + { + if (ai->ai_flags & AI_CLONE) + { + if (ai->ai_socktype != 0) + { + if ((ai = ga_clone (ai)) == NULL) + return (-1); /* memory allocation error */ + /* ai points to newly cloned entry, which is what we want */ + } + } + else if (ai->ai_socktype != socktype) + continue; /* ignore if mismatch on socket type */ + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { +#ifdef IPv4 + case AF_INET: + ((struct sockaddr_in *) ai->ai_addr)->sin_port = port; + nfound++; + break; +#endif +#ifdef IPv6 + case AF_INET6: + ((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port; + nfound++; + break; +#endif } - strcpy (strptr, temp); - return strptr; } - set_errno (EAFNOSUPPORT); - return NULL; + return (nfound); } + +/* end ga_port */ + +/* + * This function handles the service string. + */ + +/* include ga_serv */ +static int +ga_serv (struct addrinfo *aihead, const struct addrinfo *hintsp, + const char *serv) +{ + int port, rc, nfound; + struct servent *sptr; + + nfound = 0; + if (isdigit (serv[0])) + { /* check for port number string first */ + port = htons (atoi (serv)); + if (hintsp->ai_socktype) + { + /* 4caller specifies socket type */ + if ((rc = ga_port (aihead, port, hintsp->ai_socktype)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + else + { + /* 4caller does not specify socket type */ + if ((rc = ga_port (aihead, port, SOCK_STREAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + if ((rc = ga_port (aihead, port, SOCK_DGRAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + } + else + { + /* 4try service name, TCP then UDP */ + if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_STREAM) + { + if ((sptr = cygwin_getservbyname (serv, "tcp")) != NULL) + { + if ((rc = ga_port (aihead, sptr->s_port, SOCK_STREAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + } + if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_DGRAM) + { + if ((sptr = cygwin_getservbyname (serv, "udp")) != NULL) + { + if ((rc = ga_port (aihead, sptr->s_port, SOCK_DGRAM)) < 0) + return (EAI_MEMORY); + nfound += rc; + } + } + } + + if (nfound == 0) + { + if (hintsp->ai_socktype == 0) + return (EAI_NONAME); /* all calls to getservbyname() failed */ + else + return (EAI_SERVICE); /* service not supported for socket type */ + } + return (0); +} + +/* end ga_serv */ + +#ifdef UNIXdomain +/* include ga_unix */ +static int +ga_unix (const char *path, struct addrinfo *hintsp, struct addrinfo **result) +{ + int rc; + struct addrinfo *aihead, **aipnext; + + aihead = NULL; + aipnext = &aihead; + + if (hintsp->ai_family != AF_UNSPEC && hintsp->ai_family != AF_LOCAL) + return (EAI_ADDRFAMILY); + + if (hintsp->ai_socktype == 0) + { + /* 4no socket type specified: return stream then dgram */ + hintsp->ai_socktype = SOCK_STREAM; + if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0) + return (rc); + hintsp->ai_socktype = SOCK_DGRAM; + } + + if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0) + return (rc); + + if (hintsp->ai_flags & AI_CANONNAME) + { + struct utsname myname; + + if (uname (&myname) < 0) + return (EAI_SYSTEM); + if ((aihead->ai_canonname = strdup (myname.nodename)) == NULL) + return (EAI_MEMORY); + } + + *result = aihead; /* pointer to first structure in linked list */ + return (0); +} + +/* end ga_unix */ +#endif /* UNIXdomain */ + +/* include gn_ipv46 */ +static int +gn_ipv46 (char *host, size_t hostlen, char *serv, size_t servlen, + void *aptr, size_t alen, int family, int port, int flags) +{ + char *ptr; + struct hostent *hptr; + struct servent *sptr; + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL) + return (1); + } + else + { + hptr = cygwin_gethostbyaddr ((const char *) aptr, alen, family); + if (hptr != NULL && hptr->h_name != NULL) + { + if (flags & NI_NOFQDN) + { + if ((ptr = strchr (hptr->h_name, '.')) != NULL) + *ptr = 0; /* overwrite first dot */ + } + //snprintf (host, hostlen, "%s", hptr->h_name); + *host = '\0'; + strncat (host, hptr->h_name, hostlen - 1); + } + else + { + if (flags & NI_NAMEREQD) + return (1); + if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL) + return (1); + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + //snprintf (serv, servlen, "%d", ntohs (port)); + char buf[32]; + __small_sprintf (buf, "%d", ntohs (port)); + *serv = '\0'; + strncat (serv, buf, servlen - 1); + } + else + { + sptr = cygwin_getservbyport (port, (flags & NI_DGRAM) ? "udp" : NULL); + if (sptr != NULL && sptr->s_name != NULL) + { + //snprintf (serv, servlen, "%s", sptr->s_name); + *serv = '\0'; + strncat (serv, sptr->s_name, servlen - 1); + } + else + { + //snprintf (serv, servlen, "%d", ntohs (port)); + char buf[32]; + __small_sprintf (buf, "%d", ntohs (port)); + *serv = '\0'; + strncat (serv, buf, servlen - 1); + } + } + } + return (0); +} + +/* end gn_ipv46 */ + +/* include freeaddrinfo */ +void +ipv4_freeaddrinfo (struct addrinfo *aihead) +{ + struct addrinfo *ai, *ainext; + + for (ai = aihead; ai != NULL; ai = ainext) + { + if (ai->ai_addr != NULL) + free (ai->ai_addr); /* socket address structure */ + + if (ai->ai_canonname != NULL) + free (ai->ai_canonname); + + ainext = ai->ai_next; /* can't fetch ai_next after free() */ + free (ai); /* the addrinfo{} itself */ + } +} + +/* end freeaddrinfo */ + +/* include ga1 */ + +int +ipv4_getaddrinfo (const char *hostname, const char *servname, + const struct addrinfo *hintsp, struct addrinfo **result) +{ + int rc, error, nsearch; + char **ap, *canon; + struct hostent *hptr; + struct search search[3], *sptr; + struct addrinfo hints, *aihead, **aipnext; + + /* + * If we encounter an error we want to free() any dynamic memory + * that we've allocated. This is our hack to simplify the code. + */ +#define error(e) { error = (e); goto bad; } + + aihead = NULL; /* initialize automatic variables */ + aipnext = &aihead; + canon = NULL; + + if (hintsp == NULL) + { + bzero (&hints, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + } + else + hints = *hintsp; /* struct copy */ + + /* 4first some basic error checking */ + if ((rc = ga_echeck (hostname, servname, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol)) != 0) + error (rc); + +#ifdef UNIXdomain + /* 4special case Unix domain first */ + if (hostname != NULL && + (strcmp (hostname, "/local") == 0 || strcmp (hostname, "/unix") == 0) && + (servname != NULL && servname[0] == '/')) + return (ga_unix (servname, &hints, result)); +#endif +/* end ga1 */ + +/* include ga3 */ + /* 4remainder of function for IPv4/IPv6 */ + nsearch = ga_nsearch (hostname, &hints, &search[0]); + if (nsearch == -1) + error (EAI_FAMILY); + for (sptr = &search[0]; sptr < &search[nsearch]; sptr++) + { +#ifdef IPv4 + /* 4check for an IPv4 dotted-decimal string */ + if (isdigit (sptr->host[0])) + { + struct in_addr inaddr; + + if (inet_pton4 (sptr->host, (u_char *) &inaddr) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) + error (EAI_ADDRFAMILY); + if (sptr->family != AF_INET) + continue; /* ignore */ + rc = ga_aistruct (&aipnext, &hints, &inaddr, AF_INET); + if (rc != 0) + error (rc); + continue; + } + } +#endif + +#ifdef IPv6 + /* 4check for an IPv6 hex string */ + if ((isxdigit (sptr->host[0]) || sptr->host[0] == ':') && + (strchr (sptr->host, ':') != NULL)) + { + struct in6_addr in6addr; + + if (inet_pton6 (sptr->host, &in6addr) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) + error (EAI_ADDRFAMILY); + if (sptr->family != AF_INET6) + continue; /* ignore */ + rc = ga_aistruct (&aipnext, &hints, &in6addr, AF_INET6); + if (rc != 0) + error (rc); + continue; + } + } +#endif +/* end ga3 */ +/* include ga4 */ +#ifdef IPv6 + /* 4remainder of for() to look up hostname */ + if ((_res.options & RES_INIT) == 0) + res_init (); /* need this to set _res.options */ +#endif + + if (nsearch == 2) + { +#ifdef IPv6 + _res.options &= ~RES_USE_INET6; +#endif + hptr = gethostbyname2 (sptr->host, sptr->family); + } + else + { +#ifdef IPv6 + if (sptr->family == AF_INET6) + _res.options |= RES_USE_INET6; + else + _res.options &= ~RES_USE_INET6; +#endif + hptr = gethostbyname (sptr->host); + } + if (hptr == NULL) + { + if (nsearch == 2) + continue; /* failure OK if multiple searches */ + + switch (h_errno) + { + case HOST_NOT_FOUND: + error (EAI_NONAME); + case TRY_AGAIN: + error (EAI_AGAIN); + case NO_RECOVERY: + error (EAI_FAIL); + case NO_DATA: + error (EAI_NODATA); + default: + error (EAI_NONAME); + } + } + + /* 4check for address family mismatch if one specified */ + if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) + error (EAI_ADDRFAMILY); + + /* 4save canonical name first time */ + if (hostname != NULL && hostname[0] != '\0' && + (hints.ai_flags & AI_CANONNAME) && canon == NULL) + { + if ((canon = strdup (hptr->h_name)) == NULL) + error (EAI_MEMORY); + } + + /* 4create one addrinfo{} for each returned address */ + for (ap = hptr->h_addr_list; *ap != NULL; ap++) + { + rc = ga_aistruct (&aipnext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + error (rc); + } + } + if (aihead == NULL) + error (EAI_NONAME); /* nothing found */ +/* end ga4 */ + +/* include ga5 */ + /* 4return canonical name */ + if (hostname != NULL && hostname[0] != '\0' && + hints.ai_flags & AI_CANONNAME) + { + if (canon != NULL) + aihead->ai_canonname = canon; /* strdup'ed earlier */ + else + { + if ((aihead->ai_canonname = strdup (search[0].host)) == NULL) + error (EAI_MEMORY); + } + } + + /* 4now process the service name */ + if (servname != NULL && servname[0] != '\0') + { + if ((rc = ga_serv (aihead, &hints, servname)) != 0) + error (rc); + } + + *result = aihead; /* pointer to first structure in linked list */ + return (0); + +bad: + ipv4_freeaddrinfo (aihead); /* free any alloc'ed memory */ + return (error); +} + +/* end ga5 */ + +/* include getnameinfo */ +int +ipv4_getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, int flags) +{ + + switch (sa->sa_family) + { +#ifdef IPv4 + case AF_INET: + { + struct sockaddr_in *sain = (struct sockaddr_in *) sa; + + return (gn_ipv46 (host, hostlen, serv, servlen, + &sain->sin_addr, sizeof (struct in_addr), + AF_INET, sain->sin_port, flags)); + } +#endif + +#ifdef IPv6 + case AF_INET6: + { + struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa; + + return (gn_ipv46 (host, hostlen, serv, servlen, + &sain->sin6_addr, sizeof (struct in6_addr), + AF_INET6, sain->sin6_port, flags)); + } +#endif + +#ifdef UNIXdomain + case AF_LOCAL: + { + struct sockaddr_un *un = (struct sockaddr_un *) sa; + + if (hostlen > 0) + snprintf (host, hostlen, "%s", "/local"); + if (servlen > 0) + snprintf (serv, servlen, "%s", un->sun_path); + return (0); + } +#endif + + default: + return (1); + } +} + +/* end getnameinfo */ + +/* Start of cygwin specific wrappers around the gai functions. */ + +struct gai_errmap_t +{ + int w32_errval; + const char *errtxt; +}; + +static gai_errmap_t gai_errmap[] = +{ + {0, "Success"}, + {0, "Address family for hostname not supported"}, + {WSATRY_AGAIN, "Temporary failure in name resolution"}, + {WSAEINVAL, "Invalid value for ai_flags"}, + {WSANO_RECOVERY, "Non-recoverable failure in name resolution"}, + {WSAEAFNOSUPPORT, "ai_family not supported"}, + {WSA_NOT_ENOUGH_MEMORY, "Memory allocation failure"}, + {WSANO_DATA, "No address associated with hostname"}, + {WSAHOST_NOT_FOUND, "hostname nor servname provided, or not known"}, + {WSATYPE_NOT_FOUND, "servname not supported for ai_socktype"}, + {WSAESOCKTNOSUPPORT, "ai_socktype not supported"}, + {0, "System error returned in errno"}, + {0, "Invalid value for hints"}, + {0, "Resolved protocol is unknown"} +}; + +extern "C" const char * +cygwin_gai_strerror (int err) +{ + if (err >= 0 && err < EAI_MAX) + return gai_errmap[err].errtxt; + return "Unknown error"; +} + +static int +w32_to_gai_err (int w32_err) +{ + if (w32_err >= WSABASEERR) + for (int i = 0; i < EAI_MAX; ++i) + if (gai_errmap[i].w32_errval == w32_err) + return i; + return w32_err; +} + +/* We can't use autoload here because we don't know where the functions + are loaded from. On Win2K, the functions are available in the + ipv6 technology preview lib called wship6.dll, in XP and above they + are implemented in ws2_32.dll. For older systems we use the ipv4-only + version above. */ + +static void (WINAPI *freeaddrinfo)(const struct addrinfo *); +static int (WINAPI *getaddrinfo)(const char *, const char *, + const struct addrinfo *, + struct addrinfo **); +static int (WINAPI *getnameinfo)(const struct sockaddr *, socklen_t, + char *, size_t, char *, size_t, int); +static bool +get_ipv6_funcs (HMODULE lib) +{ + return ((freeaddrinfo = (void (WINAPI *)(const struct addrinfo *)) + GetProcAddress(lib, "freeaddrinfo")) + && (getaddrinfo = (int (WINAPI *)(const char *, const char *, + const struct addrinfo *, + struct addrinfo **)) + GetProcAddress(lib, "getaddrinfo")) + && (getnameinfo = (int (WINAPI *)(const struct sockaddr *, + socklen_t, char *, size_t, + char *, size_t, int)) + GetProcAddress(lib, "getnameinfo"))); +} + +static NO_COPY muto load_ipv6_guard; +static bool ipv6_inited = false; +#define load_ipv6() if (!ipv6_inited) load_ipv6_funcs (); + +static void +load_ipv6_funcs () +{ + + char lib_name[CYG_MAX_PATH]; + size_t len; + HMODULE lib; + + load_ipv6_guard.init ("klog_guard")->acquire (); + if (ipv6_inited) + goto out; + WSAGetLastError (); /* Kludge. Enforce WSAStartup call. */ + if (GetSystemDirectory (lib_name, CYG_MAX_PATH)) + { + len = strlen (lib_name); + strcpy (lib_name + len, "\\ws2_32.dll"); + if ((lib = LoadLibrary (lib_name))) + { + if (get_ipv6_funcs (lib)) + goto out; + FreeLibrary (lib); + } + strcpy (lib_name + len, "\\wship6.dll"); + if ((lib = LoadLibrary (lib_name))) + { + if (get_ipv6_funcs (lib)) + goto out; + FreeLibrary (lib); + } + freeaddrinfo = NULL; + getaddrinfo = NULL; + getnameinfo = NULL; + } +out: + ipv6_inited = true; + load_ipv6_guard.release (); +} + +extern "C" void +cygwin_freeaddrinfo (struct addrinfo *addr) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return; + load_ipv6 (); + if (freeaddrinfo) + freeaddrinfo (addr); + else + ipv4_freeaddrinfo (addr); +} + +extern "C" int +cygwin_getaddrinfo (const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return EAI_SYSTEM; + load_ipv6 (); + if (getaddrinfo) + return w32_to_gai_err (getaddrinfo (hostname, servname, hints, res)); + return ipv4_getaddrinfo (hostname, servname, hints, res); +} + +extern "C" int +cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, char *serv, + size_t servlen, int flags) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return EAI_SYSTEM; + load_ipv6 (); + if (getnameinfo) + { + /* When the incoming port number is set to 0, Winsock's getnameinfo + returns with error WSAENO_DATA instead of simply ignoring the port. + To avoid this strange behaviour, we check manually, if the port number + is 0. If so, set the NI_NUMERICSERV flag to avoid this problem. */ + switch (sa->sa_family) + { + case AF_INET: + if (((struct sockaddr_in *) sa)->sin_port == 0) + flags |= NI_NUMERICSERV; + break; + case AF_INET6: + if (((struct sockaddr_in6 *) sa)->sin6_port == 0) + flags |= NI_NUMERICSERV; + break; + } + int ret = w32_to_gai_err (getnameinfo (sa, salen, host, hostlen, serv, + servlen, flags)); + if (ret) + set_winsock_errno (); + return ret; + } + return ipv4_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags); +} + |