Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/net.cc')
-rw-r--r--winsup/cygwin/net.cc3481
1 files changed, 0 insertions, 3481 deletions
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
deleted file mode 100644
index 3f6bb5bab..000000000
--- a/winsup/cygwin/net.cc
+++ /dev/null
@@ -1,3481 +0,0 @@
-/* net.cc: network-related routines.
-
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-/* #define DEBUG_NEST_ON 1 */
-
-#define __INSIDE_CYGWIN_NET__
-
-#include "winsup.h"
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <syslog.h>
-
-#include <stdlib.h>
-#define gethostname cygwin_gethostname
-#include <unistd.h>
-#undef gethostname
-#include <netdb.h>
-#define USE_SYS_TYPES_FD_SET
-#include <winsock2.h>
-#include <iphlpapi.h>
-#include <assert.h>
-#include "cygerrno.h"
-#include "security.h"
-#include "cygwin/version.h"
-#include "perprocess.h"
-#include "path.h"
-#include "fhandler.h"
-#include "dtable.h"
-#include "cygheap.h"
-#include "sigproc.h"
-#include "pinfo.h"
-#include "registry.h"
-#include "cygtls.h"
-#include "cygwin/in6.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);
-} /* 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;
-}
-
-/* htonl: standards? */
-extern "C" unsigned long int
-htonl (unsigned long int x)
-{
- return ((((x & 0x000000ffU) << 24) |
- ((x & 0x0000ff00U) << 8) |
- ((x & 0x00ff0000U) >> 8) |
- ((x & 0xff000000U) >> 24)));
-}
-
-/* ntohl: standards? */
-extern "C" unsigned long int
-ntohl (unsigned long int x)
-{
- return htonl (x);
-}
-
-/* htons: standards? */
-extern "C" unsigned short
-htons (unsigned short x)
-{
- return ((((x & 0x000000ffU) << 8) |
- ((x & 0x0000ff00U) >> 8)));
-}
-
-/* ntohs: standards? */
-extern "C" unsigned short
-ntohs (unsigned short x)
-{
- return htons (x);
-}
-
-/* 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 NO_COPY 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 %d -> 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 NO_COPY 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)
-
-struct unionent
-{
- char *name;
- char **list;
- short port_proto_addrtype;
- short h_len;
- union
- {
- char *s_proto;
- char **h_addr_list;
- };
-};
-
-enum struct_type
-{
- t_hostent, t_protoent, t_servent
-};
-
-static const char *entnames[] = {"host", "proto", "serv"};
-
-/* 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. */
-
-#define dup_ent(old, src, type) __dup_ent ((unionent *&) (_my_tls.locals.old), (unionent *) (src), type)
-#ifdef DEBUGGING
-static void *
-#else
-static inline void *
-#endif
-__dup_ent (unionent *&dst, unionent *src, struct_type type)
-{
- if (dst)
- debug_printf ("old %sent structure \"%s\" %p\n", entnames[type],
- ((unionent *) 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 t_protoent:
- struct_sz = sizeof (protoent);
- break;
- case t_servent:
- struct_sz = sizeof (servent);
- break;
- case t_hostent:
- struct_sz = sizeof (hostent);
- break;
- default:
- api_fatal ("called with invalid value %d", type);
- break;
- }
-
- /* Every *ent begins with a name. Calculate it's 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;
- char *s_proto = NULL;
- if (type == t_servent)
- {
- if (src->s_proto)
- {
- /* Windows 95 idiocy. Structure is misaligned on Windows 95.
- Kludge around this by trying a different pointer alignment. */
- if (!IsBadStringPtr (src->s_proto, INT32_MAX))
- s_proto = src->s_proto;
- else if (!IsBadStringPtr (((pservent *) src)->s_proto, INT32_MAX))
- s_proto = ((pservent *) src)->s_proto;
- sz += (protolen = strlen_round (s_proto));
- }
- }
- else if (type == 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. 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);
- dst = (unionent *) realloc (dst, rsz);
-
- /* Hopefully, this worked. */
- if (dst)
- {
- memset (dst, 0, sz);
- /* This field is common to all *ent structures but named differently
- in each, of course. */
- 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 == t_protoent)
- debug_printf ("protoent %s %x %x", dst->name, dst->list, dst->port_proto_addrtype);
- else if (type == t_servent)
- {
- if (s_proto)
- {
- strcpy (dst->s_proto = dp, s_proto);
- dp += protolen;
- }
- }
- else if (type == 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;
-}
-
-/* exported as getprotobyname: standards? */
-extern "C" struct protoent *
-cygwin_getprotobyname (const char *p)
-{
- myfault efault;
- if (efault.faulted (EFAULT))
- return NULL;
- return (protoent *) dup_ent (protoent_buf, getprotobyname (p), t_protoent);
-}
-
-/* exported as getprotobynumber: standards? */
-extern "C" struct protoent *
-cygwin_getprotobynumber (int number)
-{
- return (protoent *) dup_ent (protoent_buf, getprotobynumber (number), t_protoent);
-}
-
-bool
-fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc)
-{
- /* NT systems apparently set sockets to inheritable by default */
- if (!wincap.has_set_handle_information ()
- && !DuplicateHandle (hMainProc, (HANDLE) soc,
- hMainProc, (HANDLE *) &soc,
- 0, TRUE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
- {
- debug_printf ("set socket inheritance failed, %E");
- return false;
- }
- fd = build_fh_dev (*dev);
- if (!fd.isopen ())
- return false;
- fd->set_io_handle ((HANDLE) soc);
- if (!((fhandler_socket *) fd)->init_events ())
- return false;
- fd->set_flags (O_RDWR | O_BINARY);
- fd->uninterruptible_io (true);
- debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name, soc);
-#if 0
- /* Same default buffer sizes as on Linux (instead of WinSock default 8K).
-
- NOT. If the SO_RCVBUF size exceeds 65535(*), and if the socket is
- connected to a remote machine, then duplicating the socket on
- fork/exec fails with WinSock error 10022, WSAEINVAL. Given that,
- there's not any good reason to set the buffer sizes at all. So we
- stick with the defaults. However, an explanation for this weird
- behaviour would be nice. I keep this stuff in the code for later
- generations. Archeological programmers might find it useful.
-
- (*) Maximum normal TCP window size. Coincidence? */
-
- int rmem = dev == tcp_dev ? 87380 : 120832;
- int wmem = dev == tcp_dev ? 16384 : 120832;
- if (::setsockopt (soc, SOL_SOCKET, SO_RCVBUF, (char *) &rmem, sizeof (int)))
- debug_printf ("setsockopt(SO_RCVBUF) failed, %lu", WSAGetLastError ());
- if (::setsockopt (soc, SOL_SOCKET, SO_SNDBUF, (char *) &wmem, sizeof (int)))
- debug_printf ("setsockopt(SO_SNDBUF) failed, %lu", WSAGetLastError ());
-#endif
- return true;
-}
-
-/* exported as socket: standards? */
-extern "C" int
-cygwin_socket (int af, int type, int protocol)
-{
- int res = -1;
- SOCKET soc = 0;
-
- debug_printf ("socket (%d, %d, %d)", af, type, protocol);
-
- 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);
- res = fd;
- }
- }
-
-done:
- syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol);
- return res;
-}
-
-/* exported as sendto: standards? */
-extern "C" int
-cygwin_sendto (int fd, const void *buf, size_t len, int flags,
- const struct sockaddr *to, socklen_t tolen)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- res = fh->sendto (buf, len, flags, to, tolen);
-
- syscall_printf ("%d = sendto (%d, %p, %d, %x, %p, %d)",
- res, fd, buf, len, flags, to, tolen);
-
- return res;
-}
-
-/* exported as recvfrom: standards? */
-extern "C" int
-cygwin_recvfrom (int fd, void *buf, size_t len, int flags,
- struct sockaddr *from, socklen_t *fromlen)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else if ((res = len) != 0)
- res = fh->recvfrom (buf, len, flags, from, fromlen);
-
- syscall_printf ("%d = recvfrom (%d, %p, %d, %x, %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;
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- {
- /* 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 = setsockopt (fh->get_socket (), level, optname,
- (const char *) optval, optlen);
-
- if (optlen == 4)
- syscall_printf ("setsockopt optval=%x", *(long *) 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 under Windows
- 2000 and above entirely. */
- if (level == IPPROTO_IP && optname == IP_TOS
- && WSAGetLastError () == WSAEINVAL
- && wincap.has_disabled_user_tos_setting ())
- {
- debug_printf ("Faked IP_TOS success");
- res = 0;
- }
- else
- set_winsock_errno ();
- }
- else if (level == SOL_SOCKET && optname == SO_REUSEADDR)
- fh->saw_reuseaddr (*(int *) optval);
- }
-
- syscall_printf ("%d = setsockopt (%d, %d, %x, %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;
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else if (optname == SO_PEERCRED)
- {
- struct ucred *cred = (struct ucred *) optval;
- res = fh->getpeereid (&cred->pid, &cred->uid, &cred->gid);
- }
- else
- {
- /* 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 (optname == SO_ERROR)
- {
- int *e = (int *) optval;
-
- debug_printf ("WinSock SO_ERROR = %d", *e);
- *e = find_winsock_errno (*e);
- }
-
- if (res)
- set_winsock_errno ();
- }
-
- syscall_printf ("%d = getsockopt (%d, %d, 0x%x, %p, %p)",
- res, fd, level, optname, optval, optlen);
- return res;
-}
-
-extern "C" int
-getpeereid (int fd, __uid32_t *euid, __gid32_t *egid)
-{
- sig_dispatch_pending ();
- 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;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- res = fh->connect (name, namelen);
-
- syscall_printf ("%d = 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)
-{
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return NULL;
-
- servent *res = (servent *) dup_ent (servent_buf, getservbyname (name, proto), t_servent);
- 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)
-{
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return NULL;
-
- servent *res = (servent *) dup_ent (servent_buf, getservbyport (port, proto), t_servent);
- syscall_printf ("%p = getservbyport (%d, %s)", _my_tls.locals.servent_buf, port, proto);
- return res;
-}
-
-extern "C" int
-cygwin_gethostname (char *name, size_t len)
-{
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return -1;
-
- if (gethostname (name, len))
- {
- DWORD local_len = len;
-
- if (!GetComputerNameA (name, &local_len))
- {
- set_winsock_errno ();
- return -1;
- }
- }
- debug_printf ("name %s", name);
- return 0;
-}
-
-/* exported as gethostbyname: standards? */
-extern "C" struct hostent *
-cygwin_gethostbyname (const char *name)
-{
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return NULL;
-
- 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;
-
- 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;
- }
-
- hostent *res = (hostent *) dup_ent (hostent_buf, h, t_hostent);
- 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 ();
- }
- return res;
-}
-
-/* exported as gethostbyaddr: standards? */
-extern "C" struct hostent *
-cygwin_gethostbyaddr (const char *addr, int len, int type)
-{
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return NULL;
-
- hostent *res = (hostent *) dup_ent (hostent_buf, gethostbyaddr (addr, len, type), t_hostent);
- if (res)
- debug_printf ("h_name %s", _my_tls.locals.hostent_buf->h_name);
- else
- set_host_errno ();
- return res;
-}
-
-/* exported as accept: standards? */
-extern "C" int
-cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- res = fh->accept (peer, len);
-
- syscall_printf ("%d = accept (%d, %p, %p)", res, fd, peer, len);
- return res;
-}
-
-/* exported as bind: standards? */
-extern "C" int
-cygwin_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen)
-{
- int res;
- sig_dispatch_pending ();
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- res = fh->bind (my_addr, addrlen);
-
- syscall_printf ("%d = 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;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- res = fh->getsockname (addr, namelen);
-
- syscall_printf ("%d = 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;
- sig_dispatch_pending ();
- fhandler_socket *fh = get (fd);
-
- if (!fh)
- res = -1;
- else
- res = fh->listen (backlog);
-
- syscall_printf ("%d = listen (%d, %d)", res, fd, backlog);
- return res;
-}
-
-/* exported as shutdown: standards? */
-extern "C" int
-cygwin_shutdown (int fd, int how)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- if (!fh)
- res = -1;
- else
- res = fh->shutdown (how);
-
- syscall_printf ("%d = 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)
-{
- myfault efault;
- if (efault.faulted ())
- return;
- 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);
-}
-
-/* exported as getpeername: standards? */
-extern "C" int
-cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- res = fh->getpeername (name, len);
-
- syscall_printf ("%d = getpeername (%d) %d", res, fd, (fh ? fh->get_socket () : -1));
- return res;
-}
-
-/* exported as recv: standards? */
-extern "C" int
-cygwin_recv (int fd, void *buf, size_t len, int flags)
-{
- return cygwin_recvfrom (fd, buf, len, flags, NULL, NULL);
-}
-
-/* exported as send: standards? */
-extern "C" int
-cygwin_send (int fd, const void *buf, size_t len, int flags)
-{
- return cygwin_sendto (fd, buf, len, flags, NULL, 0);
-}
-
-/* getdomainname: standards? */
-extern "C" int
-getdomainname (char *domain, size_t len)
-{
- /*
- * This works for Win95 only if the machine is configured to use MS-TCP.
- * If a third-party TCP is being used this will fail.
- * FIXME: On Win95, is there a way to portably check the TCP stack
- * in use and include paths for the Domain name in each ?
- * Punt for now and assume MS-TCP on Win95.
- */
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return -1;
-
- 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;
- }
-
- /* This is only used by Win95 and NT <= 4.0.
- The registry names are language independent.
- FIXME: Handle DHCP on Win95. The DhcpDomain(s) may be available
- in ..VxD\DHCP\DhcpInfoXX\OptionInfo, RFC 1533 format */
-
- reg_key r (HKEY_LOCAL_MACHINE, KEY_READ,
- (!wincap.is_winnt ()) ? "System" : "SYSTEM",
- "CurrentControlSet", "Services",
- (!wincap.is_winnt ()) ? "VxD" : "Tcpip",
- (!wincap.is_winnt ()) ? "MSTCP" : "Parameters", NULL);
-
- if (!r.error ())
- {
- int res1, res2 = 0; /* Suppress compiler warning */
- res1 = r.get_string ("Domain", domain, len, "");
- if (res1 != ERROR_SUCCESS || !domain[0])
- res2 = r.get_string ("DhcpDomain", domain, len, "");
- if (res1 == ERROR_SUCCESS || res2 == ERROR_SUCCESS)
- return 0;
- }
- __seterrno ();
- return -1;
-}
-
-/* Fill out an ifconf struct. */
-
-/*
- * IFCONF 98/ME, NTSP4, W2K:
- * Use IP Helper Library
- */
-static void
-get_2k_ifconf (struct ifconf *ifc, int what)
-{
- int cnt = 0;
- int ethId = 0, pppId = 0, slpId = 0, tokId = 0;
-
- /* Union maps buffer to correct struct */
- struct ifreq *ifr = ifc->ifc_req;
-
- DWORD ip_cnt, lip, lnp;
- DWORD siz_ip_table = 0;
- PMIB_IPADDRTABLE ipt;
- PMIB_IFROW ifrow;
- struct sockaddr_in *sa = NULL;
- struct sockaddr *so = NULL;
-
- typedef struct ifcount_t
- {
- DWORD ifIndex;
- size_t count;
- unsigned int enumerated; // for eth0:1
- unsigned int classId; // for eth0, tok0 ...
-
- };
- ifcount_t *iflist, *ifEntry;
-
- if (GetIpAddrTable (NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER
- && (ifrow = (PMIB_IFROW) alloca (sizeof (MIB_IFROW)))
- && (ipt = (PMIB_IPADDRTABLE) alloca (siz_ip_table))
- && !GetIpAddrTable (ipt, &siz_ip_table, TRUE))
- {
- iflist =
- (ifcount_t *) alloca (sizeof (ifcount_t) * (ipt->dwNumEntries + 1));
- memset (iflist, 0, sizeof (ifcount_t) * (ipt->dwNumEntries + 1));
- for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt)
- {
- ifEntry = iflist;
- /* search for matching entry (and stop at first free entry) */
- while (ifEntry->count != 0)
- {
- if (ifEntry->ifIndex == ipt->table[ip_cnt].dwIndex)
- break;
- ifEntry++;
- }
- if (ifEntry->count == 0)
- {
- ifEntry->count = 1;
- ifEntry->ifIndex = ipt->table[ip_cnt].dwIndex;
- }
- else
- {
- ifEntry->count++;
- }
- }
- // reset the last element. This is just the stopper for the loop.
- iflist[ipt->dwNumEntries].count = 0;
-
- /* Iterate over all configured IP-addresses */
- for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt)
- {
- memset (ifrow, 0, sizeof (MIB_IFROW));
- ifrow->dwIndex = ipt->table[ip_cnt].dwIndex;
- if (GetIfEntry (ifrow) != NO_ERROR)
- continue;
-
- ifcount_t *ifEntry = iflist;
-
- /* search for matching entry (and stop at first free entry) */
- while (ifEntry->count != 0)
- {
- if (ifEntry->ifIndex == ipt->table[ip_cnt].dwIndex)
- break;
- ifEntry++;
- }
-
- /* Setup the interface name */
- switch (ifrow->dwType)
- {
- case MIB_IF_TYPE_TOKENRING:
- if (ifEntry->enumerated == 0)
- {
- ifEntry->classId = tokId++;
- __small_sprintf (ifr->ifr_name, "tok%u",
- ifEntry->classId);
- }
- else
- {
- __small_sprintf (ifr->ifr_name, "tok%u:%u",
- ifEntry->classId,
- ifEntry->enumerated - 1);
- }
- ifEntry->enumerated++;
- break;
- case MIB_IF_TYPE_ETHERNET:
- if (ifEntry->enumerated == 0)
- {
- ifEntry->classId = ethId++;
- __small_sprintf (ifr->ifr_name, "eth%u",
- ifEntry->classId);
- }
- else
- {
- __small_sprintf (ifr->ifr_name, "eth%u:%u",
- ifEntry->classId,
- ifEntry->enumerated - 1);
- }
- ifEntry->enumerated++;
- break;
- case MIB_IF_TYPE_PPP:
- if (ifEntry->enumerated == 0)
- {
- ifEntry->classId = pppId++;
- __small_sprintf (ifr->ifr_name, "ppp%u",
- ifEntry->classId);
- }
- else
- {
- __small_sprintf (ifr->ifr_name, "ppp%u:%u",
- ifEntry->classId,
- ifEntry->enumerated - 1);
- }
- ifEntry->enumerated++;
- break;
- case MIB_IF_TYPE_SLIP:
- if (ifEntry->enumerated == 0)
- {
- ifEntry->classId = slpId++;
- __small_sprintf (ifr->ifr_name, "slp%u",
- ifEntry->classId);
- }
- else
- {
- __small_sprintf (ifr->ifr_name, "slp%u:%u",
- ifEntry->classId,
- ifEntry->enumerated - 1);
- }
- ifEntry->enumerated++;
- break;
- case MIB_IF_TYPE_LOOPBACK:
- strcpy (ifr->ifr_name, "lo");
- break;
- default:
- continue;
- }
- /* setup sockaddr struct */
- switch (what)
- {
- case SIOCGIFCONF:
- case SIOCGIFADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_addr;
- sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFBRDADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
-#if 0
- /* Unfortunately, the field returns only crap. */
- sa->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr;
-#else
- lip = ipt->table[ip_cnt].dwAddr;
- lnp = ipt->table[ip_cnt].dwMask;
- sa->sin_addr.s_addr = lip & lnp | ~lnp;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
-#endif
- break;
- case SIOCGIFNETMASK:
- sa = (struct sockaddr_in *) &ifr->ifr_netmask;
- sa->sin_addr.s_addr = ipt->table[ip_cnt].dwMask;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFHWADDR:
- so = &ifr->ifr_hwaddr;
- for (UINT i = 0; i < IFHWADDRLEN; ++i)
- if (i >= ifrow->dwPhysAddrLen)
- so->sa_data[i] = '\0';
- else
- so->sa_data[i] = ifrow->bPhysAddr[i];
- so->sa_family = AF_INET;
- break;
- case SIOCGIFMETRIC:
- ifr->ifr_metric = 1;
- break;
- case SIOCGIFMTU:
- ifr->ifr_mtu = ifrow->dwMtu;
- break;
- }
- ++cnt;
- if ((caddr_t)++ ifr >
- ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
- goto done;
- }
- }
-
-done:
- /* Set the correct length */
- ifc->ifc_len = cnt * sizeof (struct ifreq);
-}
-
-/*
- * IFCONF Windows NT < SP4:
- * Look at the Bind value in
- * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage\
- * This is a REG_MULTI_SZ with strings of the form:
- * \Device\<Netcard>, where netcard is the name of the net device.
- * Then look under:
- * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<NetCard>\
- * Parameters\Tcpip
- * at the IPAddress, Subnetmask and DefaultGateway values for the
- * required values.
- */
-static void
-get_nt_ifconf (struct ifconf *ifc, int what)
-{
- HKEY key;
- unsigned long lip, lnp;
- struct sockaddr_in *sa = NULL;
- struct sockaddr *so = NULL;
- DWORD size;
- int cnt = 1;
- char *binding = (char *) 0;
-
- /* Union maps buffer to correct struct */
- struct ifreq *ifr = ifc->ifc_req;
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
- "SYSTEM\\"
- "CurrentControlSet\\"
- "Services\\"
- "Tcpip\\" "Linkage",
- 0, KEY_READ, &key) == ERROR_SUCCESS)
- {
- if (RegQueryValueEx (key, "Bind",
- NULL, NULL,
- NULL, &size) == ERROR_SUCCESS)
- {
- binding = (char *) alloca (size);
- if (RegQueryValueEx (key, "Bind",
- NULL, NULL,
- (unsigned char *) binding,
- &size) != ERROR_SUCCESS)
- {
- binding = NULL;
- }
- }
- RegCloseKey (key);
- }
-
- if (binding)
- {
- char *bp, eth[2] = "/";
- char cardkey[256], ipaddress[256], netmask[256];
-
- for (bp = binding; *bp; bp += strlen (bp) + 1)
- {
- bp += strlen ("\\Device\\");
- strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\");
- strcat (cardkey, bp);
- strcat (cardkey, "\\Parameters\\Tcpip");
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey,
- 0, KEY_READ, &key) != ERROR_SUCCESS)
- continue;
-
- if (RegQueryValueEx (key, "IPAddress",
- NULL, NULL,
- (unsigned char *) ipaddress,
- (size = 256, &size)) == ERROR_SUCCESS
- && RegQueryValueEx (key, "SubnetMask",
- NULL, NULL,
- (unsigned char *) netmask,
- (size = 256, &size)) == ERROR_SUCCESS)
- {
- char *ip, *np;
- char dhcpaddress[256], dhcpnetmask[256];
-
- for (ip = ipaddress, np = netmask;
- *ip && *np;
- ip += strlen (ip) + 1, np += strlen (np) + 1)
- {
- if ((caddr_t)++ ifr > ifc->ifc_buf
- + ifc->ifc_len - sizeof (struct ifreq))
- break;
-
- if (!strncmp (bp, "NdisWan", 7))
- {
- strcpy (ifr->ifr_name, "ppp");
- strcat (ifr->ifr_name, bp + 7);
- }
- else
- {
- ++*eth;
- strcpy (ifr->ifr_name, "eth");
- strcat (ifr->ifr_name, eth);
- }
- memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr);
- if (cygwin_inet_addr (ip) == 0L
- && RegQueryValueEx (key, "DhcpIPAddress",
- NULL, NULL,
- (unsigned char *) dhcpaddress,
- (size = 256, &size))
- == ERROR_SUCCESS
- && RegQueryValueEx (key, "DhcpSubnetMask",
- NULL, NULL,
- (unsigned char *) dhcpnetmask,
- (size = 256, &size))
- == ERROR_SUCCESS)
- {
- switch (what)
- {
- case SIOCGIFCONF:
- case SIOCGIFADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_addr;
- sa->sin_addr.s_addr =
- cygwin_inet_addr (dhcpaddress);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFBRDADDR:
- lip = cygwin_inet_addr (dhcpaddress);
- lnp = cygwin_inet_addr (dhcpnetmask);
- sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
- sa->sin_addr.s_addr = lip & lnp | ~lnp;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFNETMASK:
- sa = (struct sockaddr_in *) &ifr->ifr_netmask;
- sa->sin_addr.s_addr =
- cygwin_inet_addr (dhcpnetmask);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFHWADDR:
- so = &ifr->ifr_hwaddr;
- memset (so->sa_data, 0, IFHWADDRLEN);
- so->sa_family = AF_INET;
- break;
- case SIOCGIFMETRIC:
- ifr->ifr_metric = 1;
- break;
- case SIOCGIFMTU:
- ifr->ifr_mtu = 1500;
- break;
- }
- }
- else
- {
- switch (what)
- {
- case SIOCGIFCONF:
- case SIOCGIFADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_addr;
- sa->sin_addr.s_addr = cygwin_inet_addr (ip);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFBRDADDR:
- lip = cygwin_inet_addr (ip);
- lnp = cygwin_inet_addr (np);
- sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
- sa->sin_addr.s_addr = lip & lnp | ~lnp;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFNETMASK:
- sa = (struct sockaddr_in *) &ifr->ifr_netmask;
- sa->sin_addr.s_addr = cygwin_inet_addr (np);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFHWADDR:
- so = &ifr->ifr_hwaddr;
- memset (so->sa_data, 0, IFHWADDRLEN);
- so->sa_family = AF_INET;
- break;
- case SIOCGIFMETRIC:
- ifr->ifr_metric = 1;
- break;
- case SIOCGIFMTU:
- ifr->ifr_mtu = 1500;
- break;
- }
- }
- ++cnt;
- }
- }
- RegCloseKey (key);
- }
- }
-
- /* Set the correct length */
- ifc->ifc_len = cnt * sizeof (struct ifreq);
-}
-
-/*
- * IFCONF Windows 95:
- * HKLM/Enum/Network/MSTCP/"*"
- * -> Value "Driver" enthält Subkey relativ zu
- * HKLM/System/CurrentControlSet/Class/
- * -> In Subkey "Bindings" die Values aufzählen
- * -> Enthält Subkeys der Form "VREDIR\*"
- * Das * ist ein Subkey relativ zu
- * HKLM/System/CurrentControlSet/Class/Net/
- * HKLM/System/CurrentControlSet/Class/"Driver"
- * -> Value "IPAddress"
- * -> Value "IPMask"
- * HKLM/System/CurrentControlSet/Class/Net/"*"(aus "VREDIR\*")
- * -> Wenn Value "AdapterName" == "MS$PPP" -> ppp interface
- * -> Value "DriverDesc" enthält den Namen
- *
- */
-static void
-get_95_ifconf (struct ifconf *ifc, int what)
-{
- HKEY key;
- unsigned long lip, lnp;
- struct sockaddr_in *sa = NULL;
- struct sockaddr *so = NULL;
- FILETIME update;
- LONG res;
- DWORD size;
- int cnt = 1;
- char ifname[256];
- char eth[2] = "/";
- char ppp[2] = "/";
-
- /* Union maps buffer to correct struct */
- struct ifreq *ifr = ifc->ifc_req;
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Enum\\Network\\MSTCP",
- 0, KEY_READ, &key) != ERROR_SUCCESS)
- {
- /* Set the correct length */
- ifc->ifc_len = cnt * sizeof (struct ifreq);
- return;
- }
-
- for (int i = 0;
- (res = RegEnumKeyEx (key, i, ifname,
- (size = sizeof ifname, &size),
- 0, 0, 0, &update)) != ERROR_NO_MORE_ITEMS;
- ++i)
- {
- HKEY ifkey, subkey;
- char driver[256], classname[256], netname[256];
- char adapter[256], ip[256], np[256];
-
- if (res != ERROR_SUCCESS
- || RegOpenKeyEx (key, ifname, 0, KEY_READ, &ifkey) != ERROR_SUCCESS)
- continue;
-
- if (RegQueryValueEx (ifkey, "Driver", 0,
- NULL, (unsigned char *) driver,
- (size = sizeof driver, &size)) != ERROR_SUCCESS)
- {
- RegCloseKey (ifkey);
- continue;
- }
-
- strcpy (classname, "System\\CurrentControlSet\\Services\\Class\\");
- strcat (classname, driver);
- if ((res = RegOpenKeyEx (HKEY_LOCAL_MACHINE, classname,
- 0, KEY_READ, &subkey)) != ERROR_SUCCESS)
- {
- RegCloseKey (ifkey);
- continue;
- }
-
- if (RegQueryValueEx (subkey, "IPAddress", 0,
- NULL, (unsigned char *) ip,
- (size = sizeof ip, &size)) == ERROR_SUCCESS
- && RegQueryValueEx (subkey, "IPMask", 0,
- NULL, (unsigned char *) np,
- (size = sizeof np, &size)) == ERROR_SUCCESS)
- {
- if ((caddr_t)++ ifr > ifc->ifc_buf
- + ifc->ifc_len - sizeof (struct ifreq))
- goto out;
-
- switch (what)
- {
- case SIOCGIFCONF:
- case SIOCGIFADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_addr;
- sa->sin_addr.s_addr = cygwin_inet_addr (ip);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFBRDADDR:
- lip = cygwin_inet_addr (ip);
- lnp = cygwin_inet_addr (np);
- sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
- sa->sin_addr.s_addr = lip & lnp | ~lnp;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFNETMASK:
- sa = (struct sockaddr_in *) &ifr->ifr_netmask;
- sa->sin_addr.s_addr = cygwin_inet_addr (np);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFHWADDR:
- so = &ifr->ifr_hwaddr;
- memset (so->sa_data, 0, IFHWADDRLEN);
- so->sa_family = AF_INET;
- break;
- case SIOCGIFMETRIC:
- ifr->ifr_metric = 1;
- break;
- case SIOCGIFMTU:
- ifr->ifr_mtu = 1500;
- break;
- }
- }
-
- RegCloseKey (subkey);
-
- strcpy (netname, "System\\CurrentControlSet\\Services\\Class\\Net\\");
- strcat (netname, ifname);
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, netname,
- 0, KEY_READ, &subkey) != ERROR_SUCCESS)
- {
- RegCloseKey (ifkey);
- --ifr;
- continue;
- }
-
- if (RegQueryValueEx (subkey, "AdapterName", 0,
- NULL, (unsigned char *) adapter,
- (size = sizeof adapter, &size)) == ERROR_SUCCESS
- && strcasematch (adapter, "MS$PPP"))
- {
- ++*ppp;
- strcpy (ifr->ifr_name, "ppp");
- strcat (ifr->ifr_name, ppp);
- }
- else
- {
- ++*eth;
- strcpy (ifr->ifr_name, "eth");
- strcat (ifr->ifr_name, eth);
- }
-
- RegCloseKey (subkey);
- RegCloseKey (ifkey);
-
- ++cnt;
- }
-
-out:
-
- RegCloseKey (key);
-
- /* Set the correct length */
- ifc->ifc_len = cnt * sizeof (struct ifreq);
-}
-
-int
-get_ifconf (struct ifconf *ifc, int what)
-{
- unsigned long lip, lnp;
- struct sockaddr_in *sa;
-
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return -1;
-
- /* Union maps buffer to correct struct */
- struct ifreq *ifr = ifc->ifc_req;
-
- /* Ensure we have space for two struct ifreqs, fail if not. */
- if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq)))
- {
- set_errno (EFAULT);
- return -1;
- }
-
- /* Set up interface lo0 first */
- strcpy (ifr->ifr_name, "lo");
- memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr));
- switch (what)
- {
- case SIOCGIFCONF:
- case SIOCGIFADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_addr;
- sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFBRDADDR:
- lip = htonl (INADDR_LOOPBACK);
- lnp = cygwin_inet_addr ("255.0.0.0");
- sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
- sa->sin_addr.s_addr = lip & lnp | ~lnp;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFNETMASK:
- sa = (struct sockaddr_in *) &ifr->ifr_netmask;
- sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0");
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFHWADDR:
- ifr->ifr_hwaddr.sa_family = AF_INET;
- memset (ifr->ifr_hwaddr.sa_data, 0, IFHWADDRLEN);
- break;
- case SIOCGIFMETRIC:
- ifr->ifr_metric = 1;
- break;
- case SIOCGIFMTU:
- /* This funny value is returned by `ifconfig lo' on Linux 2.2 kernel. */
- ifr->ifr_mtu = 3924;
- break;
- default:
- set_errno (EINVAL);
- return -1;
- }
-
- if (wincap.has_ip_helper_lib ())
- get_2k_ifconf (ifc, what);
- else if (wincap.is_winnt ())
- get_nt_ifconf (ifc, what);
- else
- get_95_ifconf (ifc, what);
- return 0;
-}
-
-#define PORT_LOW (IPPORT_EFSSERVER + 1)
-#define PORT_HIGH (IPPORT_RESERVED - 1)
-#define NUM_PORTS (PORT_HIGH - PORT_LOW + 1)
-
-LONG last_used_bindresvport __attribute__((section (".cygwin_dll_common"), shared)) = IPPORT_RESERVED;
-
-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;
-
- sig_dispatch_pending ();
-
- myfault efault;
- if (efault.faulted (EFAULT))
- return -1;
-
- fhandler_socket *fh = get (fd);
- if (!fh)
- return -1;
-
- 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);
- return -1;
- }
-
- /* 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))
- return ret;
- }
-
- LONG myport;
-
- for (int i = 0; i < NUM_PORTS; i++)
- {
- while ((myport = InterlockedExchange (&last_used_bindresvport, 0)) == 0)
- low_priority_sleep (0);
- if (--myport < PORT_LOW)
- myport = PORT_HIGH;
- InterlockedExchange (&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;
- }
-
- 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, outsock, newsock;
- struct sockaddr_in sock_in, sock_out;
- int len;
-
- sig_dispatch_pending ();
- myfault efault;
- if (efault.faulted (EFAULT))
- return -1;
-
- if (family != AF_LOCAL && family != AF_INET)
- {
- set_errno (EAFNOSUPPORT);
- goto done;
- }
- if (type != SOCK_STREAM && type != SOCK_DGRAM)
- {
- set_errno (EPROTOTYPE);
- goto done;
- }
- if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL)
- || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET))
- {
- set_errno (EPROTONOSUPPORT);
- goto done;
- }
-
- /* create the first socket */
- newsock = socket (AF_INET, type, 0);
- if (newsock == INVALID_SOCKET)
- {
- debug_printf ("first socket call failed");
- set_winsock_errno ();
- goto done;
- }
-
- /* bind the socket to any unused port */
- sock_in.sin_family = AF_INET;
- sock_in.sin_port = 0;
- sock_in.sin_addr.s_addr = INADDR_ANY;
- if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
- {
- debug_printf ("bind failed");
- set_winsock_errno ();
- closesocket (newsock);
- goto done;
- }
- len = sizeof (sock_in);
- if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0)
- {
- debug_printf ("getsockname error");
- set_winsock_errno ();
- closesocket (newsock);
- goto done;
- }
-
- /* 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 ();
- closesocket (newsock);
- goto done;
- }
-
- /* 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 ();
- closesocket (newsock);
- closesocket (outsock);
- goto done;
- }
- len = sizeof (sock_out);
- if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0)
- {
- debug_printf ("getsockname error");
- set_winsock_errno ();
- closesocket (newsock);
- closesocket (outsock);
- goto done;
- }
- }
-
- /* 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 ();
- closesocket (newsock);
- closesocket (outsock);
- goto done;
- }
-
- 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 ();
- closesocket (newsock);
- closesocket (outsock);
- goto done;
- }
- closesocket (newsock);
- }
- 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 ();
- closesocket (newsock);
- closesocket (outsock);
- goto done;
- }
- insock = newsock;
- }
-
- {
- 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_sun_path ("");
- ((fhandler_socket *) sb0)->set_addr_family (family);
- ((fhandler_socket *) sb0)->set_socket_type (type);
- ((fhandler_socket *) sb0)->connect_state (connected);
- 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_sun_path ("");
- ((fhandler_socket *) sb1)->set_addr_family (family);
- ((fhandler_socket *) sb1)->set_socket_type (type);
- ((fhandler_socket *) sb1)->connect_state (connected);
- if (family == AF_LOCAL && type == SOCK_STREAM)
- ((fhandler_socket *) sb1)->af_local_set_sockpair_cred ();
-
- sb[0] = sb0;
- sb[1] = sb1;
- res = 0;
- }
- }
-
- if (res == -1)
- {
- closesocket (insock);
- closesocket (outsock);
- }
- }
-
-done:
- syscall_printf ("%d = socketpair (...)", res);
- return res;
-}
-
-/* sethostent: standards? */
-extern "C" void
-sethostent (int)
-{
-}
-
-/* endhostent: standards? */
-extern "C" void
-endhostent (void)
-{
-}
-
-/* exported as recvmsg: standards? */
-extern "C" int
-cygwin_recvmsg (int fd, struct msghdr *msg, int flags)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- {
- res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen);
- if (res > 0)
- res = fh->recvmsg (msg, flags);
- }
-
- syscall_printf ("%d = recvmsg (%d, %p, %x)", res, fd, msg, flags);
- return res;
-}
-
-/* exported as sendmsg: standards? */
-extern "C" int
-cygwin_sendmsg (int fd, const struct msghdr *msg, int flags)
-{
- int res;
- sig_dispatch_pending ();
-
- fhandler_socket *fh = get (fd);
-
- myfault efault;
- if (efault.faulted (EFAULT) || !fh)
- res = -1;
- else
- {
- res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen);
- if (res >= 0)
- res = fh->sendmsg (msg, flags);
- }
-
- syscall_printf ("%d = sendmsg (%d, %p, %x)", 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.
- */
-
-#define IN6ADDRSZ 16
-#define INADDRSZ 4
-#define INT16SZ 2
-
-/* int
- * inet_pton4(src, dst)
- * like inet_aton() but without all the hexadecimal and shorthand.
- * return:
- * 1 if `src' is a valid dotted quad, else 0.
- * notice:
- * does not touch `dst' unless it's returning 1.
- * author:
- * Paul Vixie, 1996.
- */
-static int
-inet_pton4 (const char *src, u_char *dst)
-{
- static const char digits[] = "0123456789";
- int saw_digit, octets, ch;
- u_char tmp[INADDRSZ], *tp;
-
- saw_digit = 0;
- octets = 0;
- *(tp = tmp) = 0;
- while ((ch = *src++) != '\0')
- {
- const char *pch;
-
- if ((pch = strchr(digits, ch)) != NULL)
- {
- u_int ret = *tp * 10 + (pch - digits);
-
- if (ret > 255)
- return (0);
- *tp = ret;
- if (! saw_digit)
- {
- if (++octets > 4)
- return (0);
- saw_digit = 1;
- }
- }
- else if (ch == '.' && saw_digit)
- {
- if (octets == 4)
- return (0);
- *++tp = 0;
- saw_digit = 0;
- }
- else
- return (0);
- }
- if (octets < 4)
- return (0);
-
- memcpy(dst, tmp, INADDRSZ);
- return (1);
-}
-
-/* int
- * inet_pton6(src, dst)
- * convert presentation level address to network order binary form.
- * return:
- * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
- * notice:
- * (1) does not touch `dst' unless it's returning 1.
- * (2) :: in a full address is silently ignored.
- * credit:
- * inspired by Mark Andrews.
- * author:
- * Paul Vixie, 1996.
- */
-static int
-inet_pton6 (const char *src, u_char *dst)
-{
- static const char xdigits_l[] = "0123456789abcdef",
- xdigits_u[] = "0123456789ABCDEF";
- u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
- const char *xdigits, *curtok;
- int ch, saw_xdigit;
- u_int val;
-
- memset((tp = tmp), 0, IN6ADDRSZ);
- endp = tp + IN6ADDRSZ;
- colonp = NULL;
- /* Leading :: requires some special handling. */
- if (*src == ':')
- if (*++src != ':')
- return (0);
- curtok = src;
- saw_xdigit = 0;
- val = 0;
- while ((ch = *src++) != '\0')
- {
- const char *pch;
-
- if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
- pch = strchr((xdigits = xdigits_u), ch);
- if (pch != NULL)
- {
- val <<= 4;
- val |= (pch - xdigits);
- if (val > 0xffff)
- return (0);
- saw_xdigit = 1;
- continue;
- }
- if (ch == ':')
- {
- curtok = src;
- if (!saw_xdigit)
- {
- if (colonp)
- return (0);
- colonp = tp;
- continue;
- }
- if (tp + INT16SZ > endp)
- return (0);
- *tp++ = (u_char) (val >> 8) & 0xff;
- *tp++ = (u_char) val & 0xff;
- saw_xdigit = 0;
- val = 0;
- continue;
- }
- if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
- {
- tp += INADDRSZ;
- saw_xdigit = 0;
- break; /* '\0' was seen by inet_pton4(). */
- }
- return (0);
- }
- if (saw_xdigit)
- {
- if (tp + INT16SZ > endp)
- return (0);
- *tp++ = (u_char) (val >> 8) & 0xff;
- *tp++ = (u_char) val & 0xff;
- }
- if (colonp != NULL)
- {
- /*
- * Since some memmove()'s erroneously fail to handle
- * overlapping regions, we'll do the shift by hand.
- */
- const int n = tp - colonp;
- int i;
-
- for (i = 1; i <= n; i++)
- {
- endp[- i] = colonp[n - i];
- colonp[n - i] = 0;
- }
- tp = endp;
- }
- if (tp != endp)
- return (0);
-
- memcpy(dst, tmp, IN6ADDRSZ);
- return (1);
-}
-
-/* int
- * inet_pton(af, src, dst)
- * convert from presentation format (which usually means ASCII printable)
- * to network format (which is usually some kind of binary format).
- * return:
- * 1 if the address was valid for the specified address family
- * 0 if the address wasn't valid (`dst' is untouched in this case)
- * -1 if some other error occurred (`dst' is untouched in this case, too)
- * author:
- * Paul Vixie, 1996.
- */
-extern "C" int
-cygwin_inet_pton (int 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;
- 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]);
- tp += strlen(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 */
-}
-
-/* W. Richard STEVENS libgai implementation, slightly tweaked for inclusion
- into Cygwin as pure IPv4 replacement. Please note that the code is
- kept intact as much as possible. Especially the IPv6 and AF_UNIX code
- is kept in, even though we can support neither of them. Please don't
- activate them, they won't work correctly. */
-
-#define IPv4
-#undef IPv6
-#undef UNIXdomain
-
-#undef HAVE_SOCKADDR_SA_LEN
-#define gethostbyname2(host,family) cygwin_gethostbyname((host))
-
-#define AI_CLONE 0x8000 /* Avoid collision with AI_ values in netdb.h */
-
-/*
- * Create and fill in an addrinfo{}.
- */
-
-/* include ga_aistruct1 */
-static int
-ga_aistruct (struct addrinfo ***paipnext, const struct addrinfo *hintsp,
- const void *addr, int family)
-{
- struct addrinfo *ai;
-
- if ((ai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL)
- return (EAI_MEMORY);
- ai->ai_next = NULL;
- ai->ai_canonname = NULL;
- **paipnext = ai;
- *paipnext = &ai->ai_next;
-
- if ((ai->ai_socktype = hintsp->ai_socktype) == 0)
- ai->ai_flags |= AI_CLONE;
-
- ai->ai_protocol = hintsp->ai_protocol;
-/* end ga_aistruct1 */
-
-/* include ga_aistruct2 */
- switch ((ai->ai_family = family))
- {
-#ifdef IPv4
- case AF_INET:
- {
- struct sockaddr_in *sinptr;
-
- /* 4allocate sockaddr_in{} and fill in all but port */
- if ((sinptr = (struct sockaddr_in *)
- calloc (1, sizeof (struct sockaddr_in))) == NULL)
- return (EAI_MEMORY);
-#ifdef HAVE_SOCKADDR_SA_LEN
- sinptr->sin_len = sizeof (struct sockaddr_in);
-#endif
- sinptr->sin_family = AF_INET;
- memcpy (&sinptr->sin_addr, addr, sizeof (struct in_addr));
- ai->ai_addr = (struct sockaddr *) sinptr;
- ai->ai_addrlen = sizeof (struct sockaddr_in);
- break;
- }
-#endif /* IPV4 */
-#ifdef IPv6
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6ptr;
-
- /* 4allocate sockaddr_in6{} and fill in all but port */
- if ((sin6ptr = calloc (1, sizeof (struct sockaddr_in6))) == NULL)
- return (EAI_MEMORY);
-#ifdef HAVE_SOCKADDR_SA_LEN
- sin6ptr->sin6_len = sizeof (struct sockaddr_in6);
-#endif
- sin6ptr->sin6_family = AF_INET6;
- memcpy (&sin6ptr->sin6_addr, addr, sizeof (struct in6_addr));
- ai->ai_addr = (struct sockaddr *) sin6ptr;
- ai->ai_addrlen = sizeof (struct sockaddr_in6);
- break;
- }
-#endif /* IPV6 */
-#ifdef UNIXdomain
- case AF_LOCAL:
- {
- struct sockaddr_un *unp;
-
- /* 4allocate sockaddr_un{} and fill in */
-/* *INDENT-OFF* */
- if (strlen(addr) >= sizeof(unp->sun_path))
- return(EAI_SERVICE);
- if ( (unp = calloc(1, sizeof(struct sockaddr_un))) == NULL)
- return(EAI_MEMORY);
-/* *INDENT-ON* */
- unp->sun_family = AF_LOCAL;
- strcpy (unp->sun_path, addr);
-#ifdef HAVE_SOCKADDR_SA_LEN
- unp->sun_len = SUN_LEN (unp);
-#endif
- ai->ai_addr = (struct sockaddr *) unp;
- ai->ai_addrlen = sizeof (struct sockaddr_un);
- if (hintsp->ai_flags & AI_PASSIVE)
- unlink (unp->sun_path); /* OK if this fails */
- break;
- }
-#endif /* UNIXDOMAIN */
- }
- return (0);
-}
-
-/* end ga_aistruct2 */
-
-/*
- * Clone a new addrinfo structure from an existing one.
- */
-
-/* include ga_clone */
-static struct addrinfo *
-ga_clone (struct addrinfo *ai)
-{
- struct addrinfo *nai;
-
- if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL)
- return (NULL);
-
- nai->ai_next = ai->ai_next;
- ai->ai_next = nai;
-
- nai->ai_flags = 0; /* make sure AI_CLONE is off */
- nai->ai_family = ai->ai_family;
- nai->ai_socktype = ai->ai_socktype;
- nai->ai_protocol = ai->ai_protocol;
- nai->ai_canonname = NULL;
- nai->ai_addrlen = ai->ai_addrlen;
- if ((nai->ai_addr = (struct sockaddr *) malloc (ai->ai_addrlen)) == NULL)
- return (NULL);
- memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen);
-
- return (nai);
-}
-
-/* end ga_clone */
-
-/*
- * Basic error checking of flags, family, socket type, and protocol.
- */
-
-/* include ga_echeck */
-static int
-ga_echeck (const char *hostname, const char *servname,
- int flags, int family, int socktype, int protocol)
-{
- if (flags & ~(AI_PASSIVE | AI_CANONNAME))
- return (EAI_BADFLAGS); /* unknown flag bits */
-
- if (hostname == NULL || hostname[0] == '\0')
- {
- if (servname == NULL || servname[0] == '\0')
- return (EAI_NONAME); /* host or service must be specified */
- }
-
- switch (family)
- {
- case AF_UNSPEC:
- break;
-#ifdef IPv4
- case AF_INET:
- if (socktype != 0 &&
- (socktype != SOCK_STREAM &&
- socktype != SOCK_DGRAM && socktype != SOCK_RAW))
- return (EAI_SOCKTYPE); /* invalid socket type */
- break;
-#endif
-#ifdef IPv6
- case AF_INET6:
- if (socktype != 0 &&
- (socktype != SOCK_STREAM &&
- socktype != SOCK_DGRAM && socktype != SOCK_RAW))
- return (EAI_SOCKTYPE); /* invalid socket type */
- break;
-#endif
-#ifdef UNIXdomain
- case AF_LOCAL:
- if (socktype != 0 &&
- (socktype != SOCK_STREAM && socktype != SOCK_DGRAM))
- return (EAI_SOCKTYPE); /* invalid socket type */
- break;
-#endif
- default:
- return (EAI_FAMILY); /* unknown protocol family */
- }
- return (0);
-}
-
-/* end ga_echeck */
-
-struct search {
- const char *host; /* hostname or address string */
- int family; /* AF_xxx */
-};
-
-/*
- * Set up the search[] array with the hostnames and address families
- * that we are to look up.
- */
-
-/* include ga_nsearch1 */
-static int
-ga_nsearch (const char *hostname, const struct addrinfo *hintsp,
- struct search *search)
-{
- int nsearch = 0;
-
- if (hostname == NULL || hostname[0] == '\0')
- {
- if (hintsp->ai_flags & AI_PASSIVE)
- {
- /* 4no hostname and AI_PASSIVE: implies wildcard bind */
- switch (hintsp->ai_family)
- {
-#ifdef IPv4
- case AF_INET:
- search[nsearch].host = "0.0.0.0";
- search[nsearch].family = AF_INET;
- nsearch++;
- break;
-#endif
-#ifdef IPv6
- case AF_INET6:
- search[nsearch].host = "0::0";
- search[nsearch].family = AF_INET6;
- nsearch++;
- break;
-#endif
- case AF_UNSPEC:
-#ifdef IPv6
- search[nsearch].host = "0::0"; /* IPv6 first, then IPv4 */
- search[nsearch].family = AF_INET6;
- nsearch++;
-#endif
-#ifdef IPv4
- search[nsearch].host = "0.0.0.0";
- search[nsearch].family = AF_INET;
- nsearch++;
-#endif
- break;
- }
-/* end ga_nsearch1 */
-/* include ga_nsearch2 */
- }
- else
- {
- /* 4no host and not AI_PASSIVE: connect to local host */
- switch (hintsp->ai_family)
- {
-#ifdef IPv4
- case AF_INET:
- search[nsearch].host = "localhost"; /* 127.0.0.1 */
- search[nsearch].family = AF_INET;
- nsearch++;
- break;
-#endif
-#ifdef IPv6
- case AF_INET6:
- search[nsearch].host = "0::1";
- search[nsearch].family = AF_INET6;
- nsearch++;
- break;
-#endif
- case AF_UNSPEC:
-#ifdef IPv6
- search[nsearch].host = "0::1"; /* IPv6 first, then IPv4 */
- search[nsearch].family = AF_INET6;
- nsearch++;
-#endif
-#ifdef IPv4
- search[nsearch].host = "localhost";
- search[nsearch].family = AF_INET;
- nsearch++;
-#endif
- break;
- }
- }
-/* end ga_nsearch2 */
-/* include ga_nsearch3 */
- }
- else
- { /* host is specified */
- switch (hintsp->ai_family)
- {
-#ifdef IPv4
- case AF_INET:
- search[nsearch].host = hostname;
- search[nsearch].family = AF_INET;
- nsearch++;
- break;
-#endif
-#ifdef IPv6
- case AF_INET6:
- search[nsearch].host = hostname;
- search[nsearch].family = AF_INET6;
- nsearch++;
- break;
-#endif
- case AF_UNSPEC:
-#ifdef IPv6
- search[nsearch].host = hostname;
- search[nsearch].family = AF_INET6; /* IPv6 first */
- nsearch++;
-#endif
-#ifdef IPv4
- search[nsearch].host = hostname;
- search[nsearch].family = AF_INET; /* then IPv4 */
- nsearch++;
-#endif
- break;
- }
- }
- if (nsearch < 1 || nsearch > 2)
- return -1;
- return (nsearch);
-}
-
-/* end ga_nsearch3 */
-
-/*
- * Go through all the addrinfo structures, checking for a match of the
- * socket type and filling in the socket type, and then the port number
- * in the corresponding socket address structures.
- *
- * The AI_CLONE flag works as follows. Consider a multihomed host with
- * two IP addresses and no socket type specified by the caller. After
- * the "host" search there are two addrinfo structures, one per IP address.
- * Assuming a service supported by both TCP and UDP (say the daytime
- * service) we need to return *four* addrinfo structures:
- * IP#1, SOCK_STREAM, TCP port,
- * IP#1, SOCK_DGRAM, UDP port,
- * IP#2, SOCK_STREAM, TCP port,
- * IP#2, SOCK_DGRAM, UDP port.
- * To do this, when the "host" loop creates an addrinfo structure, if the
- * caller has not specified a socket type (hintsp->ai_socktype == 0), the
- * AI_CLONE flag is set. When the following function finds an entry like
- * this it is handled as follows: If the entry's ai_socktype is still 0,
- * this is the first use of the structure, and the ai_socktype field is set.
- * But, if the entry's ai_socktype is nonzero, then we clone a new addrinfo
- * structure and set it's ai_socktype to the new value. Although we only
- * need two socket types today (SOCK_STREAM and SOCK_DGRAM) this algorithm
- * will handle any number. Also notice that Posix.1g requires all socket
- * types to be nonzero.
- */
-
-/* include ga_port */
-static int
-ga_port (struct addrinfo *aihead, int port, int socktype)
- /* port must be in network byte order */
-{
- int nfound = 0;
- struct addrinfo *ai;
-
- for (ai = aihead; ai != NULL; ai = ai->ai_next)
- {
- if (ai->ai_flags & AI_CLONE)
- {
- if (ai->ai_socktype != 0)
- {
- if ((ai = ga_clone (ai)) == NULL)
- return (-1); /* memory allocation error */
- /* ai points to newly cloned entry, which is what we want */
- }
- }
- else if (ai->ai_socktype != socktype)
- continue; /* ignore if mismatch on socket type */
-
- ai->ai_socktype = socktype;
-
- switch (ai->ai_family)
- {
-#ifdef IPv4
- case AF_INET:
- ((struct sockaddr_in *) ai->ai_addr)->sin_port = port;
- nfound++;
- break;
-#endif
-#ifdef IPv6
- case AF_INET6:
- ((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port;
- nfound++;
- break;
-#endif
- }
- }
- return (nfound);
-}
-
-/* end ga_port */
-
-/*
- * This function handles the service string.
- */
-
-/* include ga_serv */
-static int
-ga_serv (struct addrinfo *aihead, const struct addrinfo *hintsp,
- const char *serv)
-{
- int port, rc, nfound;
- struct servent *sptr;
-
- nfound = 0;
- if (isdigit (serv[0]))
- { /* check for port number string first */
- port = htons (atoi (serv));
- if (hintsp->ai_socktype)
- {
- /* 4caller specifies socket type */
- if ((rc = ga_port (aihead, port, hintsp->ai_socktype)) < 0)
- return (EAI_MEMORY);
- nfound += rc;
- }
- else
- {
- /* 4caller does not specify socket type */
- if ((rc = ga_port (aihead, port, SOCK_STREAM)) < 0)
- return (EAI_MEMORY);
- nfound += rc;
- if ((rc = ga_port (aihead, port, SOCK_DGRAM)) < 0)
- return (EAI_MEMORY);
- nfound += rc;
- }
- }
- else
- {
- /* 4try service name, TCP then UDP */
- if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_STREAM)
- {
- if ((sptr = cygwin_getservbyname (serv, "tcp")) != NULL)
- {
- if ((rc = ga_port (aihead, sptr->s_port, SOCK_STREAM)) < 0)
- return (EAI_MEMORY);
- nfound += rc;
- }
- }
- if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_DGRAM)
- {
- if ((sptr = cygwin_getservbyname (serv, "udp")) != NULL)
- {
- if ((rc = ga_port (aihead, sptr->s_port, SOCK_DGRAM)) < 0)
- return (EAI_MEMORY);
- nfound += rc;
- }
- }
- }
-
- if (nfound == 0)
- {
- if (hintsp->ai_socktype == 0)
- return (EAI_NONAME); /* all calls to getservbyname() failed */
- else
- return (EAI_SERVICE); /* service not supported for socket type */
- }
- return (0);
-}
-
-/* end ga_serv */
-
-#ifdef UNIXdomain
-/* include ga_unix */
-static int
-ga_unix (const char *path, struct addrinfo *hintsp, struct addrinfo **result)
-{
- int rc;
- struct addrinfo *aihead, **aipnext;
-
- aihead = NULL;
- aipnext = &aihead;
-
- if (hintsp->ai_family != AF_UNSPEC && hintsp->ai_family != AF_LOCAL)
- return (EAI_ADDRFAMILY);
-
- if (hintsp->ai_socktype == 0)
- {
- /* 4no socket type specified: return stream then dgram */
- hintsp->ai_socktype = SOCK_STREAM;
- if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0)
- return (rc);
- hintsp->ai_socktype = SOCK_DGRAM;
- }
-
- if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0)
- return (rc);
-
- if (hintsp->ai_flags & AI_CANONNAME)
- {
- struct utsname myname;
-
- if (uname (&myname) < 0)
- return (EAI_SYSTEM);
- if ((aihead->ai_canonname = strdup (myname.nodename)) == NULL)
- return (EAI_MEMORY);
- }
-
- *result = aihead; /* pointer to first structure in linked list */
- return (0);
-}
-
-/* end ga_unix */
-#endif /* UNIXdomain */
-
-/* include gn_ipv46 */
-static int
-gn_ipv46 (char *host, size_t hostlen, char *serv, size_t servlen,
- void *aptr, size_t alen, int family, int port, int flags)
-{
- char *ptr;
- struct hostent *hptr;
- struct servent *sptr;
-
- if (host && hostlen > 0)
- {
- if (flags & NI_NUMERICHOST)
- {
- if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL)
- return (1);
- }
- else
- {
- hptr = cygwin_gethostbyaddr ((const char *) aptr, alen, family);
- if (hptr != NULL && hptr->h_name != NULL)
- {
- if (flags & NI_NOFQDN)
- {
- if ((ptr = strchr (hptr->h_name, '.')) != NULL)
- *ptr = 0; /* overwrite first dot */
- }
- //snprintf (host, hostlen, "%s", hptr->h_name);
- *host = '\0';
- strncat (host, hptr->h_name, hostlen - 1);
- }
- else
- {
- if (flags & NI_NAMEREQD)
- return (1);
- if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL)
- return (1);
- }
- }
- }
-
- if (serv && servlen > 0)
- {
- if (flags & NI_NUMERICSERV)
- {
- //snprintf (serv, servlen, "%d", ntohs (port));
- char buf[32];
- __small_sprintf (buf, "%d", ntohs (port));
- *serv = '\0';
- strncat (serv, buf, servlen - 1);
- }
- else
- {
- sptr = cygwin_getservbyport (port, (flags & NI_DGRAM) ? "udp" : NULL);
- if (sptr != NULL && sptr->s_name != NULL)
- {
- //snprintf (serv, servlen, "%s", sptr->s_name);
- *serv = '\0';
- strncat (serv, sptr->s_name, servlen - 1);
- }
- else
- {
- //snprintf (serv, servlen, "%d", ntohs (port));
- char buf[32];
- __small_sprintf (buf, "%d", ntohs (port));
- *serv = '\0';
- strncat (serv, buf, servlen - 1);
- }
- }
- }
- return (0);
-}
-
-/* end gn_ipv46 */
-
-/* include freeaddrinfo */
-void
-ipv4_freeaddrinfo (struct addrinfo *aihead)
-{
- struct addrinfo *ai, *ainext;
-
- for (ai = aihead; ai != NULL; ai = ainext)
- {
- if (ai->ai_addr != NULL)
- free (ai->ai_addr); /* socket address structure */
-
- if (ai->ai_canonname != NULL)
- free (ai->ai_canonname);
-
- ainext = ai->ai_next; /* can't fetch ai_next after free() */
- free (ai); /* the addrinfo{} itself */
- }
-}
-
-/* end freeaddrinfo */
-
-/* include ga1 */
-
-int
-ipv4_getaddrinfo (const char *hostname, const char *servname,
- const struct addrinfo *hintsp, struct addrinfo **result)
-{
- int rc, error, nsearch;
- char **ap, *canon;
- struct hostent *hptr;
- struct search search[3], *sptr;
- struct addrinfo hints, *aihead, **aipnext;
-
- /*
- * If we encounter an error we want to free() any dynamic memory
- * that we've allocated. This is our hack to simplify the code.
- */
-#define error(e) { error = (e); goto bad; }
-
- aihead = NULL; /* initialize automatic variables */
- aipnext = &aihead;
- canon = NULL;
-
- if (hintsp == NULL)
- {
- bzero (&hints, sizeof (hints));
- hints.ai_family = AF_UNSPEC;
- }
- else
- hints = *hintsp; /* struct copy */
-
- /* 4first some basic error checking */
- if ((rc = ga_echeck (hostname, servname, hints.ai_flags, hints.ai_family,
- hints.ai_socktype, hints.ai_protocol)) != 0)
- error (rc);
-
-#ifdef UNIXdomain
- /* 4special case Unix domain first */
- if (hostname != NULL &&
- (strcmp (hostname, "/local") == 0 || strcmp (hostname, "/unix") == 0) &&
- (servname != NULL && servname[0] == '/'))
- return (ga_unix (servname, &hints, result));
-#endif
-/* end ga1 */
-
-/* include ga3 */
- /* 4remainder of function for IPv4/IPv6 */
- nsearch = ga_nsearch (hostname, &hints, &search[0]);
- if (nsearch == -1)
- error (EAI_FAMILY);
- for (sptr = &search[0]; sptr < &search[nsearch]; sptr++)
- {
-#ifdef IPv4
- /* 4check for an IPv4 dotted-decimal string */
- if (isdigit (sptr->host[0]))
- {
- struct in_addr inaddr;
-
- if (inet_pton4 (sptr->host, (u_char *) &inaddr) == 1)
- {
- if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
- error (EAI_ADDRFAMILY);
- if (sptr->family != AF_INET)
- continue; /* ignore */
- rc = ga_aistruct (&aipnext, &hints, &inaddr, AF_INET);
- if (rc != 0)
- error (rc);
- continue;
- }
- }
-#endif
-
-#ifdef IPv6
- /* 4check for an IPv6 hex string */
- if ((isxdigit (sptr->host[0]) || sptr->host[0] == ':') &&
- (strchr (sptr->host, ':') != NULL))
- {
- struct in6_addr in6addr;
-
- if (inet_pton6 (sptr->host, &in6addr) == 1)
- {
- if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
- error (EAI_ADDRFAMILY);
- if (sptr->family != AF_INET6)
- continue; /* ignore */
- rc = ga_aistruct (&aipnext, &hints, &in6addr, AF_INET6);
- if (rc != 0)
- error (rc);
- continue;
- }
- }
-#endif
-/* end ga3 */
-/* include ga4 */
-#ifdef IPv6
- /* 4remainder of for() to look up hostname */
- if ((_res.options & RES_INIT) == 0)
- res_init (); /* need this to set _res.options */
-#endif
-
- if (nsearch == 2)
- {
-#ifdef IPv6
- _res.options &= ~RES_USE_INET6;
-#endif
- hptr = gethostbyname2 (sptr->host, sptr->family);
- }
- else
- {
-#ifdef IPv6
- if (sptr->family == AF_INET6)
- _res.options |= RES_USE_INET6;
- else
- _res.options &= ~RES_USE_INET6;
-#endif
- hptr = gethostbyname (sptr->host);
- }
- if (hptr == NULL)
- {
- if (nsearch == 2)
- continue; /* failure OK if multiple searches */
-
- switch (h_errno)
- {
- case HOST_NOT_FOUND:
- error (EAI_NONAME);
- case TRY_AGAIN:
- error (EAI_AGAIN);
- case NO_RECOVERY:
- error (EAI_FAIL);
- case NO_DATA:
- error (EAI_NODATA);
- default:
- error (EAI_NONAME);
- }
- }
-
- /* 4check for address family mismatch if one specified */
- if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
- error (EAI_ADDRFAMILY);
-
- /* 4save canonical name first time */
- if (hostname != NULL && hostname[0] != '\0' &&
- (hints.ai_flags & AI_CANONNAME) && canon == NULL)
- {
- if ((canon = strdup (hptr->h_name)) == NULL)
- error (EAI_MEMORY);
- }
-
- /* 4create one addrinfo{} for each returned address */
- for (ap = hptr->h_addr_list; *ap != NULL; ap++)
- {
- rc = ga_aistruct (&aipnext, &hints, *ap, hptr->h_addrtype);
- if (rc != 0)
- error (rc);
- }
- }
- if (aihead == NULL)
- error (EAI_NONAME); /* nothing found */
-/* end ga4 */
-
-/* include ga5 */
- /* 4return canonical name */
- if (hostname != NULL && hostname[0] != '\0' &&
- hints.ai_flags & AI_CANONNAME)
- {
- if (canon != NULL)
- aihead->ai_canonname = canon; /* strdup'ed earlier */
- else
- {
- if ((aihead->ai_canonname = strdup (search[0].host)) == NULL)
- error (EAI_MEMORY);
- }
- }
-
- /* 4now process the service name */
- if (servname != NULL && servname[0] != '\0')
- {
- if ((rc = ga_serv (aihead, &hints, servname)) != 0)
- error (rc);
- }
-
- *result = aihead; /* pointer to first structure in linked list */
- return (0);
-
-bad:
- ipv4_freeaddrinfo (aihead); /* free any alloc'ed memory */
- return (error);
-}
-
-/* end ga5 */
-
-/* include getnameinfo */
-int
-ipv4_getnameinfo (const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
-{
-
- switch (sa->sa_family)
- {
-#ifdef IPv4
- case AF_INET:
- {
- struct sockaddr_in *sain = (struct sockaddr_in *) sa;
-
- return (gn_ipv46 (host, hostlen, serv, servlen,
- &sain->sin_addr, sizeof (struct in_addr),
- AF_INET, sain->sin_port, flags));
- }
-#endif
-
-#ifdef IPv6
- case AF_INET6:
- {
- struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa;
-
- return (gn_ipv46 (host, hostlen, serv, servlen,
- &sain->sin6_addr, sizeof (struct in6_addr),
- AF_INET6, sain->sin6_port, flags));
- }
-#endif
-
-#ifdef UNIXdomain
- case AF_LOCAL:
- {
- struct sockaddr_un *un = (struct sockaddr_un *) sa;
-
- if (hostlen > 0)
- snprintf (host, hostlen, "%s", "/local");
- if (servlen > 0)
- snprintf (serv, servlen, "%s", un->sun_path);
- return (0);
- }
-#endif
-
- default:
- return (1);
- }
-}
-
-/* end getnameinfo */
-
-/* Start of cygwin specific wrappers around the gai functions. */
-
-struct gai_errmap_t
-{
- int w32_errval;
- const char *errtxt;
-};
-
-static gai_errmap_t gai_errmap[] =
-{
- {0, "Success"},
- {0, "Address family for hostname not supported"},
- {WSATRY_AGAIN, "Temporary failure in name resolution"},
- {WSAEINVAL, "Invalid value for ai_flags"},
- {WSANO_RECOVERY, "Non-recoverable failure in name resolution"},
- {WSAEAFNOSUPPORT, "ai_family not supported"},
- {WSA_NOT_ENOUGH_MEMORY, "Memory allocation failure"},
- {WSANO_DATA, "No address associated with hostname"},
- {WSAHOST_NOT_FOUND, "hostname nor servname provided, or not known"},
- {WSATYPE_NOT_FOUND, "servname not supported for ai_socktype"},
- {WSAESOCKTNOSUPPORT, "ai_socktype not supported"},
- {0, "System error returned in errno"},
- {0, "Invalid value for hints"},
- {0, "Resolved protocol is unknown"}
-};
-
-extern "C" const char *
-cygwin_gai_strerror (int err)
-{
- if (err >= 0 && err < EAI_MAX)
- return gai_errmap[err].errtxt;
- return "Unknown error";
-}
-
-static int
-w32_to_gai_err (int w32_err)
-{
- if (w32_err >= WSABASEERR)
- for (int i = 0; i < EAI_MAX; ++i)
- if (gai_errmap[i].w32_errval == w32_err)
- return i;
- return w32_err;
-}
-
-/* We can't use autoload here because we don't know where the functions
- are loaded from. On Win2K, the functions are available in the
- ipv6 technology preview lib called wship6.dll, in XP and above they
- are implemented in ws2_32.dll. For older systems we use the ipv4-only
- version above. */
-
-static void (WINAPI *freeaddrinfo)(const struct addrinfo *);
-static int (WINAPI *getaddrinfo)(const char *, const char *,
- const struct addrinfo *,
- struct addrinfo **);
-static int (WINAPI *getnameinfo)(const struct sockaddr *, socklen_t,
- char *, size_t, char *, size_t, int);
-static bool
-get_ipv6_funcs (HMODULE lib)
-{
- return ((freeaddrinfo = (void (WINAPI *)(const struct addrinfo *))
- GetProcAddress (lib, "freeaddrinfo"))
- && (getaddrinfo = (int (WINAPI *)(const char *, const char *,
- const struct addrinfo *,
- struct addrinfo **))
- GetProcAddress (lib, "getaddrinfo"))
- && (getnameinfo = (int (WINAPI *)(const struct sockaddr *,
- socklen_t, char *, size_t,
- char *, size_t, int))
- GetProcAddress (lib, "getnameinfo")));
-}
-
-static NO_COPY muto load_ipv6_guard;
-static bool ipv6_inited = false;
-#define load_ipv6() if (!ipv6_inited) load_ipv6_funcs ();
-
-static void
-load_ipv6_funcs ()
-{
-
- char lib_name[CYG_MAX_PATH];
- size_t len;
- HMODULE lib;
-
- load_ipv6_guard.init ("klog_guard")->acquire ();
- if (ipv6_inited)
- goto out;
- WSAGetLastError (); /* Kludge. Enforce WSAStartup call. */
- if (GetSystemDirectory (lib_name, CYG_MAX_PATH))
- {
- len = strlen (lib_name);
- strcpy (lib_name + len, "\\ws2_32.dll");
- if ((lib = LoadLibrary (lib_name)))
- {
- if (get_ipv6_funcs (lib))
- goto out;
- FreeLibrary (lib);
- }
- strcpy (lib_name + len, "\\wship6.dll");
- if ((lib = LoadLibrary (lib_name)))
- {
- if (get_ipv6_funcs (lib))
- goto out;
- FreeLibrary (lib);
- }
- freeaddrinfo = NULL;
- getaddrinfo = NULL;
- getnameinfo = NULL;
- }
-out:
- ipv6_inited = true;
- load_ipv6_guard.release ();
-}
-
-extern "C" void
-cygwin_freeaddrinfo (struct addrinfo *addr)
-{
- myfault efault;
- if (efault.faulted (EFAULT))
- return;
- load_ipv6 ();
- if (freeaddrinfo)
- freeaddrinfo (addr);
- else
- ipv4_freeaddrinfo (addr);
-}
-
-extern "C" int
-cygwin_getaddrinfo (const char *hostname, const char *servname,
- const struct addrinfo *hints, struct addrinfo **res)
-{
- myfault efault;
- if (efault.faulted (EFAULT))
- return EAI_SYSTEM;
- load_ipv6 ();
- if (getaddrinfo)
- return w32_to_gai_err (getaddrinfo (hostname, servname, hints, res));
- return ipv4_getaddrinfo (hostname, servname, hints, res);
-}
-
-extern "C" int
-cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen, char *serv,
- size_t servlen, int flags)
-{
- myfault efault;
- if (efault.faulted (EFAULT))
- return EAI_SYSTEM;
- load_ipv6 ();
- if (getnameinfo)
- {
- /* When the incoming port number is set to 0, Winsock's getnameinfo
- returns with error WSANO_DATA instead of simply ignoring the port.
- To avoid this strange behaviour, we check manually, if the port number
- is 0. If so, set the NI_NUMERICSERV flag to avoid this problem. */
- switch (sa->sa_family)
- {
- case AF_INET:
- if (((struct sockaddr_in *) sa)->sin_port == 0)
- flags |= NI_NUMERICSERV;
- break;
- case AF_INET6:
- if (((struct sockaddr_in6 *) sa)->sin6_port == 0)
- flags |= NI_NUMERICSERV;
- break;
- }
- int ret = w32_to_gai_err (getnameinfo (sa, salen, host, hostlen, serv,
- servlen, flags));
- if (ret)
- set_winsock_errno ();
- return ret;
- }
- return ipv4_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags);
-}
-