diff options
Diffstat (limited to 'winsup/cygwin/net.cc')
-rw-r--r-- | winsup/cygwin/net.cc | 3740 |
1 files changed, 0 insertions, 3740 deletions
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc deleted file mode 100644 index 5c4959bdf..000000000 --- a/winsup/cygwin/net.cc +++ /dev/null @@ -1,3740 +0,0 @@ -/* net.cc: network-related routines. - - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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. */ - -/* #define DEBUG_NEST_ON 1 */ - -#define __INSIDE_CYGWIN_NET__ -#define USE_SYS_TYPES_FD_SET -#define __WSA_ERR_MACROS_DEFINED -/* FIXME: Collision with different declarations of if_nametoindex and - if_indextoname functions in iphlpapi.h since Vista. - TODO: Convert if_nametoindex to cygwin_if_nametoindex and call - system functions on Vista and later. */ -#define _INC_NETIOAPI -#include "winsup.h" -#ifdef __x86_64__ -/* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte) - because a redefinition for LP64 systems is missing. This leads to a wrong - definition and size of sockaddr_in6 when building with winsock headers. - This definition is also required to use the right u_long type in subsequent - function calls. */ -#undef u_long -#define u_long __ms_u_long -#endif -#include <ws2tcpip.h> -#include <mswsock.h> -#include <iphlpapi.h> -#include "miscfuncs.h" -#include <ctype.h> -#include <wchar.h> -#include <stdlib.h> -#define gethostname cygwin_gethostname -#include <unistd.h> -#undef gethostname -#include <netdb.h> -#include <cygwin/in.h> -#include <asm/byteorder.h> -#include <assert.h> -#include "cygerrno.h" -#include "security.h" -#include "cygwin/version.h" -#include "shared_info.h" -#include "perprocess.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "cygheap.h" -#include "sigproc.h" -#include "registry.h" -#include "cygtls.h" -#include "ifaddrs.h" -#include "tls_pbuf.h" -#include "ntdll.h" - -/* Unfortunately defined in Windows header files and arpa/nameser_compat.h. */ -#undef NOERROR -#undef DELETE -#define _CYGWIN_IN_H -#include <resolv.h> - -extern "C" -{ - int h_errno; - - int __stdcall rcmd (char **ahost, unsigned short inport, char *locuser, - char *remuser, char *cmd, SOCKET * fd2p); - int sscanf (const char *, const char *, ...); - int cygwin_inet_aton(const char *, struct in_addr *); - const char *cygwin_inet_ntop (int, const void *, char *, socklen_t); - int dn_length1(const unsigned char *, const unsigned char *, - const unsigned 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) -{ - cygheap_fdget cfd (fd); - - if (cfd < 0) - return 0; - - fhandler_socket *const fh = cfd->is_socket (); - - if (!fh) - set_errno (ENOTSOCK); - - return fh; -} - -/* exported as inet_ntoa: BSD 4.3 */ -extern "C" char * -cygwin_inet_ntoa (struct in_addr in) -{ - char buf[20]; - const char *res = cygwin_inet_ntop (AF_INET, &in, buf, sizeof buf); - - if (_my_tls.locals.ntoa_buf) - { - free (_my_tls.locals.ntoa_buf); - _my_tls.locals.ntoa_buf = NULL; - } - if (res) - _my_tls.locals.ntoa_buf = strdup (res); - return _my_tls.locals.ntoa_buf; -} - -/* inet_netof is in the standard BSD sockets library. It is useless - for modern networks, since it assumes network values which are no - longer meaningful, but some existing code calls it. */ - -extern "C" unsigned long -inet_netof (struct in_addr in) -{ - unsigned long i, res; - - i = ntohl (in.s_addr); - if (IN_CLASSA (i)) - res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; - else if (IN_CLASSB (i)) - res = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; - else - res = (i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT; - - return res; -} - -/* inet_makeaddr is in the standard BSD sockets library. It is - useless for modern networks, since it assumes network values which - are no longer meaningful, but some existing code calls it. */ - -extern "C" struct in_addr -inet_makeaddr (int net, int lna) -{ - unsigned long i; - struct in_addr in; - - if (net < IN_CLASSA_MAX) - i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST); - else if (net < IN_CLASSB_MAX) - i = (net << IN_CLASSB_NSHIFT) | (lna & IN_CLASSB_HOST); - else if (net < 0x1000000) - i = (net << IN_CLASSC_NSHIFT) | (lna & IN_CLASSC_HOST); - else - i = net | lna; - - in.s_addr = htonl (i); - - - return in; -} - -struct tl -{ - int w; - const char *s; - int e; -}; - -static const struct tl errmap[] = { - {WSAEINTR, "WSAEINTR", EINTR}, - {WSAEWOULDBLOCK, "WSAEWOULDBLOCK", EWOULDBLOCK}, - {WSAEINPROGRESS, "WSAEINPROGRESS", EINPROGRESS}, - {WSAEALREADY, "WSAEALREADY", EALREADY}, - {WSAENOTSOCK, "WSAENOTSOCK", ENOTSOCK}, - {WSAEDESTADDRREQ, "WSAEDESTADDRREQ", EDESTADDRREQ}, - {WSAEMSGSIZE, "WSAEMSGSIZE", EMSGSIZE}, - {WSAEPROTOTYPE, "WSAEPROTOTYPE", EPROTOTYPE}, - {WSAENOPROTOOPT, "WSAENOPROTOOPT", ENOPROTOOPT}, - {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", EPROTONOSUPPORT}, - {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, - {WSAEOPNOTSUPP, "WSAEOPNOTSUPP", EOPNOTSUPP}, - {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", EPFNOSUPPORT}, - {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", EAFNOSUPPORT}, - {WSAEADDRINUSE, "WSAEADDRINUSE", EADDRINUSE}, - {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", EADDRNOTAVAIL}, - {WSAENETDOWN, "WSAENETDOWN", ENETDOWN}, - {WSAENETUNREACH, "WSAENETUNREACH", ENETUNREACH}, - {WSAENETRESET, "WSAENETRESET", ENETRESET}, - {WSAECONNABORTED, "WSAECONNABORTED", ECONNABORTED}, - {WSAECONNRESET, "WSAECONNRESET", ECONNRESET}, - {WSAENOBUFS, "WSAENOBUFS", ENOBUFS}, - {WSAEISCONN, "WSAEISCONN", EISCONN}, - {WSAENOTCONN, "WSAENOTCONN", ENOTCONN}, - {WSAESHUTDOWN, "WSAESHUTDOWN", ESHUTDOWN}, - {WSAETOOMANYREFS, "WSAETOOMANYREFS", ETOOMANYREFS}, - {WSAETIMEDOUT, "WSAETIMEDOUT", ETIMEDOUT}, - {WSAECONNREFUSED, "WSAECONNREFUSED", ECONNREFUSED}, - {WSAELOOP, "WSAELOOP", ELOOP}, - {WSAENAMETOOLONG, "WSAENAMETOOLONG", ENAMETOOLONG}, - {WSAEHOSTDOWN, "WSAEHOSTDOWN", EHOSTDOWN}, - {WSAEHOSTUNREACH, "WSAEHOSTUNREACH", EHOSTUNREACH}, - {WSAENOTEMPTY, "WSAENOTEMPTY", ENOTEMPTY}, - {WSAEPROCLIM, "WSAEPROCLIM", EPROCLIM}, - {WSAEUSERS, "WSAEUSERS", EUSERS}, - {WSAEDQUOT, "WSAEDQUOT", EDQUOT}, - {WSAESTALE, "WSAESTALE", ESTALE}, - {WSAEREMOTE, "WSAEREMOTE", EREMOTE}, - {WSAEINVAL, "WSAEINVAL", EINVAL}, - {WSAEFAULT, "WSAEFAULT", EFAULT}, - {0, "NOERROR", 0}, - {0, NULL, 0} -}; - -static int -find_winsock_errno (int why) -{ - for (int i = 0; errmap[i].s != NULL; ++i) - if (why == errmap[i].w) - return errmap[i].e; - - return EPERM; -} - -void -__set_winsock_errno (const char *fn, int ln) -{ - DWORD werr = WSAGetLastError (); - int err = find_winsock_errno (werr); - - set_errno (err); - syscall_printf ("%s:%d - winsock error %u -> errno %d", fn, ln, werr, err); -} - -/* - * Since the member `s' isn't used for debug output we can use it - * for the error text returned by herror and hstrerror. - */ -static const struct tl host_errmap[] = { - {WSAHOST_NOT_FOUND, "Unknown host", HOST_NOT_FOUND}, - {WSATRY_AGAIN, "Host name lookup failure", TRY_AGAIN}, - {WSANO_RECOVERY, "Unknown server error", NO_RECOVERY}, - {WSANO_DATA, "No address associated with name", NO_DATA}, - {0, NULL, 0} -}; - -static void -set_host_errno () -{ - int i; - - int why = WSAGetLastError (); - - for (i = 0; host_errmap[i].w != 0; ++i) - if (why == host_errmap[i].w) - break; - - if (host_errmap[i].w != 0) - h_errno = host_errmap[i].e; - else - h_errno = NETDB_INTERNAL; -} - -inline int -DWORD_round (int n) -{ - return sizeof (DWORD) * (((n + sizeof (DWORD) - 1)) / sizeof (DWORD)); -} - -inline int -strlen_round (const char *s) -{ - if (!s) - return 0; - return DWORD_round (strlen (s) + 1); -} - -#pragma pack(push,2) -struct pservent -{ - char *s_name; - char **s_aliases; - short s_port; - char *s_proto; -}; -#pragma pack(pop) - -static const char *entnames[] = {"host", "proto", "serv"}; - -static unionent * -realloc_ent (unionent *&dst, int sz) -{ - /* Allocate the storage needed. Allocate a rounded size to attempt to force - reuse of this buffer so that a poorly-written caller will not be using - a freed buffer. */ - unsigned rsz = 256 * ((sz + 255) / 256); - unionent * ptr; - if ((ptr = (unionent *) realloc (dst, rsz))) - dst = ptr; - return ptr; -} - -static inline hostent * -realloc_ent (int sz, hostent *) -{ - return (hostent *) realloc_ent (_my_tls.locals.hostent_buf, sz); -} - -/* Generic "dup a {host,proto,serv}ent structure" function. - This is complicated because we need to be able to free the - structure at any point and we can't rely on the pointer contents - being untouched by callers. So, we allocate a chunk of memory - large enough to hold the structure and all of the stuff it points - to then we copy the source into this new block of memory. - The 'unionent' struct is a union of all of the currently used - *ent structure. */ - -#ifdef __x86_64__ -/* For some baffling reason, somebody at Microsoft decided that it would be - a good idea to exchange the s_port and s_proto members in the servent - structure. */ -struct win64_servent -{ - char *s_name; - char **s_aliases; - char *s_proto; - short s_port; -}; -#define WIN_SERVENT(x) ((win64_servent *)(x)) -#else -#define WIN_SERVENT(x) ((servent *)(x)) -#endif - -#ifdef DEBUGGING -static void * -#else -static inline void * -#endif -dup_ent (unionent *&dst, unionent *src, unionent::struct_type type) -{ - if (dst) - debug_printf ("old %sent structure \"%s\" %p\n", entnames[type], - dst->name, dst); - - if (!src) - { - set_winsock_errno (); - return NULL; - } - - debug_printf ("duping %sent \"%s\", %p", entnames[type], src->name, src); - - /* Find the size of the raw structure minus any character strings, etc. */ - int sz, struct_sz; - switch (type) - { - case unionent::t_protoent: - struct_sz = sizeof (protoent); - break; - case unionent::t_servent: - struct_sz = sizeof (servent); - break; - case unionent::t_hostent: - struct_sz = sizeof (hostent); - break; - default: - api_fatal ("called with invalid value %d", type); - break; - } - - /* Every *ent begins with a name. Calculate its length. */ - int namelen = strlen_round (src->name); - sz = struct_sz + namelen; - - char **av; - /* The next field in every *ent is an argv list of "something". - Calculate the number of components and how much space the - character strings will take. */ - int list_len = 0; - for (av = src->list; av && *av; av++) - { - list_len++; - sz += sizeof (char **) + strlen_round (*av); - } - - /* NULL terminate if there actually was a list */ - if (av) - { - sz += sizeof (char **); - list_len++; - } - - /* Do servent/hostent specific processing */ - int protolen = 0; - int addr_list_len = 0; - if (type == unionent::t_servent) - { - if (WIN_SERVENT (src)->s_proto) - sz += (protolen = strlen_round (WIN_SERVENT (src)->s_proto)); - } - else if (type == unionent::t_hostent) - { - /* Calculate the length and storage used for h_addr_list */ - for (av = src->h_addr_list; av && *av; av++) - { - addr_list_len++; - sz += sizeof (char **) + DWORD_round (src->h_len); - } - if (av) - { - sz += sizeof (char **); - addr_list_len++; - } - } - - /* Allocate the storage needed. */ - if (realloc_ent (dst, sz)) - { - memset (dst, 0, sz); - /* This field is common to all *ent structures but named differently - in each, of course. Also, take 64 bit Windows servent weirdness - into account. */ - if (type == unionent::t_servent) - dst->port_proto_addrtype = WIN_SERVENT (src)->s_port; - else - dst->port_proto_addrtype = src->port_proto_addrtype; - - char *dp = ((char *) dst) + struct_sz; - if (namelen) - { - /* Copy the name field to dst, using space just beyond the end of - the dst structure. */ - strcpy (dst->name = dp, src->name); - dp += namelen; - } - - /* Copy the 'list' type to dst, using space beyond end of structure - + storage for name. */ - if (src->list) - { - char **dav = dst->list = (char **) dp; - dp += sizeof (char **) * list_len; - for (av = src->list; av && *av; av++) - { - int len = strlen (*av) + 1; - memcpy (*dav++ = dp, *av, len); - dp += DWORD_round (len); - } - } - - /* Do servent/protoent/hostent specific processing. */ - if (type == unionent::t_protoent) - debug_printf ("protoent %s %p %y", dst->name, dst->list, dst->port_proto_addrtype); - else if (type == unionent::t_servent) - { - if (WIN_SERVENT (src)->s_proto) - { - strcpy (dst->s_proto = dp, WIN_SERVENT (src)->s_proto); - dp += protolen; - } - } - else if (type == unionent::t_hostent) - { - /* Transfer h_len and duplicate contents of h_addr_list, using - memory after 'list' allocation. */ - dst->h_len = src->h_len; - char **dav = dst->h_addr_list = (char **) dp; - dp += sizeof (char **) * addr_list_len; - for (av = src->h_addr_list; av && *av; av++) - { - memcpy (*dav++ = dp, *av, src->h_len); - dp += DWORD_round (src->h_len); - } - } - /* Sanity check that we did our bookkeeping correctly. */ - assert ((dp - (char *) dst) == sz); - } - debug_printf ("duped %sent \"%s\", %p", entnames[type], dst ? dst->name : "<null!>", dst); - return dst; -} - -static inline hostent * -dup_ent (hostent *src) -{ - return (hostent *) dup_ent (_my_tls.locals.hostent_buf, (unionent *) src, unionent::t_hostent); -} - -static inline protoent * -dup_ent (protoent *src) -{ - return (protoent *) dup_ent (_my_tls.locals.protoent_buf, (unionent *) src, unionent::t_protoent); -} - -static inline servent * -dup_ent (servent *src) -{ - return (servent *) dup_ent (_my_tls.locals.servent_buf, (unionent *) src, unionent::t_servent); -} - -/* exported as getprotobyname: standards? */ -extern "C" struct protoent * -cygwin_getprotobyname (const char *p) -{ - __try - { - return dup_ent (getprotobyname (p)); - } - __except (EFAULT) {} - __endtry - return NULL; -} - -/* exported as getprotobynumber: standards? */ -extern "C" struct protoent * -cygwin_getprotobynumber (int number) -{ - return dup_ent (getprotobynumber (number)); -} - -#ifndef SIO_BASE_HANDLE -#define SIO_BASE_HANDLE _WSAIOR(IOC_WS2,34) -#endif - -bool -fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc) -{ - int size; - - fd = build_fh_dev (*dev); - if (!fd.isopen ()) - return false; - - /* Usually sockets are inheritable IFS objects. Unfortunately some virus - scanners or other network-oriented software replace normal sockets - with their own kind, which is running through a filter driver called - "layered service provider" (LSP). - - LSP sockets are not kernel objects. They are typically not marked as - inheritable, nor are they IFS handles. They are in fact not inheritable - to child processes, and it does not help to mark them inheritable via - SetHandleInformation. Subsequent socket calls in the child process fail - with error 10038, WSAENOTSOCK. - - The only way up to Windows Server 2003 to make these sockets usable in - child processes is to duplicate them via WSADuplicateSocket/WSASocket - calls. This requires to start the child process in SUSPENDED state so - we only do this on affected systems. If we recognize a non-inheritable - socket we switch to inheritance/dup via WSADuplicateSocket/WSASocket for - that socket. - - Starting with Vista there's another neat way to workaround these annoying - LSP sockets. WSAIoctl allows to fetch the underlying base socket, which - is a normal, inheritable IFS handle. So we fetch the base socket, - duplicate it, and close the original socket. Now we have a standard IFS - socket which (hopefully) works as expected. */ - DWORD flags; - bool fixup = false; - if (!GetHandleInformation ((HANDLE) soc, &flags) - || !(flags & HANDLE_FLAG_INHERIT)) - { - int ret; - SOCKET base_soc; - DWORD bret; - - fixup = true; - debug_printf ("LSP handle: %p", soc); - ret = WSAIoctl (soc, SIO_BASE_HANDLE, NULL, 0, (void *) &base_soc, - sizeof (base_soc), &bret, NULL, NULL); - if (ret) - debug_printf ("WSAIoctl: %u", WSAGetLastError ()); - else if (base_soc != soc) - { - /* LSPs are often BLODAs as well. So we print an info about - detecting an LSP if BLODA detection is desired. */ - if (detect_bloda) - { - WSAPROTOCOL_INFO prot; - - memset (&prot, 0, sizeof prot); - ::getsockopt (soc, SOL_SOCKET, SO_PROTOCOL_INFO, (char *) &prot, - (size = sizeof prot, &size)); - small_printf ("\n\nPotential BLODA detected! Layered Socket " - "Service Provider:\n %s\n\n", prot.szProtocol); - } - if (GetHandleInformation ((HANDLE) base_soc, &flags) - && (flags & HANDLE_FLAG_INHERIT)) - { - if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) base_soc, - GetCurrentProcess (), (PHANDLE) &base_soc, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - debug_printf ("DuplicateHandle failed, %E"); - else - { - closesocket (soc); - soc = base_soc; - fixup = false; - } - } - } - } - fd->set_io_handle ((HANDLE) soc); - if (!((fhandler_socket *) fd)->init_events ()) - return false; - if (fixup) - ((fhandler_socket *) fd)->init_fixup_before (); - fd->set_flags (O_RDWR | O_BINARY); - debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name, soc); - - /* Raise default buffer sizes (instead of WinSock default 8K). - - 64K appear to have the best size/performance ratio for a default - value. Tested with ssh/scp on Vista over Gigabit LAN. - - NOTE. If the SO_RCVBUF size exceeds 65535(*), and if the socket is - connected to a remote machine, then calling WSADuplicateSocket on - fork/exec fails with WinSock error 10022, WSAEINVAL. Fortunately - we don't use WSADuplicateSocket anymore, rather we just utilize - handle inheritance. An explanation for this weird behaviour would - be nice, though. - - NOTE 2. Testing on x86_64 (XP, Vista, 2008 R2, W8) indicates that - this is no problem on 64 bit. So we set the default buffer size to - the default values in current 3.x Linux versions. - - NOTE 3. Setting the window size to 65535 results in extremely bad - performance for apps that send data in multiples of Kb, as they - eventually end up sending 1 byte on the network and naggle + delay - ack kicks in. For example, iperf on a 10Gb network gives only 10 - Mbits/sec with a 65535 send buffer. We want this to be a multiple - of 1k, but since 64k breaks WSADuplicateSocket we use 63Kb. - - (*) Maximum normal TCP window size. Coincidence? */ -#ifdef __x86_64__ - ((fhandler_socket *) fd)->rmem () = 212992; - ((fhandler_socket *) fd)->wmem () = 212992; -#else - ((fhandler_socket *) fd)->rmem () = 64512; - ((fhandler_socket *) fd)->wmem () = 64512; -#endif - if (::setsockopt (soc, SOL_SOCKET, SO_RCVBUF, - (char *) &((fhandler_socket *) fd)->rmem (), sizeof (int))) - { - debug_printf ("setsockopt(SO_RCVBUF) failed, %u", WSAGetLastError ()); - if (::getsockopt (soc, SOL_SOCKET, SO_RCVBUF, - (char *) &((fhandler_socket *) fd)->rmem (), - (size = sizeof (int), &size))) - system_printf ("getsockopt(SO_RCVBUF) failed, %u", WSAGetLastError ()); - } - if (::setsockopt (soc, SOL_SOCKET, SO_SNDBUF, - (char *) &((fhandler_socket *) fd)->wmem (), sizeof (int))) - { - debug_printf ("setsockopt(SO_SNDBUF) failed, %u", WSAGetLastError ()); - if (::getsockopt (soc, SOL_SOCKET, SO_SNDBUF, - (char *) &((fhandler_socket *) fd)->wmem (), - (size = sizeof (int), &size))) - system_printf ("getsockopt(SO_SNDBUF) failed, %u", WSAGetLastError ()); - } - - /* A unique ID is necessary to recognize fhandler entries which are - duplicated by dup(2) or fork(2). This is used in BSD flock calls - to identify the descriptor. */ - ((fhandler_socket *) fd)->set_unique_id (); - - return true; -} - -/* exported as socket: standards? */ -extern "C" int -cygwin_socket (int af, int type, int protocol) -{ - int res = -1; - SOCKET soc = 0; - - int flags = type & _SOCK_FLAG_MASK; - type &= ~_SOCK_FLAG_MASK; - - debug_printf ("socket (%d, %d (flags %y), %d)", af, type, flags, protocol); - - if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) - { - set_errno (EINVAL); - goto done; - } - - soc = socket (af == AF_LOCAL ? AF_INET : af, type, - af == AF_LOCAL ? 0 : protocol); - - if (soc == INVALID_SOCKET) - { - set_winsock_errno (); - goto done; - } - - const device *dev; - - if (af == AF_LOCAL) - dev = type == SOCK_STREAM ? stream_dev : dgram_dev; - else - dev = type == SOCK_STREAM ? tcp_dev : udp_dev; - - { - cygheap_fdnew fd; - if (fd < 0 || !fdsock (fd, dev, soc)) - closesocket (soc); - else - { - ((fhandler_socket *) fd)->set_addr_family (af); - ((fhandler_socket *) fd)->set_socket_type (type); - if (flags & SOCK_NONBLOCK) - ((fhandler_socket *) fd)->set_nonblocking (true); - if (flags & SOCK_CLOEXEC) - ((fhandler_socket *) fd)->set_close_on_exec (true); - if (type == SOCK_DGRAM) - { - /* Workaround the problem that a missing listener on a UDP socket - in a call to sendto will result in select/WSAEnumNetworkEvents - reporting that the socket has pending data and a subsequent call - to recvfrom will return -1 with error set to WSAECONNRESET. - - This problem is a regression introduced in Windows 2000. - Instead of fixing the problem, a new socket IOCTL code has - been added, see http://support.microsoft.com/kb/263823 */ - BOOL cr = FALSE; - DWORD blen; - if (WSAIoctl (soc, SIO_UDP_CONNRESET, &cr, sizeof cr, NULL, 0, - &blen, NULL, NULL) == SOCKET_ERROR) - debug_printf ("Reset SIO_UDP_CONNRESET: WinSock error %u", - WSAGetLastError ()); - } - res = fd; - } - } - -done: - syscall_printf ("%R = socket(%d, %d (flags %y), %d)", - res, af, type, flags, protocol); - return res; -} - -/* exported as sendto: standards? */ -extern "C" ssize_t -cygwin_sendto (int fd, const void *buf, size_t len, int flags, - const struct sockaddr *to, socklen_t tolen) -{ - ssize_t res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->sendto (buf, len, flags, to, tolen); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%lR = sendto(%d, %p, %ld, %y, %p, %d)", - res, fd, buf, len, flags, to, tolen); - return res; -} - -/* exported as recvfrom: standards? */ -extern "C" ssize_t -cygwin_recvfrom (int fd, void *buf, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) -{ - ssize_t res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - /* Originally we shortcircuited here if res == 0. - Allow 0 bytes buffer. This is valid in POSIX and handled in - fhandler_socket::recv_internal. If we shortcircuit, we fail - to deliver valid error conditions and peer address. */ - res = fh->recvfrom (buf, len, flags, from, fromlen); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%lR = recvfrom(%d, %p, %ld, %y, %p, %p)", - res, fd, buf, len, flags, from, fromlen); - return res; -} - -static int -convert_ws1_ip_optname (int optname) -{ - static int ws2_optname[] = - { - 0, - IP_OPTIONS, - IP_MULTICAST_IF, - IP_MULTICAST_TTL, - IP_MULTICAST_LOOP, - IP_ADD_MEMBERSHIP, - IP_DROP_MEMBERSHIP, - IP_TTL, - IP_TOS, - IP_DONTFRAGMENT - }; - return (optname < 1 || optname > _WS1_IP_DONTFRAGMENT) - ? optname - : ws2_optname[optname]; -} - -/* exported as setsockopt: standards? */ -extern "C" int -cygwin_setsockopt (int fd, int level, int optname, const void *optval, - socklen_t optlen) -{ - int res = -1; - - __try - { - fhandler_socket *fh = get (fd); - if (!fh) - __leave; - - /* Switch off the AF_LOCAL handshake and thus SO_PEERCRED handling - for AF_LOCAL/SOCK_STREAM sockets. This allows to handle special - situations in which connect is called before a listening socket - accepts connections. - FIXME: In the long run we should find a more generic solution which - doesn't require a blocking handshake in accept/connect to exchange - SO_PEERCRED credentials. */ - if (level == SOL_SOCKET && optname == SO_PEERCRED) - { - if (optval || optlen) - set_errno (EINVAL); - else - res = fh->af_local_set_no_getpeereid (); - __leave; - } - - /* Old applications still use the old WinSock1 IPPROTO_IP values. */ - if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) - optname = convert_ws1_ip_optname (optname); - - /* Per POSIX we must not be able to reuse a complete duplicate of a - local TCP address (same IP, same port), even if SO_REUSEADDR has been - set. That's unfortunately possible in WinSock, and this has never - been changed to maintain backward compatibility. Instead, the - SO_EXCLUSIVEADDRUSE option has been added to allow an application to - request POSIX standard behaviour in the non-SO_REUSEADDR case. - - However, the WinSock standard behaviour of stream socket binding - is equivalent to the POSIX behaviour as if SO_REUSEADDR has been set. - So what we do here is to note that SO_REUSEADDR has been set, but not - actually hand over the request to WinSock. This is tested in - fhandler_socket::bind(), so that SO_EXCLUSIVEADDRUSE can be set if - the application did not set SO_REUSEADDR. This should reflect the - POSIX socket binding behaviour as close as possible with WinSock. */ - if (level == SOL_SOCKET && optname == SO_REUSEADDR - && fh->get_socket_type () == SOCK_STREAM) - res = 0; - else - res = setsockopt (fh->get_socket (), level, optname, - (const char *) optval, optlen); - - if (optlen == sizeof (int)) - syscall_printf ("setsockopt optval=%x", *(int *) optval); - - if (res) - { - /* KB 248611: - - Windows 2000 and above don't support setting the IP_TOS field - with setsockopt. Additionally, TOS was always (also under 9x - and NT) only implemented for UDP and ICMP, never for TCP. - - The difference is that beginning with Windows 2000 the - setsockopt call returns WinSock error 10022, WSAEINVAL when - trying to set the IP_TOS field, instead of just ignoring the - call. This is *not* explained in KB 248611, but only in KB - 258978. - - Either case, the official workaround is to add a new registry - DWORD value HKLM/System/CurrentControlSet/Services/Tcpip/... - ... Parameters/DisableUserTOSSetting, set to 0, and reboot. - - Sidenote: The reasoning for dropping ToS in Win2K is that ToS - per RFC 1349 is incompatible with DiffServ per RFC 2474/2475. - - We just ignore the return value of setting IP_TOS entirely. - - CV 2014-04-16: Same for IPV6_TCLASS - FIXME: Same for IPV6_RECVTCLASS? */ - if (level == IPPROTO_IP && optname == IP_TOS - && WSAGetLastError () == WSAEINVAL) - { - debug_printf ("Faked IP_TOS success"); - res = 0; - } - else if (level == IPPROTO_IPV6 && optname == IPV6_TCLASS - && WSAGetLastError () == WSAENOPROTOOPT) - { - debug_printf ("Faked IPV6_TCLASS success"); - res = 0; - } - else - set_winsock_errno (); - } - else if (level == SOL_SOCKET) - switch (optname) - { - case SO_REUSEADDR: - fh->saw_reuseaddr (*(int *) optval); - break; - case SO_RCVBUF: - fh->rmem (*(int *) optval); - break; - case SO_SNDBUF: - fh->wmem (*(int *) optval); - break; - default: - break; - } - } - __except (EFAULT) - { - res = -1; - } - __endtry - syscall_printf ("%R = setsockopt(%d, %d, %y, %p, %d)", - res, fd, level, optname, optval, optlen); - return res; -} - -/* exported as getsockopt: standards? */ -extern "C" int -cygwin_getsockopt (int fd, int level, int optname, void *optval, - socklen_t *optlen) -{ - int res = -1; - - __try - { - fhandler_socket *fh = get (fd); - if (!fh) - __leave; - if (optname == SO_PEERCRED && level == SOL_SOCKET) - { - struct ucred *cred = (struct ucred *) optval; - res = fh->getpeereid (&cred->pid, &cred->uid, &cred->gid); - __leave; - } - /* Old applications still use the old WinSock1 IPPROTO_IP values. */ - if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) - optname = convert_ws1_ip_optname (optname); - res = getsockopt (fh->get_socket (), level, optname, (char *) optval, - (int *) optlen); - if (res == SOCKET_ERROR) - set_winsock_errno (); - else if (level == SOL_SOCKET && optname == SO_ERROR) - { - int *e = (int *) optval; - debug_printf ("WinSock SO_ERROR = %d", *e); - *e = find_winsock_errno (*e); - } - else if (*optlen == 1) - { - /* Regression in Vista and later: instead of a 4 byte BOOL value, - a 1 byte BOOLEAN value is returned, in contrast to older systems - and the documentation. Since an int type is expected by the - calling application, we convert the result here. For some reason - only three BSD-compatible socket options seem to be affected. */ - if ((level == SOL_SOCKET - && (optname == SO_KEEPALIVE || optname == SO_DONTROUTE)) - || (level == IPPROTO_TCP && optname == TCP_NODELAY)) - { - BOOLEAN *in = (BOOLEAN *) optval; - int *out = (int *) optval; - *out = *in; - *optlen = 4; - } - } - } - __except (EFAULT) - { - res = -1; - } - __endtry - syscall_printf ("%R = getsockopt(%d, %d, %y, %p, %p)", - res, fd, level, optname, optval, optlen); - return res; -} - -extern "C" int -getpeereid (int fd, uid_t *euid, gid_t *egid) -{ - fhandler_socket *fh = get (fd); - if (fh) - return fh->getpeereid (NULL, euid, egid); - return -1; -} - -/* exported as connect: standards? */ -extern "C" int -cygwin_connect (int fd, const struct sockaddr *name, socklen_t namelen) -{ - int res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->connect (name, namelen); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = connect(%d, %p, %d)", res, fd, name, namelen); - return res; -} - -/* exported as getservbyname: standards? */ -extern "C" struct servent * -cygwin_getservbyname (const char *name, const char *proto) -{ - servent *res = NULL; - - __try - { - res = dup_ent (getservbyname (name, proto)); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%p = getservbyname (%s, %s)", res, name, proto); - return res; -} - -/* exported as getservbyport: standards? */ -extern "C" struct servent * -cygwin_getservbyport (int port, const char *proto) -{ - servent *res = NULL; - - __try - { - res = dup_ent (getservbyport (port, proto)); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%p = getservbyport (%d, %s)", res, port, proto); - return res; -} - -extern "C" int -cygwin_gethostname (char *name, size_t len) -{ - int res = -1; - - __try - { - if (gethostname (name, len)) - { - DWORD local_len = len; - - if (!GetComputerNameExA (ComputerNameDnsFullyQualified, name, - &local_len)) - { - set_winsock_errno (); - __leave; - } - } - debug_printf ("name %s", name); - res = 0; - } - __except (EFAULT) {} - __endtry - return res; -} - -/* exported as gethostbyname: standards? */ -extern "C" struct hostent * -cygwin_gethostbyname (const char *name) -{ - unsigned char tmp_addr[4]; - struct hostent tmp, *h; - char *tmp_aliases[1] = {0}; - char *tmp_addr_list[2] = {0,0}; - unsigned int a, b, c, d; - char dummy; - hostent *res = NULL; - - __try - { - if (sscanf (name, "%u.%u.%u.%u%c", &a, &b, &c, &d, &dummy) != 4 - || a >= 256 || b >= 256 || c >= 256 || d >= 256) - h = gethostbyname (name); - else - { - /* In case you don't have DNS, at least x.x.x.x still works */ - memset (&tmp, 0, sizeof (tmp)); - tmp_addr[0] = a; - tmp_addr[1] = b; - tmp_addr[2] = c; - tmp_addr[3] = d; - tmp_addr_list[0] = (char *) tmp_addr; - tmp.h_name = name; - tmp.h_aliases = tmp_aliases; - tmp.h_addrtype = 2; - tmp.h_length = 4; - tmp.h_addr_list = tmp_addr_list; - h = &tmp; - } - - res = dup_ent (h); - if (res) - debug_printf ("h_name %s", res->h_name); - else - { - debug_printf ("dup_ent returned NULL for name %s, h %p", name, h); - set_host_errno (); - } - } - __except (EFAULT) - { - res = NULL; - } - __endtry - return res; -} - -/* exported as gethostbyaddr: standards? */ -extern "C" struct hostent * -cygwin_gethostbyaddr (const char *addr, int len, int type) -{ - hostent *res = NULL; - - __try - { - res = dup_ent (gethostbyaddr (addr, len, type)); - if (res) - debug_printf ("h_name %s", res->h_name); - else - set_host_errno (); - } - __except (EFAULT) - { - res = NULL; - } - __endtry - return res; -} - -static void -memcpy4to6 (char *dst, const u_char *src) -{ - const unsigned int h[] = {0, 0, htonl (0xFFFF)}; - memcpy (dst, h, 12); - memcpy (dst + 12, src, NS_INADDRSZ); -} - -static hostent * -gethostby_helper (const char *name, const int af, const int type, - const int addrsize_in, const int addrsize_out) -{ - /* Get the data from the name server */ - const int maxcount = 3; - int old_errno, ancount = 0, anlen = 1024, msgsize = 0; - u_char *ptr, *msg = NULL; - int sz; - hostent *ret; - char *string_ptr; - - while ((anlen > msgsize) && (ancount++ < maxcount)) - { - msgsize = anlen; - ptr = (u_char *) realloc (msg, msgsize); - if (ptr == NULL ) - { - old_errno = errno; - free (msg); - set_errno (old_errno); - h_errno = NETDB_INTERNAL; - return NULL; - } - msg = ptr; - anlen = res_search (name, ns_c_in, type, msg, msgsize); - } - - if (ancount >= maxcount) - { - free (msg); - h_errno = NO_RECOVERY; - return NULL; - } - if (anlen < 0) /* errno and h_errno are set */ - { - old_errno = errno; - free (msg); - set_errno (old_errno); - return NULL; - } - u_char *eomsg = msg + anlen - 1; - - - /* We scan the answer records to determine the required memory size. - They can be corrupted and we don't fully trust that the message - follows the standard exactly. glibc applies some checks that - we emulate. - The answers are copied in the hostent structure in a second scan. - To simplify the second scan we store information as follows: - - "class" is replaced by the compressed name size - - the first 16 bits of the "ttl" store the expanded name size + 1 - - the last 16 bits of the "ttl" store the offset to the next valid record. - Note that "type" is rewritten in host byte order. */ - - class record { - public: - unsigned type: 16; // type - unsigned complen: 16; // class or compressed length - unsigned namelen1: 16; // expanded length (with final 0) - unsigned next_o: 16; // offset to next valid - unsigned size: 16; // data size - u_char data[]; // data - record * next () { return (record *) (((char *) this) + next_o); } - void set_next ( record * nxt) { next_o = ((char *) nxt) - ((char *) this); } - u_char * name () { return (u_char *) (((char *) this) - complen); } - }; - - record * anptr = NULL, * prevptr = NULL, * curptr; - int i, alias_count = 0, string_size = 0, address_count = 0; - int namelen1 = 0, address_len = 0, antype, anclass, ansize; - unsigned complen; - - /* Get the count of answers */ - ancount = ntohs (((HEADER *) msg)->ancount); - - /* Skip the question, it was verified by res_send */ - ptr = msg + sizeof (HEADER); - if ((complen = dn_skipname (ptr, eomsg)) < 0) - goto corrupted; - /* Point to the beginning of the answer section */ - ptr += complen + NS_QFIXEDSZ; - - /* Scan the answer records to determine the sizes */ - for (i = 0; i < ancount; i++, ptr = curptr->data + ansize) - { - if ((complen = dn_skipname (ptr, eomsg)) < 0) - goto corrupted; - - curptr = (record *) (ptr + complen); - antype = ntohs (curptr->type); - anclass = ntohs (curptr->complen); - ansize = ntohs (curptr->size); - /* Class must be internet */ - if (anclass != ns_c_in) - continue; - - curptr->complen = complen; - if ((namelen1 = dn_length1 (msg, eomsg, curptr-> name())) <= 0) - goto corrupted; - - if (antype == ns_t_cname) - { - alias_count++; - string_size += namelen1; - } - else if (antype == type) - { - ansize = ntohs (curptr->size); - if (ansize != addrsize_in) - continue; - if (address_count == 0) - { - address_len = namelen1; - string_size += namelen1; - } - else if (address_len != namelen1) - continue; - address_count++; - } - /* Update the records */ - curptr->type = antype; /* Host byte order */ - curptr->namelen1 = namelen1; - if (! anptr) - anptr = prevptr = curptr; - else - { - prevptr->set_next (curptr); - prevptr = curptr; - } - } - - /* If there is no address, quit */ - if (address_count == 0) - { - free (msg); - h_errno = NO_DATA; - return NULL; - } - - /* Determine the total size */ - sz = DWORD_round (sizeof(hostent)) - + sizeof (char *) * (alias_count + address_count + 2) - + string_size - + address_count * addrsize_out; - - ret = realloc_ent (sz, (hostent *) NULL); - if (! ret) - { - old_errno = errno; - free (msg); - set_errno (old_errno); - h_errno = NETDB_INTERNAL; - return NULL; - } - - ret->h_addrtype = af; - ret->h_length = addrsize_out; - ret->h_aliases = (char **) (((char *) ret) + DWORD_round (sizeof(hostent))); - ret->h_addr_list = ret->h_aliases + alias_count + 1; - string_ptr = (char *) (ret->h_addr_list + address_count + 1); - - /* Rescan the answers */ - alias_count = address_count = 0; - prevptr->set_next (prevptr + 1); - - for (curptr = anptr; curptr <= prevptr; curptr = curptr->next ()) - { - antype = curptr->type; - if (antype == ns_t_cname) - { - dn_expand (msg, eomsg, curptr->name (), string_ptr, curptr->namelen1); - ret->h_aliases[alias_count++] = string_ptr; - string_ptr += curptr->namelen1; - } - else - { - if (address_count == 0) - { - dn_expand (msg, eomsg, curptr->name (), string_ptr, curptr->namelen1); - ret->h_name = string_ptr; - string_ptr += curptr->namelen1; - } - ret->h_addr_list[address_count++] = string_ptr; - if (addrsize_in != addrsize_out) - memcpy4to6 (string_ptr, curptr->data); - else - memcpy (string_ptr, curptr->data, addrsize_in); - string_ptr += addrsize_out; - } - } - - free (msg); - - ret->h_aliases[alias_count] = NULL; - ret->h_addr_list[address_count] = NULL; - - return ret; - - corrupted: - free (msg); - /* Hopefully message corruption errors are temporary. - Should it be NO_RECOVERY ? */ - h_errno = TRY_AGAIN; - return NULL; -} - -/* gethostbyname2: standards? */ -extern "C" struct hostent * -gethostbyname2 (const char *name, int af) -{ - hostent *res = NULL; - - __try - { - if (!(_res.options & RES_INIT)) - res_init(); - bool v4to6 = _res.options & RES_USE_INET6; - - int type, addrsize_in, addrsize_out; - switch (af) - { - case AF_INET: - addrsize_in = NS_INADDRSZ; - addrsize_out = (v4to6) ? NS_IN6ADDRSZ : NS_INADDRSZ; - type = ns_t_a; - break; - case AF_INET6: - addrsize_in = addrsize_out = NS_IN6ADDRSZ; - type = ns_t_aaaa; - break; - default: - set_errno (EAFNOSUPPORT); - h_errno = NETDB_INTERNAL; - __leave; - } - - res = gethostby_helper (name, af, type, addrsize_in, addrsize_out); - } - __except (EFAULT) {} - __endtry - return res; -} - -/* exported as accept: standards? */ -extern "C" int -cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len) -{ - int res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->accept4 (peer, len, - fh->is_nonblocking () ? SOCK_NONBLOCK : 0); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = accept(%d, %p, %p)", res, fd, peer, len); - return res; -} - -extern "C" int -accept4 (int fd, struct sockaddr *peer, socklen_t *len, int flags) -{ - int res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (!fh) - __leave; - if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) - set_errno (EINVAL); - else - res = fh->accept4 (peer, len, flags); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = accept4(%d, %p, %p, %y)", res, fd, peer, len, flags); - return res; -} - -/* exported as bind: standards? */ -extern "C" int -cygwin_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen) -{ - int res = -1; - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->bind (my_addr, addrlen); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = bind(%d, %p, %d)", res, fd, my_addr, addrlen); - return res; -} - -/* exported as getsockname: standards? */ -extern "C" int -cygwin_getsockname (int fd, struct sockaddr *addr, socklen_t *namelen) -{ - int res = -1; - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->getsockname (addr, namelen); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R =getsockname (%d, %p, %p)", res, fd, addr, namelen); - return res; -} - -/* exported as listen: standards? */ -extern "C" int -cygwin_listen (int fd, int backlog) -{ - int res = -1; - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->listen (backlog); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = listen(%d, %d)", res, fd, backlog); - return res; -} - -/* exported as shutdown: standards? */ -extern "C" int -cygwin_shutdown (int fd, int how) -{ - int res = -1; - - fhandler_socket *fh = get (fd); - if (fh) - res = fh->shutdown (how); - syscall_printf ("%R = shutdown(%d, %d)", res, fd, how); - return res; -} - -/* exported as hstrerror: BSD 4.3 */ -extern "C" const char * -cygwin_hstrerror (int err) -{ - int i; - - for (i = 0; host_errmap[i].e != 0; ++i) - if (err == host_errmap[i].e) - break; - - return host_errmap[i].s; -} - -/* exported as herror: BSD 4.3 */ -extern "C" void -cygwin_herror (const char *s) -{ - __try - { - if (cygheap->fdtab.not_open (2)) - return; - - if (s) - { - write (2, s, strlen (s)); - write (2, ": ", 2); - } - - const char *h_errstr = cygwin_hstrerror (h_errno); - - if (!h_errstr) - switch (h_errno) - { - case NETDB_INTERNAL: - h_errstr = "Resolver internal error"; - break; - case NETDB_SUCCESS: - h_errstr = "Resolver error 0 (no error)"; - break; - default: - h_errstr = "Unknown resolver error"; - break; - } - write (2, h_errstr, strlen (h_errstr)); - write (2, "\n", 1); - } - __except (NO_ERROR) {} - __endtry -} - -/* exported as getpeername: standards? */ -extern "C" int -cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len) -{ - int res = -1; - fhandler_socket *fh = NULL; - - __try - { - fh = get (fd); - if (fh) - res = fh->getpeername (name, len); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = getpeername(%d) %p", res, fd, - (fh ? fh->get_socket () : (SOCKET) -1)); - return res; -} - -/* exported as recv: standards? */ -extern "C" ssize_t -cygwin_recv (int fd, void *buf, size_t len, int flags) -{ - ssize_t res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - /* Originally we shortcircuited here if res == 0. - Allow 0 bytes buffer. This is valid in POSIX and handled in - fhandler_socket::recv_internal. If we shortcircuit, we fail - to deliver valid error conditions. */ - res = fh->recvfrom (buf, len, flags, NULL, NULL); - } - __except (EFAULT) {} - __endtry - syscall_printf ("%lR = recv(%d, %p, %ld, %y)", res, fd, buf, len, flags); - return res; -} - -/* exported as send: standards? */ -extern "C" ssize_t -cygwin_send (int fd, const void *buf, size_t len, int flags) -{ - ssize_t res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - res = fh->sendto (buf, len, flags, NULL, 0); - } - __except (EFAULT) - __endtry - syscall_printf ("%lR = send(%d, %p, %ld, %y)", res, fd, buf, len, flags); - return res; -} - -/* getdomainname: standards? */ -extern "C" int -getdomainname (char *domain, size_t len) -{ - __try - { - PFIXED_INFO info = NULL; - ULONG size = 0; - - if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW - && (info = (PFIXED_INFO) alloca(size)) - && GetNetworkParams(info, &size) == ERROR_SUCCESS) - { - strncpy(domain, info->DomainName, len); - return 0; - } - __seterrno (); - } - __except (EFAULT) - __endtry - return -1; -} - -/* Fill out an ifconf struct. */ - -#ifndef IN_LOOPBACK -#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) -#endif - -static int in6_are_prefix_equal (struct in6_addr *, struct in6_addr *, int); - -static int in_are_prefix_equal (struct in_addr *p1, struct in_addr *p2, int len) -{ - if (0 > len || len > 32) - return 0; - uint32_t pfxmask = 0xffffffff << (32 - len); - return (ntohl (p1->s_addr) & pfxmask) == (ntohl (p2->s_addr) & pfxmask); -} - -extern "C" int -ip_addr_prefix (PIP_ADAPTER_UNICAST_ADDRESS pua, PIP_ADAPTER_PREFIX pap) -{ - if (wincap.has_gaa_on_link_prefix ()) - return (int) ((PIP_ADAPTER_UNICAST_ADDRESS_LH) pua)->OnLinkPrefixLength; - switch (pua->Address.lpSockaddr->sa_family) - { - case AF_INET: - /* Prior to Vista, the loopback prefix is not available. */ - if (IN_LOOPBACK (ntohl (((struct sockaddr_in *) - pua->Address.lpSockaddr)->sin_addr.s_addr))) - return 8; - for ( ; pap; pap = pap->Next) - if (in_are_prefix_equal ( - &((struct sockaddr_in *) pua->Address.lpSockaddr)->sin_addr, - &((struct sockaddr_in *) pap->Address.lpSockaddr)->sin_addr, - pap->PrefixLength)) - return pap->PrefixLength; - break; - case AF_INET6: - /* Prior to Vista, the loopback prefix is not available. */ - if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) - pua->Address.lpSockaddr)->sin6_addr)) - return 128; - for ( ; pap; pap = pap->Next) - if (in6_are_prefix_equal ( - &((struct sockaddr_in6 *) pua->Address.lpSockaddr)->sin6_addr, - &((struct sockaddr_in6 *) pap->Address.lpSockaddr)->sin6_addr, - pap->PrefixLength)) - return pap->PrefixLength; - break; - default: - break; - } - return 0; -} - -#ifndef GAA_FLAG_INCLUDE_ALL_INTERFACES -#define GAA_FLAG_INCLUDE_ALL_INTERFACES 0x0100 -#endif - -struct gaa_wa { - ULONG family; - PIP_ADAPTER_ADDRESSES *pa_ret; -}; - -DWORD WINAPI -call_gaa (LPVOID param) -{ - DWORD ret, size = 0; - gaa_wa *p = (gaa_wa *) param; - PIP_ADAPTER_ADDRESSES pa0 = NULL; - - if (!p->pa_ret) - return GetAdaptersAddresses (p->family, GAA_FLAG_INCLUDE_PREFIX - | GAA_FLAG_INCLUDE_ALL_INTERFACES, - NULL, NULL, &size); - do - { - ret = GetAdaptersAddresses (p->family, GAA_FLAG_INCLUDE_PREFIX - | GAA_FLAG_INCLUDE_ALL_INTERFACES, - NULL, pa0, &size); - if (ret == ERROR_BUFFER_OVERFLOW - && !(pa0 = (PIP_ADAPTER_ADDRESSES) realloc (pa0, size))) - break; - } - while (ret == ERROR_BUFFER_OVERFLOW); - if (pa0) - { - if (ret != ERROR_SUCCESS) - { - free (pa0); - *p->pa_ret = NULL; - } - else - *p->pa_ret = pa0; - } - return ret; -} - -bool -get_adapters_addresses (PIP_ADAPTER_ADDRESSES *pa_ret, ULONG family) -{ - DWORD ret; - gaa_wa param = { family, pa_ret }; - - if ((uintptr_t) ¶m >= (uintptr_t) 0x80000000L - && wincap.has_gaa_largeaddress_bug ()) - { - /* In Windows Vista and Windows 7 under WOW64, GetAdaptersAddresses fails - if it's running in a thread with a stack located in the large address - area. So, if we're running in a pthread with such a stack, we call - GetAdaptersAddresses in a child thread with an OS-allocated stack. - The OS allocates stacks bottom up, so chances are good that the new - stack will be located in the lower address area. */ - HANDLE thr = CreateThread (NULL, 0, call_gaa, ¶m, 0, NULL); - if (!thr) - { - debug_printf ("CreateThread: %E"); - return false; - } - WaitForSingleObject (thr, INFINITE); - GetExitCodeThread (thr, &ret); - CloseHandle (thr); - } - else - ret = call_gaa (¶m); - return ret == ERROR_SUCCESS || (!pa_ret && ret == ERROR_BUFFER_OVERFLOW); -} - -#define WS_IFF_UP 1 -#define WS_IFF_BROADCAST 2 -#define WS_IFF_LOOPBACK 4 -#define WS_IFF_POINTTOPOINT 8 -#define WS_IFF_MULTICAST 16 - -static inline short -convert_ifr_flags (u_long ws_flags) -{ - return (ws_flags & (WS_IFF_UP | WS_IFF_BROADCAST)) - | ((ws_flags & (WS_IFF_LOOPBACK | WS_IFF_POINTTOPOINT)) << 1) - | ((ws_flags & WS_IFF_MULTICAST) << 8); -} - -static u_long -get_routedst (DWORD if_index) -{ - PMIB_IPFORWARDTABLE pift; - ULONG size = 0; - if (GetIpForwardTable (NULL, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER - && (pift = (PMIB_IPFORWARDTABLE) alloca (size)) - && GetIpForwardTable (pift, &size, FALSE) == NO_ERROR) - for (DWORD i = 0; i < pift->dwNumEntries; ++i) - { - if (pift->table[i].dwForwardIfIndex == if_index - && pift->table[i].dwForwardMask == INADDR_BROADCAST) - return pift->table[i].dwForwardDest; - } - return INADDR_ANY; -} - -struct ifall { - struct ifaddrs ifa_ifa; - char ifa_name[IFNAMSIZ]; - struct sockaddr_storage ifa_addr; - struct sockaddr_storage ifa_brddstaddr; - struct sockaddr_storage ifa_netmask; - struct sockaddr ifa_hwaddr; - int ifa_metric; - int ifa_mtu; - int ifa_ifindex; - struct ifreq_frndlyname ifa_frndlyname; -}; - -static unsigned int -get_flags (PIP_ADAPTER_ADDRESSES pap) -{ - unsigned int flags = IFF_UP; - if (pap->IfType == IF_TYPE_SOFTWARE_LOOPBACK) - flags |= IFF_LOOPBACK; - else if (pap->IfType == IF_TYPE_PPP - || pap->IfType == IF_TYPE_SLIP) - flags |= IFF_POINTOPOINT | IFF_NOARP; - if (!(pap->Flags & IP_ADAPTER_NO_MULTICAST)) - flags |= IFF_MULTICAST; - if (pap->OperStatus == IfOperStatusUp - || pap->OperStatus == IfOperStatusUnknown) - flags |= IFF_RUNNING; - if (pap->OperStatus != IfOperStatusLowerLayerDown) - flags |= IFF_LOWER_UP; - if (pap->OperStatus == IfOperStatusDormant) - flags |= IFF_DORMANT; - return flags; -} - -static ULONG -get_ipv4fromreg_ipcnt (const char *name) -{ - WCHAR regkey[256], *c; - - c = wcpcpy (regkey, L"Tcpip\\Parameters\\Interfaces\\"); - sys_mbstowcs (c, 220, name); - if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_SERVICES, regkey))) - return 0; - - ULONG ifs = 1; - DWORD dhcp = 0; - UNICODE_STRING uipa = { 0, 0, NULL }; - RTL_QUERY_REGISTRY_TABLE tab[3] = { - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING, - L"EnableDHCP", &dhcp, REG_NONE, NULL, 0 }, - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, - L"IPAddress", &uipa, REG_NONE, NULL, 0 }, - { NULL, 0, NULL, NULL, 0, NULL, 0 } - }; - - /* If DHCP is used, we have only one address. */ - if (NT_SUCCESS (RtlQueryRegistryValues (RTL_REGISTRY_SERVICES, regkey, tab, - NULL, NULL)) - && uipa.Buffer) - { - if (dhcp == 0) - for (ifs = 0, c = uipa.Buffer; *c; c += wcslen (c) + 1) - ifs++; - RtlFreeUnicodeString (&uipa); - } - return ifs; -} - -static void -get_ipv4fromreg (struct ifall *ifp, const char *name, DWORD idx) -{ - WCHAR regkey[256], *c; - - c = wcpcpy (regkey, L"Tcpip\\Parameters\\Interfaces\\"); - sys_mbstowcs (c, 220, name); - if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_SERVICES, regkey))) - return; - - ULONG ifs; - DWORD dhcp = 0; - UNICODE_STRING udipa = { 0, 0, NULL }; - UNICODE_STRING udsub = { 0, 0, NULL }; - UNICODE_STRING uipa = { 0, 0, NULL }; - UNICODE_STRING usub = { 0, 0, NULL }; - RTL_QUERY_REGISTRY_TABLE tab[6] = { - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING, - L"EnableDHCP", &dhcp, REG_NONE, NULL, 0 }, - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, - L"DhcpIPAddress", &udipa, REG_NONE, NULL, 0 }, - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, - L"DhcpSubnetMask", &udsub, REG_NONE, NULL, 0 }, - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, - L"IPAddress", &uipa, REG_NONE, NULL, 0 }, - { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND, - L"SubnetMask", &usub, REG_NONE, NULL, 0 }, - { NULL, 0, NULL, NULL, 0, NULL, 0 } - }; - - if (NT_SUCCESS (RtlQueryRegistryValues (RTL_REGISTRY_SERVICES, regkey, tab, - NULL, NULL))) - { -# define addr ((struct sockaddr_in *) &ifp->ifa_addr) -# define mask ((struct sockaddr_in *) &ifp->ifa_netmask) -# define brdc ((struct sockaddr_in *) &ifp->ifa_brddstaddr) -# define inet_uton(u, a) \ - { \ - char t[64]; \ - sys_wcstombs (t, 64, (u)); \ - cygwin_inet_aton (t, (a)); \ - } - /* If DHCP is used, we have only one address. */ - if (dhcp) - { - if (udipa.Buffer) - inet_uton (udipa.Buffer, &addr->sin_addr); - if (udsub.Buffer) - inet_uton (udsub.Buffer, &mask->sin_addr); - } - else - { - if (uipa.Buffer) - { - for (ifs = 0, c = uipa.Buffer; *c && ifs < idx; - c += wcslen (c) + 1) - ifs++; - if (*c) - inet_uton (c, &addr->sin_addr); - } - if (usub.Buffer) - { - for (ifs = 0, c = usub.Buffer; *c && ifs < idx; - c += wcslen (c) + 1) - ifs++; - if (*c) - inet_uton (c, &mask->sin_addr); - } - } - if (ifp->ifa_ifa.ifa_flags & IFF_BROADCAST) - brdc->sin_addr.s_addr = (addr->sin_addr.s_addr - & mask->sin_addr.s_addr) - | ~mask->sin_addr.s_addr; -#undef addr -#undef mask -#undef brdc -#undef inet_uton - if (udipa.Buffer) - RtlFreeUnicodeString (&udipa); - if (udsub.Buffer) - RtlFreeUnicodeString (&udsub); - if (uipa.Buffer) - RtlFreeUnicodeString (&uipa); - if (usub.Buffer) - RtlFreeUnicodeString (&usub); - } -} - -static void -get_friendlyname (struct ifall *ifp, PIP_ADAPTER_ADDRESSES pap) -{ - struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *) - &ifp->ifa_frndlyname; - iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname, - IFRF_FRIENDLYNAMESIZ, - pap->FriendlyName); -} - -static void -get_hwaddr (struct ifall *ifp, PIP_ADAPTER_ADDRESSES pap) -{ - for (UINT i = 0; i < IFHWADDRLEN; ++i) - if (i >= pap->PhysicalAddressLength) - ifp->ifa_hwaddr.sa_data[i] = '\0'; - else - ifp->ifa_hwaddr.sa_data[i] = pap->PhysicalAddress[i]; -} - -/* - * Generate short, unique interface name for usage with aged - * applications still using the old pre-1.7 ifreq structure. - */ -static void -gen_old_if_name (char *name, PIP_ADAPTER_ADDRESSES pap, DWORD idx) -{ - /* Note: The returned name must be < 16 chars. */ - const char *prefix; - - switch (pap->IfType) - { - case IF_TYPE_ISO88025_TOKENRING: - prefix = "tok"; - break; - case IF_TYPE_PPP: - prefix = "ppp"; - break; - case IF_TYPE_SOFTWARE_LOOPBACK: - prefix = "lo"; - break; - case IF_TYPE_ATM: - prefix = "atm"; - break; - case IF_TYPE_IEEE80211: - prefix = "wlan"; - break; - case IF_TYPE_SLIP: - case IF_TYPE_RS232: - case IF_TYPE_MODEM: - prefix = "slp"; - break; - case IF_TYPE_TUNNEL: - prefix = "tun"; - break; - default: - prefix = "eth"; - break; - } - if (idx) - __small_sprintf (name, "%s%u:%u", prefix, pap->IfIndex, idx); - else - __small_sprintf (name, "%s%u", prefix, pap->IfIndex, idx); -} - -/* - * Get network interfaces. Use IP Helper function GetAdaptersAddresses. - */ -static struct ifall * -get_ifs (ULONG family) -{ - PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; - PIP_ADAPTER_UNICAST_ADDRESS pua; - int cnt = 0; - struct ifall *ifret = NULL, *ifp; - struct sockaddr_in *if_sin; - struct sockaddr_in6 *if_sin6; - - if (!get_adapters_addresses (&pa0, family)) - goto done; - - for (pap = pa0; pap; pap = pap->Next) - if (!pap->FirstUnicastAddress) - { - /* FirstUnicastAddress is NULL for interfaces which are disconnected. - Fetch number of configured IPv4 addresses from registry and - store in an unused member of the adapter addresses structure. */ - pap->Ipv6IfIndex = get_ipv4fromreg_ipcnt (pap->AdapterName); - cnt += pap->Ipv6IfIndex; - } - else for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next) - ++cnt; - - if (!(ifret = (struct ifall *) calloc (cnt, sizeof (struct ifall)))) - goto done; - ifp = ifret; - - for (pap = pa0; pap; pap = pap->Next) - { - DWORD idx = 0; - if (!pap->FirstUnicastAddress) - for (idx = 0; idx < pap->Ipv6IfIndex; ++idx) - { - /* Next in chain */ - ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa; - /* Interface name */ - - if (CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ) - gen_old_if_name (ifp->ifa_name, pap, idx); - else if (idx) - __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx); - else - strcpy (ifp->ifa_name, pap->AdapterName); - ifp->ifa_ifa.ifa_name = ifp->ifa_name; - /* Flags */ - ifp->ifa_ifa.ifa_flags = get_flags (pap); - if (pap->IfType != IF_TYPE_PPP - && pap->IfType != IF_TYPE_SOFTWARE_LOOPBACK) - ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST; - /* Address */ - ifp->ifa_addr.ss_family = AF_INET; - ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr; - /* Broadcast/Destination address */ - ifp->ifa_brddstaddr.ss_family = AF_INET; - ifp->ifa_ifa.ifa_dstaddr = NULL; - /* Netmask */ - ifp->ifa_netmask.ss_family = AF_INET; - ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask; - /* Try to fetch real IPv4 address information from registry. */ - get_ipv4fromreg (ifp, pap->AdapterName, idx); - /* Hardware address */ - get_hwaddr (ifp, pap); - /* Metric */ - ifp->ifa_metric = 1; - /* MTU */ - ifp->ifa_mtu = pap->Mtu; - /* Interface index */ - ifp->ifa_ifindex = pap->IfIndex; - /* Friendly name */ - get_friendlyname (ifp, pap); - ++ifp; - } - else - for (idx = 0, pua = pap->FirstUnicastAddress; pua; pua = pua->Next) - { - struct sockaddr *sa = (struct sockaddr *) pua->Address.lpSockaddr; -# define sin ((struct sockaddr_in *) sa) -# define sin6 ((struct sockaddr_in6 *) sa) - size_t sa_size = (sa->sa_family == AF_INET6 - ? sizeof *sin6 : sizeof *sin); - /* Next in chain */ - ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa; - /* Interface name */ - if (CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ) - gen_old_if_name (ifp->ifa_name, pap, idx); - else if (sa->sa_family == AF_INET && idx) - __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx); - else - strcpy (ifp->ifa_name, pap->AdapterName); - if (sa->sa_family == AF_INET) - ++idx; - ifp->ifa_ifa.ifa_name = ifp->ifa_name; - /* Flags */ - ifp->ifa_ifa.ifa_flags = get_flags (pap); - if (sa->sa_family == AF_INET - && pap->IfType != IF_TYPE_SOFTWARE_LOOPBACK - && pap->IfType != IF_TYPE_PPP) - ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST; - /* Address */ - memcpy (&ifp->ifa_addr, sa, sa_size); - ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr; - /* Netmask */ - int prefix = ip_addr_prefix (pua, pap->FirstPrefix); - switch (sa->sa_family) - { - case AF_INET: - if_sin = (struct sockaddr_in *) &ifp->ifa_netmask; - if_sin->sin_addr.s_addr = htonl (UINT32_MAX << (32 - prefix)); - if_sin->sin_family = AF_INET; - break; - case AF_INET6: - if_sin6 = (struct sockaddr_in6 *) &ifp->ifa_netmask; - for (cnt = 0; cnt < 4 && prefix > 0; ++cnt, prefix -= 32) - { - if_sin6->sin6_addr.s6_addr32[cnt] = UINT32_MAX; - if (prefix < 32) - if_sin6->sin6_addr.s6_addr32[cnt] <<= 32 - prefix; - } - break; - } - ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask; - if (pap->IfType == IF_TYPE_PPP) - { - /* Destination address */ - if (sa->sa_family == AF_INET) - { - if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr; - if_sin->sin_addr.s_addr = get_routedst (pap->IfIndex); - if_sin->sin_family = AF_INET; - } - else - /* FIXME: No official way to get the dstaddr for ipv6? */ - memcpy (&ifp->ifa_addr, sa, sa_size); - ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *) - &ifp->ifa_brddstaddr; - } - else - { - /* Broadcast address */ - if (sa->sa_family == AF_INET) - { - if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr; - uint32_t mask = - ((struct sockaddr_in *) &ifp->ifa_netmask)->sin_addr.s_addr; - if_sin->sin_addr.s_addr = (sin->sin_addr.s_addr & mask) - | ~mask; - if_sin->sin_family = AF_INET; - ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *) - &ifp->ifa_brddstaddr; - } - else /* No IPv6 broadcast */ - ifp->ifa_ifa.ifa_broadaddr = NULL; - } - /* Hardware address */ - get_hwaddr (ifp, pap); - /* Metric */ - if (wincap.has_gaa_on_link_prefix ()) - ifp->ifa_metric = (sa->sa_family == AF_INET - ? ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv4Metric - : ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv6Metric); - else - ifp->ifa_metric = 1; - /* MTU */ - ifp->ifa_mtu = pap->Mtu; - /* Interface index */ - ifp->ifa_ifindex = pap->IfIndex; - /* Friendly name */ - get_friendlyname (ifp, pap); - ++ifp; -# undef sin -# undef sin6 - } - } - /* Since every entry is set to the next entry, the last entry points to an - invalid next entry now. Fix it retroactively. */ - if (ifp > ifret) - ifp[-1].ifa_ifa.ifa_next = NULL; - -done: - if (pa0) - free (pa0); - return ifret; -} - -extern "C" int -getifaddrs (struct ifaddrs **ifap) -{ - if (!ifap) - { - set_errno (EINVAL); - return -1; - } - struct ifall *ifp; - ifp = get_ifs (AF_UNSPEC); - *ifap = &ifp->ifa_ifa; - return ifp ? 0 : -1; -} - -extern "C" void -freeifaddrs (struct ifaddrs *ifp) -{ - if (ifp) - free (ifp); -} - -int -get_ifconf (struct ifconf *ifc, int what) -{ - __try - { - /* Ensure we have space for at least one struct ifreqs, fail if not. */ - if (ifc->ifc_len < (int) sizeof (struct ifreq)) - { - set_errno (EINVAL); - __leave; - } - - struct ifall *ifret, *ifp; - ifret = get_ifs (AF_INET); - if (!ifret) - __leave; - - struct sockaddr_in *sin; - struct ifreq *ifr = ifc->ifc_req; - int cnt = 0; - for (ifp = ifret; ifp; ifp = (struct ifall *) ifp->ifa_ifa.ifa_next) - { - ++cnt; - strcpy (ifr->ifr_name, ifp->ifa_name); - switch (what) - { - case SIOCGIFFLAGS: - ifr->ifr_flags = ifp->ifa_ifa.ifa_flags; - break; - case SIOCGIFCONF: - case SIOCGIFADDR: - sin = (struct sockaddr_in *) &ifr->ifr_addr; - memcpy (sin, &ifp->ifa_addr, sizeof *sin); - break; - case SIOCGIFNETMASK: - sin = (struct sockaddr_in *) &ifr->ifr_netmask; - memcpy (sin, &ifp->ifa_netmask, sizeof *sin); - break; - case SIOCGIFDSTADDR: - sin = (struct sockaddr_in *) &ifr->ifr_dstaddr; - if (ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT) - memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); - else /* Return addr as on Linux. */ - memcpy (sin, &ifp->ifa_addr, sizeof *sin); - break; - case SIOCGIFBRDADDR: - sin = (struct sockaddr_in *) &ifr->ifr_broadaddr; - if (!(ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT)) - memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); - else - { - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_family = AF_INET; - sin->sin_port = 0; - } - break; - case SIOCGIFHWADDR: - memcpy (&ifr->ifr_hwaddr, &ifp->ifa_hwaddr, - sizeof ifr->ifr_hwaddr); - break; - case SIOCGIFMETRIC: - ifr->ifr_metric = ifp->ifa_metric; - break; - case SIOCGIFMTU: - ifr->ifr_mtu = ifp->ifa_mtu; - break; - case SIOCGIFINDEX: - ifr->ifr_ifindex = ifp->ifa_ifindex; - break; - case SIOCGIFFRNDLYNAM: - memcpy (ifr->ifr_frndlyname, &ifp->ifa_frndlyname, - sizeof (struct ifreq_frndlyname)); - } - if ((caddr_t) ++ifr > - ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) - break; - } - /* Set the correct length */ - ifc->ifc_len = cnt * sizeof (struct ifreq); - free (ifret); - return 0; - } - __except (EFAULT) {} - __endtry - return -1; -} - -extern "C" unsigned -if_nametoindex (const char *name) -{ - PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; - unsigned index = 0; - - __try - { - if (get_adapters_addresses (&pa0, AF_UNSPEC)) - { - char lname[IF_NAMESIZE], *c; - - lname[0] = '\0'; - strncat (lname, name, IF_NAMESIZE - 1); - if (lname[0] == '{' && (c = strchr (lname, ':'))) - *c = '\0'; - for (pap = pa0; pap; pap = pap->Next) - if (strcasematch (lname, pap->AdapterName)) - { - index = pap->Ipv6IfIndex ?: pap->IfIndex; - break; - } - free (pa0); - } - } - __except (EFAULT) - { - index = 0; - } - __endtry - return index; -} - -extern "C" char * -if_indextoname (unsigned ifindex, char *ifname) -{ - PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; - char *name = NULL; - - __try - { - if (get_adapters_addresses (&pa0, AF_UNSPEC)) - { - for (pap = pa0; pap; pap = pap->Next) - if (ifindex == (pap->Ipv6IfIndex ?: pap->IfIndex)) - { - /* Unfortunately the pre-Vista IPv6 stack has a distinct - loopback device with the same Ipv6IfIndex as the IfIndex - of the IPv4 loopback device, but with a different adapter - name. For consistency with /proc/net/if_inet6, try to find - the IPv6 loopback device and use that adapter name instead. - We identify the loopback device by its IfIndex of 1. */ - if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) - for (PIP_ADAPTER_ADDRESSES pap2 = pa0; - pap2; - pap2 = pap2->Next) - if (pap2->Ipv6IfIndex == 1) - { - pap = pap2; - break; - } - name = strcpy (ifname, pap->AdapterName); - break; - } - free (pa0); - } - else - set_errno (ENXIO); - } - __except (EFAULT) {} - __endtry - return name; -} - -extern "C" struct if_nameindex * -if_nameindex (void) -{ - PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; - struct if_nameindex *iflist = NULL; - char (*ifnamelist)[IF_NAMESIZE]; - - __try - { - if (get_adapters_addresses (&pa0, AF_UNSPEC)) - { - int cnt = 0; - for (pap = pa0; pap; pap = pap->Next) - ++cnt; - iflist = (struct if_nameindex *) - malloc ((cnt + 1) * sizeof (struct if_nameindex) - + cnt * IF_NAMESIZE); - if (!iflist) - set_errno (ENOBUFS); - else - { - ifnamelist = (char (*)[IF_NAMESIZE]) (iflist + cnt + 1); - for (pap = pa0, cnt = 0; pap; pap = pap->Next) - { - for (int i = 0; i < cnt; ++i) - if (iflist[i].if_index - == (pap->Ipv6IfIndex ?: pap->IfIndex)) - goto outer_loop; - iflist[cnt].if_index = pap->Ipv6IfIndex ?: pap->IfIndex; - strcpy (iflist[cnt].if_name = ifnamelist[cnt], - pap->AdapterName); - /* See comment in if_indextoname. */ - if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) - for (PIP_ADAPTER_ADDRESSES pap2 = pa0; - pap2; - pap2 = pap2->Next) - if (pap2->Ipv6IfIndex == 1) - { - strcpy (ifnamelist[cnt], pap2->AdapterName); - break; - } - ++cnt; - outer_loop: - ; - } - iflist[cnt].if_index = 0; - iflist[cnt].if_name = NULL; - } - free (pa0); - } - else - set_errno (ENXIO); - } - __except (EFAULT) {} - __endtry - return iflist; -} - -extern "C" void -if_freenameindex (struct if_nameindex *ptr) -{ - free (ptr); -} - -#define PORT_LOW (IPPORT_EFSSERVER + 1) -#define PORT_HIGH (IPPORT_RESERVED - 1) -#define NUM_PORTS (PORT_HIGH - PORT_LOW + 1) - -extern "C" int -cygwin_bindresvport_sa (int fd, struct sockaddr *sa) -{ - struct sockaddr_storage sst; - struct sockaddr_in *sin = NULL; - struct sockaddr_in6 *sin6 = NULL; - in_port_t port; - socklen_t salen; - int ret = -1; - - __try - { - fhandler_socket *fh = get (fd); - if (!fh) - __leave; - - if (!sa) - { - sa = (struct sockaddr *) &sst; - memset (&sst, 0, sizeof sst); - sa->sa_family = fh->get_addr_family (); - } - - switch (sa->sa_family) - { - case AF_INET: - salen = sizeof (struct sockaddr_in); - sin = (struct sockaddr_in *) sa; - port = sin->sin_port; - break; - case AF_INET6: - salen = sizeof (struct sockaddr_in6); - sin6 = (struct sockaddr_in6 *) sa; - port = sin6->sin6_port; - break; - default: - set_errno (EPFNOSUPPORT); - __leave; - } - - /* If a non-zero port number is given, try this first. If that succeeds, - or if the error message is serious, return. */ - if (port) - { - ret = fh->bind (sa, salen); - if (!ret || (get_errno () != EADDRINUSE && get_errno () != EINVAL)) - __leave; - } - - LONG myport; - - for (int i = 0; i < NUM_PORTS; i++) - { - while ((myport = InterlockedExchange ( - &cygwin_shared->last_used_bindresvport, -1)) == -1) - yield (); - if (myport == 0 || --myport < PORT_LOW) - myport = PORT_HIGH; - InterlockedExchange (&cygwin_shared->last_used_bindresvport, myport); - - if (sa->sa_family == AF_INET6) - sin6->sin6_port = htons (myport); - else - sin->sin_port = htons (myport); - if (!(ret = fh->bind (sa, salen))) - break; - if (get_errno () != EADDRINUSE && get_errno () != EINVAL) - break; - } - - } - __except (EFAULT) {} - __endtry - return ret; -} - - -extern "C" int -cygwin_bindresvport (int fd, struct sockaddr_in *sin) -{ - return cygwin_bindresvport_sa (fd, (struct sockaddr *) sin); -} - -/* socketpair: standards? */ -/* Win32 supports AF_INET only, so ignore domain and protocol arguments */ -extern "C" int -socketpair (int family, int type, int protocol, int *sb) -{ - int res = -1; - SOCKET insock = INVALID_SOCKET; - SOCKET outsock = INVALID_SOCKET; - SOCKET newsock = INVALID_SOCKET; - struct sockaddr_in sock_in, sock_out; - int len; - - __try - { - int flags = type & _SOCK_FLAG_MASK; - type &= ~_SOCK_FLAG_MASK; - - if (family != AF_LOCAL && family != AF_INET) - { - set_errno (EAFNOSUPPORT); - __leave; - } - if (type != SOCK_STREAM && type != SOCK_DGRAM) - { - set_errno (EPROTOTYPE); - __leave; - } - if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) - { - set_errno (EINVAL); - __leave; - } - if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL) - || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET)) - { - set_errno (EPROTONOSUPPORT); - __leave; - } - - /* create the first socket */ - newsock = socket (AF_INET, type, 0); - if (newsock == INVALID_SOCKET) - { - debug_printf ("first socket call failed"); - set_winsock_errno (); - __leave; - } - - /* bind the socket to any unused port */ - sock_in.sin_family = AF_INET; - sock_in.sin_port = 0; - sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) - { - debug_printf ("bind failed"); - set_winsock_errno (); - __leave; - } - len = sizeof (sock_in); - if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0) - { - debug_printf ("getsockname error"); - set_winsock_errno (); - __leave; - } - - /* For stream sockets, create a listener */ - if (type == SOCK_STREAM) - listen (newsock, 2); - - /* create a connecting socket */ - outsock = socket (AF_INET, type, 0); - if (outsock == INVALID_SOCKET) - { - debug_printf ("second socket call failed"); - set_winsock_errno (); - __leave; - } - - /* For datagram sockets, bind the 2nd socket to an unused address, too */ - if (type == SOCK_DGRAM) - { - sock_out.sin_family = AF_INET; - sock_out.sin_port = 0; - sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0) - { - debug_printf ("bind failed"); - set_winsock_errno (); - __leave; - } - len = sizeof (sock_out); - if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0) - { - debug_printf ("getsockname error"); - set_winsock_errno (); - __leave; - } - } - - /* Force IP address to loopback */ - sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (type == SOCK_DGRAM) - sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - - /* Do a connect */ - if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) - { - debug_printf ("connect error"); - set_winsock_errno (); - __leave; - } - - if (type == SOCK_STREAM) - { - /* For stream sockets, accept the connection and close the listener */ - len = sizeof (sock_in); - insock = accept (newsock, (struct sockaddr *) &sock_in, &len); - if (insock == INVALID_SOCKET) - { - debug_printf ("accept error"); - set_winsock_errno (); - __leave; - } - closesocket (newsock); - newsock = INVALID_SOCKET; - } - else - { - /* For datagram sockets, connect the 2nd socket */ - if (connect (newsock, (struct sockaddr *) &sock_out, - sizeof (sock_out)) < 0) - { - debug_printf ("connect error"); - set_winsock_errno (); - __leave; - } - insock = newsock; - newsock = INVALID_SOCKET; - } - - cygheap_fdnew sb0; - const device *dev; - - if (family == AF_INET) - dev = (type == SOCK_STREAM ? tcp_dev : udp_dev); - else - dev = (type == SOCK_STREAM ? stream_dev : dgram_dev); - - if (sb0 >= 0 && fdsock (sb0, dev, insock)) - { - ((fhandler_socket *) sb0)->set_addr_family (family); - ((fhandler_socket *) sb0)->set_socket_type (type); - ((fhandler_socket *) sb0)->connect_state (connected); - if (flags & SOCK_NONBLOCK) - ((fhandler_socket *) sb0)->set_nonblocking (true); - if (flags & SOCK_CLOEXEC) - ((fhandler_socket *) sb0)->set_close_on_exec (true); - if (family == AF_LOCAL && type == SOCK_STREAM) - ((fhandler_socket *) sb0)->af_local_set_sockpair_cred (); - - cygheap_fdnew sb1 (sb0, false); - - if (sb1 >= 0 && fdsock (sb1, dev, outsock)) - { - ((fhandler_socket *) sb1)->set_addr_family (family); - ((fhandler_socket *) sb1)->set_socket_type (type); - ((fhandler_socket *) sb1)->connect_state (connected); - if (flags & SOCK_NONBLOCK) - ((fhandler_socket *) sb1)->set_nonblocking (true); - if (flags & SOCK_CLOEXEC) - ((fhandler_socket *) sb1)->set_close_on_exec (true); - if (family == AF_LOCAL && type == SOCK_STREAM) - ((fhandler_socket *) sb1)->af_local_set_sockpair_cred (); - - sb[0] = sb0; - sb[1] = sb1; - res = 0; - } - else - sb0.release (); - } - } - __except (EFAULT) {} - __endtry - syscall_printf ("%R = socketpair(...)", res); - if (res == -1) - { - if (insock != INVALID_SOCKET) - closesocket (insock); - if (outsock != INVALID_SOCKET) - closesocket (outsock); - if (newsock != INVALID_SOCKET) - closesocket (newsock); - } - return res; -} - -/* sethostent: standards? */ -extern "C" void -sethostent (int) -{ -} - -/* endhostent: standards? */ -extern "C" void -endhostent (void) -{ -} - -/* exported as recvmsg: standards? */ -extern "C" ssize_t -cygwin_recvmsg (int fd, struct msghdr *msg, int flags) -{ - ssize_t res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - { - res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); - /* Originally we shortcircuited here if res == 0. - Allow 0 bytes buffer. This is valid in POSIX and handled in - fhandler_socket::recv_internal. If we shortcircuit, we fail - to deliver valid error conditions and peer address. */ - if (res >= 0) - res = fh->recvmsg (msg, flags); - } - } - __except (EFAULT) - { - res = -1; - } - __endtry - syscall_printf ("%lR = recvmsg(%d, %p, %y)", res, fd, msg, flags); - return res; -} - -/* exported as sendmsg: standards? */ -extern "C" ssize_t -cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) -{ - ssize_t res = -1; - - pthread_testcancel (); - - __try - { - fhandler_socket *fh = get (fd); - if (fh) - { - res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); - if (res >= 0) - res = fh->sendmsg (msg, flags); - } - } - __except (EFAULT) - { - res = -1; - } - __endtry - syscall_printf ("%lR = sendmsg(%d, %p, %y)", res, fd, msg, flags); - return res; -} - -/* 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. - */ - -/* 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 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) -{ - 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) - { - errno = ENOSPC; - return (NULL); - } - strcpy(dst, tmp); - return (dst); -} - -/* 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; - best.len = 0; - cur.len = 0; - 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))) - { - if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) - return (NULL); - tp += strlen(tp); - break; - } - __small_sprintf(tp, "%x", words[i]); - while (*tp) - { - if (isupper (*tp)) - *tp = _tolower (*tp); - ++tp; - } - } - /* 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); -} - -/* 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 af, const void *src, char *dst, socklen_t size) -{ - 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 */ -} - -extern "C" void -cygwin_freeaddrinfo (struct addrinfo *addr) -{ - struct addrinfo *ai, *ainext; - - for (ai = addr; 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 */ - } -} - -static struct addrinfo * -ga_dup (struct addrinfoW *ai, bool v4mapped, int idn_flags, int &err) -{ - struct addrinfo *nai; - - if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) - { - err = EAI_MEMORY; - return NULL; - } - - nai->ai_family = v4mapped ? AF_INET6 : ai->ai_family; - nai->ai_socktype = ai->ai_socktype; - nai->ai_protocol = ai->ai_protocol; - if (ai->ai_canonname) - { - tmp_pathbuf tp; - wchar_t *canonname = ai->ai_canonname; - - if (idn_flags & AI_CANONIDN) - { - /* Map flags to equivalent IDN_* flags. */ - wchar_t *canonbuf = tp.w_get (); - if (IdnToUnicode (idn_flags >> 16, canonname, -1, - canonbuf, NT_MAX_PATH)) - canonname = canonbuf; - else if (GetLastError () != ERROR_PROC_NOT_FOUND) - { - free (nai); - err = EAI_IDN_ENCODE; - return NULL; - } - } - size_t len = wcstombs (NULL, canonname, 0); - if (len == (size_t) -1) - { - free (nai); - err = EAI_IDN_ENCODE; - return NULL; - } - nai->ai_canonname = (char *) malloc (len + 1); - if (!nai->ai_canonname) - { - free (nai); - err = EAI_MEMORY; - return NULL; - } - wcstombs (nai->ai_canonname, canonname, len + 1); - } - - nai->ai_addrlen = v4mapped ? sizeof (struct sockaddr_in6) : ai->ai_addrlen; - if ((nai->ai_addr = (struct sockaddr *) malloc (v4mapped - ? sizeof (struct sockaddr_in6) - : ai->ai_addrlen)) == NULL) - { - if (nai->ai_canonname) - free (nai->ai_canonname); - free (nai); - err = EAI_MEMORY; - return NULL; - } - if (v4mapped) - { - struct sockaddr_in6 *in = (struct sockaddr_in6 *) nai->ai_addr; - in->sin6_family = AF_INET6; - in->sin6_port = ((struct sockaddr_in *) ai->ai_addr)->sin_port; - in->sin6_flowinfo = 0; - in->sin6_addr.s6_addr32[0] = 0; - in->sin6_addr.s6_addr32[1] = 0; - in->sin6_addr.s6_addr32[2] = htonl (0xffff); - in->sin6_addr.s6_addr32[3] = ((struct sockaddr_in *) ai->ai_addr)->sin_addr.s_addr; - in->sin6_scope_id = 0; - } - else - memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen); - - return nai; -} - -static struct addrinfo * -ga_duplist (struct addrinfoW *ai, bool v4mapped, int idn_flags, int &err) -{ - struct addrinfo *tmp, *nai = NULL, *nai0 = NULL; - - for (; ai; ai = ai->ai_next, nai = tmp) - { - if (!(tmp = ga_dup (ai, v4mapped, idn_flags, err))) - goto bad; - if (!nai0) - nai0 = tmp; - if (nai) - nai->ai_next = tmp; - } - return nai0; - -bad: - cygwin_freeaddrinfo (nai0); - return NULL; -} - -/* Cygwin specific wrappers around the gai functions. */ -static struct gai_errmap_t -{ - int w32_errval; - const char *errtxt; -} gai_errmap[] = -{ - {0, "Success"}, - /* EAI_ADDRFAMILY */ - {0, "Address family for hostname not supported"}, - /* EAI_AGAIN */ - {WSATRY_AGAIN, "Temporary failure in name resolution"}, - /* EAI_BADFLAGS */ - {WSAEINVAL, "Bad value for ai_flags"}, - /* EAI_FAIL */ - {WSANO_RECOVERY, "Non-recoverable failure in name resolution"}, - /* EAI_FAMILY */ - {WSAEAFNOSUPPORT, "ai_family not supported"}, - /* EAI_MEMORY */ - {WSA_NOT_ENOUGH_MEMORY, "Memory allocation failure"}, - /* EAI_NODATA */ - {WSANO_DATA, "No address associated with hostname"}, - /* EAI_NONAME */ - {WSAHOST_NOT_FOUND, "Name or service not known"}, - /* EAI_SERVICE */ - {WSATYPE_NOT_FOUND, "Servname not supported for ai_socktype"}, - /* EAI_SOCKTYPE */ - {WSAESOCKTNOSUPPORT, "ai_socktype not supported"}, - /* EAI_SYSTEM */ - {0, "System error"}, - /* EAI_BADHINTS */ - {0, "Invalid value for hints"}, - /* EAI_PROTOCOL */ - {0, "Resolved protocol is unknown"}, - /* EAI_OVERFLOW */ - {WSAEFAULT, "An argument buffer overflowed"}, - /* EAI_IDN_ENCODE */ - {0, "Parameter string not correctly encoded"} -}; - -extern "C" const char * -cygwin_gai_strerror (int err) -{ - if (err >= 0 && err < (int) (sizeof gai_errmap / sizeof *gai_errmap)) - return gai_errmap[err].errtxt; - return "Unknown error"; -} - -static int -w32_to_gai_err (int w32_err) -{ - if (w32_err >= WSABASEERR) - for (unsigned i = 0; i < sizeof gai_errmap / sizeof *gai_errmap; ++i) - if (gai_errmap[i].w32_errval == w32_err) - return i; - return w32_err; -} - -extern "C" int -cygwin_getaddrinfo (const char *hostname, const char *servname, - const struct addrinfo *hints, struct addrinfo **res) -{ - int ret = 0; - - /* Windows' getaddrinfo implementations lets all possible values - in ai_flags slip through and just ignores unknown values. So we - check manually here. */ -#define AI_IDN_MASK (AI_IDN | \ - AI_CANONIDN | \ - AI_IDN_ALLOW_UNASSIGNED | \ - AI_IDN_USE_STD3_ASCII_RULES) -#ifndef AI_DISABLE_IDN_ENCODING -#define AI_DISABLE_IDN_ENCODING 0x80000 -#endif - __try - { - if (hints && (hints->ai_flags - & ~(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_ALL - | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED - | AI_IDN_MASK))) - return EAI_BADFLAGS; - /* AI_NUMERICSERV is not supported prior to Windows Vista. We just check - the servname parameter by ourselves here. */ - if (hints && (hints->ai_flags & AI_NUMERICSERV)) - { - char *p; - if (servname && *servname && (strtoul (servname, &p, 10), *p)) - return EAI_NONAME; - } - - int idn_flags = hints ? (hints->ai_flags & AI_IDN_MASK) : 0; - const char *src; - mbstate_t ps; - tmp_pathbuf tp; - wchar_t *whost = NULL, *wserv = NULL; - struct addrinfoW whints, *wres; - - if (hostname) - { - memset (&ps, 0, sizeof ps); - src = hostname; - whost = tp.w_get (); - if (mbsrtowcs (whost, &src, NT_MAX_PATH, &ps) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_MEMORY; - if (idn_flags & AI_IDN) - { - /* Map flags to equivalent IDN_* flags. */ - wchar_t *ascbuf = tp.w_get (); - if (IdnToAscii (idn_flags >> 16, whost, -1, ascbuf, NT_MAX_PATH)) - whost = ascbuf; - else if (GetLastError () != ERROR_PROC_NOT_FOUND) - return EAI_IDN_ENCODE; - } - } - if (servname) - { - memset (&ps, 0, sizeof ps); - src = servname; - wserv = tp.w_get (); - if (mbsrtowcs (wserv, &src, NT_MAX_PATH, &ps) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_MEMORY; - } - - if (!hints) - { - /* Default settings per glibc man page. */ - memset (&whints, 0, sizeof whints); - whints.ai_family = PF_UNSPEC; - whints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; - } - else - { - /* sizeof addrinfo == sizeof addrinfoW */ - memcpy (&whints, hints, sizeof whints); - whints.ai_flags &= ~AI_IDN_MASK; -#ifdef __x86_64__ - /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in - Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ - whints.ai_addrlen &= UINT32_MAX; -#endif - /* AI_ADDRCONFIG is not supported prior to Vista. Rather it's - the default and only possible setting. - On Vista, the default behaviour is as if AI_ADDRCONFIG is set, - apparently for performance reasons. To get the POSIX default - behaviour, the AI_ALL flag has to be set. */ - if (wincap.supports_all_posix_ai_flags () - && whints.ai_family == PF_UNSPEC - && !(whints.ai_flags & AI_ADDRCONFIG)) - whints.ai_flags |= AI_ALL; - } - /* Disable automatic IDN conversion on W8 and later. */ - whints.ai_flags |= AI_DISABLE_IDN_ENCODING; - ret = w32_to_gai_err (GetAddrInfoW (whost, wserv, &whints, &wres)); - /* Always copy over to self-allocated memory. */ - if (!ret) - { - *res = ga_duplist (wres, false, idn_flags, ret); - FreeAddrInfoW (wres); - if (!*res) - __leave; - } - /* AI_V4MAPPED and AI_ALL are not supported prior to Vista. So, what - we do here is to emulate AI_V4MAPPED. If no IPv6 addresses are - returned, or the AI_ALL flag is set, we try with AF_INET again, and - convert the returned IPv4 addresses into v4-in-v6 entries. This - is done in ga_dup if the v4mapped flag is set. */ - if (!wincap.supports_all_posix_ai_flags () - && hints - && hints->ai_family == AF_INET6 - && (hints->ai_flags & AI_V4MAPPED) - && (ret == EAI_NODATA || ret == EAI_NONAME - || (hints->ai_flags & AI_ALL))) - { - /* sizeof addrinfo == sizeof addrinfoW */ - memcpy (&whints, hints, sizeof whints); - whints.ai_family = AF_INET; -#ifdef __x86_64__ - /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in - Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ - whints.ai_addrlen &= UINT32_MAX; -#endif - int ret2 = w32_to_gai_err (GetAddrInfoW (whost, wserv, &whints, &wres)); - if (!ret2) - { - struct addrinfo *v4res = ga_duplist (wres, true, idn_flags, ret); - FreeAddrInfoW (wres); - if (!v4res) - { - if (!ret) - cygwin_freeaddrinfo (*res); - __leave; - } - /* If a list of v6 addresses exists, append the v4-in-v6 address - list. Otherwise just return the v4-in-v6 address list. */ - if (!ret) - { - struct addrinfo *ptr; - for (ptr = *res; ptr->ai_next; ptr = ptr->ai_next) - ; - ptr->ai_next = v4res; - } - else - *res = v4res; - ret = 0; - } - } - } - __except (EFAULT) - { - ret = EAI_SYSTEM; - } - __endtry - return ret; -} - -extern "C" int -cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen, - char *host, size_t hostlen, char *serv, - size_t servlen, int flags) -{ - int ret = 0; - - __try - { - /* When the incoming port number does not resolve to a well-known service, - WinSock's getnameinfo up to Windows 2003 returns with error WSANO_DATA - instead of setting `serv' to the numeric port number string, as - required by RFC 3493. This is fixed on Vista and later. To avoid the - error on systems up to Windows 2003, we check if the port number - resolves to a well-known service. If not, we set the NI_NUMERICSERV - flag. */ - if (!wincap.supports_all_posix_ai_flags ()) - { - int port = 0; - - switch (sa->sa_family) - { - case AF_INET: - port = ((struct sockaddr_in *) sa)->sin_port; - break; - case AF_INET6: - port = ((struct sockaddr_in6 *) sa)->sin6_port; - break; - default: - return EAI_FAMILY; - } - if (!port || !getservbyport (port, flags & NI_DGRAM ? "udp" : "tcp")) - flags |= NI_NUMERICSERV; - } - /* We call GetNameInfoW with local buffers and convert to locale - charset to allow RFC 3490 IDNs like glibc 2.3.4 and later. */ -#define NI_IDN_MASK (NI_IDN | \ - NI_IDN_ALLOW_UNASSIGNED | \ - NI_IDN_USE_STD3_ASCII_RULES) - int idn_flags = flags & NI_IDN_MASK; - flags &= ~NI_IDN_MASK; - tmp_pathbuf tp; - wchar_t *whost = NULL, *wserv = NULL; - DWORD whlen = 0, wslen = 0; - - if (host && hostlen) - { - whost = tp.w_get (); - whlen = NT_MAX_PATH; - } - if (serv && servlen) - { - wserv = tp.w_get (); - wslen = NT_MAX_PATH; - } - - ret = w32_to_gai_err (GetNameInfoW (sa, salen, whost, whlen, - wserv, wslen, flags)); - if (!ret) - { - const wchar_t *src; - - if (whost) - { - if (idn_flags & NI_IDN) - { - /* Map flags to equivalent IDN_* flags. */ - wchar_t *idnbuf = tp.w_get (); - if (IdnToUnicode (idn_flags >> 16, whost, -1, - idnbuf, NT_MAX_PATH)) - whost = idnbuf; - else if (GetLastError () != ERROR_PROC_NOT_FOUND) - return EAI_IDN_ENCODE; - } - src = whost; - if (wcsrtombs (host, &src, hostlen, NULL) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_OVERFLOW; - } - if (wserv) - { - src = wserv; - if (wcsrtombs (serv, &src, servlen, NULL) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_OVERFLOW; - } - } - else if (ret == EAI_SYSTEM) - set_winsock_errno (); - } - __except (EFAULT) - { - ret = EAI_SYSTEM; - } - __endtry - return ret; -} - -/* The below function in6_are_prefix_equal has been taken from OpenBSD's - src/sys/netinet6/in6.c. */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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 project 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 PROJECT 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 PROJECT 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. - */ - -/* - * Copyright (c) 1982, 1986, 1991, 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. - * - * @(#)in.c 8.2 (Berkeley) 11/15/93 - */ - -static int -in6_are_prefix_equal (struct in6_addr *p1, struct in6_addr *p2, int len) -{ - int bytelen, bitlen; - - /* sanity check */ - if (0 > len || len > 128) - return 0; - - bytelen = len / 8; - bitlen = len % 8; - - if (memcmp (&p1->s6_addr, &p2->s6_addr, bytelen)) - return 0; - /* len == 128 is ok because bitlen == 0 then */ - if (bitlen != 0 && - p1->s6_addr[bytelen] >> (8 - bitlen) != - p2->s6_addr[bytelen] >> (8 - bitlen)) - return 0; - - return 1; -} - -/* These functions are stick to the end of this file so that the - optimization in asm/byteorder.h can be used even here in net.cc. */ - -#undef htonl -#undef ntohl -#undef htons -#undef ntohs - -/* htonl: standards? */ -extern "C" uint32_t -htonl (uint32_t x) -{ - return __htonl (x); -} - -/* ntohl: standards? */ -extern "C" uint32_t -ntohl (uint32_t x) -{ - return __ntohl (x); -} - -/* htons: standards? */ -extern "C" uint16_t -htons (uint16_t x) -{ - return __htons (x); -} - -/* ntohs: standards? */ -extern "C" uint16_t -ntohs (uint16_t x) -{ - return __ntohs (x); -} |