diff options
Diffstat (limited to 'winsup/cygwin/net.cc')
-rw-r--r-- | winsup/cygwin/net.cc | 1380 |
1 files changed, 593 insertions, 787 deletions
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index c310c78b3..32b4b2ef1 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -1,6 +1,6 @@ /* net.cc: network-related routines. - Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. This file is part of Cygwin. @@ -21,7 +21,6 @@ details. */ #include <stdlib.h> #include <unistd.h> #include <netdb.h> -#include <fcntl.h> #define USE_SYS_TYPES_FD_SET #include <winsock2.h> #include "cygerrno.h" @@ -30,10 +29,10 @@ details. */ #include "path.h" #include "dtable.h" #include "cygheap.h" -#include "sync.h" #include "sigproc.h" #include "pinfo.h" #include "registry.h" +#include "wsock_event.h" extern "C" { int h_errno; @@ -46,23 +45,6 @@ int __stdcall rresvport (int *); int sscanf (const char *, const char *, ...); } /* End of "C" section */ -class wsock_event -{ - WSAEVENT event; - WSAOVERLAPPED ovr; -public: - wsock_event () : event (NULL) {}; - ~wsock_event () - { - if (event) - WSACloseEvent (event); - event = NULL; - }; - - LPWSAOVERLAPPED prepare (); - int wait (int socket, LPDWORD flags); -}; - LPWSAOVERLAPPED wsock_event::prepare () { @@ -88,18 +70,18 @@ wsock_event::wait (int socket, LPDWORD flags) int ret = -1; WSAEVENT ev[2] = { event, signal_arrived }; - switch (WSAWaitForMultipleEvents(2, ev, FALSE, WSA_INFINITE, FALSE)) + switch (WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE, FALSE)) { case WSA_WAIT_EVENT_0: DWORD len; - if (WSAGetOverlappedResult(socket, &ovr, &len, FALSE, flags)) + if (WSAGetOverlappedResult (socket, &ovr, &len, FALSE, flags)) ret = (int) len; break; case WSA_WAIT_EVENT_0 + 1: if (!CancelIo ((HANDLE)socket)) { debug_printf ("CancelIo() %E, fallback to blocking io"); - WSAGetOverlappedResult(socket, &ovr, &len, TRUE, flags); + WSAGetOverlappedResult (socket, &ovr, &len, TRUE, flags); } else WSASetLastError (WSAEINTR); @@ -118,23 +100,30 @@ wsock_event::wait (int socket, LPDWORD flags) WSADATA wsadata; /* Cygwin internal */ +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; +} + +/* Cygwin internal */ static SOCKET __stdcall set_socket_inheritance (SOCKET sock) { - if (wincap.has_set_handle_information ()) - (void) SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + SOCKET osock = sock; + if (!DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &sock, + 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) + system_printf ("DuplicateHandle failed %E"); else - { - SOCKET newsock; - if (!DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &newsock, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - small_printf ("DuplicateHandle failed %E"); - else - { - closesocket (sock); - sock = newsock; - } - } + debug_printf ("DuplicateHandle succeeded osock %p, sock %p", osock, sock); return sock; } @@ -203,6 +192,8 @@ cygwin_inet_ntoa (struct in_addr in) extern "C" unsigned long cygwin_inet_addr (const char *cp) { + if (check_null_str_errno (cp)) + return INADDR_NONE; unsigned long res = inet_addr (cp); return res; } @@ -213,6 +204,9 @@ cygwin_inet_addr (const char *cp) extern "C" int cygwin_inet_aton (const char *cp, struct in_addr *inp) { + if (check_null_str_errno (cp) || check_null_invalid_struct_errno (inp)) + return 0; + unsigned long res = inet_addr (cp); if (res == INADDR_NONE && strcmp (cp, "255.255.255.255")) return 0; @@ -227,6 +221,8 @@ extern "C" unsigned int WINAPI inet_network (const char *); extern "C" unsigned int cygwin_inet_network (const char *cp) { + if (check_null_str_errno (cp)) + return INADDR_NONE; unsigned int res = inet_network (cp); return res; } @@ -240,7 +236,6 @@ 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; @@ -263,7 +258,6 @@ 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) @@ -356,7 +350,7 @@ __set_winsock_errno (const char *fn, int ln) * Since the member `s' isn't used for debug output we can use it * for the error text returned by herror and hstrerror. */ -const static NO_COPY struct tl host_errmap[] = +static NO_COPY struct tl host_errmap[] = { {WSAHOST_NOT_FOUND, "Unknown host", HOST_NOT_FOUND}, {WSATRY_AGAIN, "Host name lookup failure", TRY_AGAIN}, @@ -423,9 +417,9 @@ dup_addr_list (char **src, unsigned int size) return NULL; while (cnt-- > 0) { - if (!(dst[cnt] = (char *) malloc(size))) + if (!(dst[cnt] = (char *) malloc (size))) return NULL; - memcpy(dst[cnt], src[cnt], size); + memcpy (dst[cnt], src[cnt], size); } return dst; } @@ -481,6 +475,8 @@ out: extern "C" struct protoent * cygwin_getprotobyname (const char *p) { + if (check_null_str_errno (p)) + return NULL; free_protoent_ptr (protoent_buf); protoent_buf = dup_protoent_ptr (getprotobyname (p)); if (!protoent_buf) @@ -504,14 +500,23 @@ cygwin_getprotobynumber (int number) } fhandler_socket * -fdsock (int fd, const char *name, SOCKET soc) +fdsock (int& fd, const char *name, SOCKET soc) { - if (wsadata.wVersion < 512) /* < Winsock 2.0 */ + if (!winsock2_active) soc = set_socket_inheritance (soc); + else if (wincap.has_set_handle_information ()) + { + /* NT systems apparently set sockets to inheritable by default */ + SetHandleInformation ((HANDLE)soc, HANDLE_FLAG_INHERIT, 0); + debug_printf ("reset socket inheritance since winsock2_active %d", winsock2_active); + } + else + debug_printf ("not setting socket inheritance since winsock2_active %d", winsock2_active); fhandler_socket *fh = (fhandler_socket *) cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name); fh->set_io_handle ((HANDLE) soc); - fh->set_flags (O_RDWR); - cygheap->fdtab.inc_need_fixup_before (); + fh->set_flags (O_RDWR | O_BINARY); + fh->set_r_no_interrupt (winsock2_active); + debug_printf ("fd %d, name '%s', soc %p", fd, name, soc); return fh; } @@ -520,19 +525,16 @@ extern "C" int cygwin_socket (int af, int type, int protocol) { int res = -1; - SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socket"); - - SOCKET soc; + SOCKET soc = 0; + fhandler_socket* fh = NULL; - int fd = cygheap->fdtab.find_unused_handle (); + cygheap_fdnew fd; - if (fd < 0) - set_errno (EMFILE); - else + if (fd >= 0) { debug_printf ("socket (%d, %d, %d)", af, type, protocol); - soc = socket (AF_INET, type, af == AF_UNIX ? 0 : protocol); + soc = socket (AF_INET, type, af == AF_LOCAL ? 0 : protocol); if (soc == INVALID_SOCKET) { @@ -546,222 +548,118 @@ cygwin_socket (int af, int type, int protocol) else name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket"); - fdsock (fd, name, soc)->set_addr_family (af); + fh = fdsock (fd, name, soc); + if (fh) + { + fh->set_addr_family (af); + fh->set_socket_type (type); + } res = fd; } done: syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol); - ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socket"); return res; } -/* cygwin internal: map sockaddr into internet domain address */ - -static int get_inet_addr (const struct sockaddr *in, int inlen, - struct sockaddr_in *out, int *outlen, int* secret = 0) -{ - int secret_buf [4]; - int* secret_ptr = (secret ? : secret_buf); - - if (in->sa_family == AF_INET) - { - *out = * (sockaddr_in *)in; - *outlen = inlen; - return 1; - } - else if (in->sa_family == AF_UNIX) - { - int fd = _open (in->sa_data, O_RDONLY); - if (fd == -1) - return 0; - - int ret = 0; - char buf[128]; - memset (buf, 0, sizeof buf); - if (read (fd, buf, sizeof buf) != -1) - { - sockaddr_in sin; - sin.sin_family = AF_INET; - sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x", - &sin.sin_port, - secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3); - sin.sin_port = htons (sin.sin_port); - sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - *out = sin; - *outlen = sizeof sin; - ret = 1; - } - _close (fd); - return ret; - } - else - { - set_errno (EAFNOSUPPORT); - return 0; - } -} - /* exported as sendto: standards? */ extern "C" int -cygwin_sendto (int fd, - const void *buf, - int len, - unsigned int flags, - const struct sockaddr *to, - int tolen) +cygwin_sendto (int fd, const void *buf, int len, int flags, + const struct sockaddr *to, int tolen) { int res; - wsock_event wsock_evt; - LPWSAOVERLAPPED ovr; - fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; - sockaddr_in sin; sigframe thisframe (mainthread); - if (get_inet_addr (to, tolen, &sin, &tolen) == 0) - return -1; + fhandler_socket *fh = get (fd); - if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ())) - { - debug_printf ("Fallback to winsock 1 sendto call"); - if ((res = sendto (h->get_socket (), (const char *) buf, len, flags, - to, tolen)) == SOCKET_ERROR) - { - set_winsock_errno (); - res = -1; - } - } - else - { - WSABUF wsabuf = { len, (char *) buf }; - DWORD ret = 0; - if (WSASendTo (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags, - to, tolen, ovr, NULL) != SOCKET_ERROR) - res = ret; - else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) - { - set_winsock_errno (); - res = -1; - } - else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) - set_winsock_errno (); - } + if ((len && __check_invalid_read_ptr_errno (buf, (unsigned) len)) + || (to &&__check_invalid_read_ptr_errno (to, tolen)) + || !fh) + res = -1; + else if ((res = len) != 0) + res = fh->sendto (buf, len, flags, to, tolen); - syscall_printf ("%d = sendto (%d, %x, %x, %x)", res, fd, buf, len, flags); + 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, - char *buf, - int len, - int flags, - struct sockaddr *from, - int *fromlen) +cygwin_recvfrom (int fd, void *buf, int len, int flags, + struct sockaddr *from, int *fromlen) { int res; - wsock_event wsock_evt; - LPWSAOVERLAPPED ovr; - fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; sigframe thisframe (mainthread); - if (h->is_nonblocking () ||!(ovr = wsock_evt.prepare ())) - { - debug_printf ("Fallback to winsock 1 recvfrom call"); - if ((res = recvfrom (h->get_socket (), buf, len, flags, from, fromlen)) - == SOCKET_ERROR) - { - set_winsock_errno (); - res = -1; - } - } - else - { - WSABUF wsabuf = { len, (char *) buf }; - DWORD ret = 0; - if (WSARecvFrom (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags, - from, fromlen, ovr, NULL) != SOCKET_ERROR) - res = ret; - else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) - { - set_winsock_errno (); - res = -1; - } - else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) - set_winsock_errno (); - } + fhandler_socket *fh = get (fd); - syscall_printf ("%d = recvfrom (%d, %x, %x, %x)", res, fd, buf, len, flags); + if ((len && __check_null_invalid_struct_errno (buf, (unsigned) len)) + || (from + && (check_null_invalid_struct_errno (fromlen) + ||__check_null_invalid_struct_errno (from, (unsigned) *fromlen))) + || !fh) + res = -1; + else if ((res = len) != 0) + res = fh->recvfrom (buf, len, flags, from, fromlen); - return res; -} + syscall_printf ("%d = recvfrom (%d, %p, %d, %x, %p, %p)", + res, fd, buf, len, flags, from, fromlen); -/* Cygwin internal */ -fhandler_socket * -get (int fd) -{ - if (cygheap->fdtab.not_open (fd)) - { - set_errno (EINVAL); - return 0; - } - - return cygheap->fdtab[fd]->is_socket (); + return res; } /* exported as setsockopt: standards? */ extern "C" int -cygwin_setsockopt (int fd, - int level, - int optname, - const void *optval, - int optlen) +cygwin_setsockopt (int fd, int level, int optname, const void *optval, + int optlen) { - fhandler_socket *h = get (fd); - int res = -1; + int res; + fhandler_socket *fh = get (fd); const char *name = "error"; - if (h) + /* For the following debug_printf */ + switch (optname) { - /* For the following debug_printf */ - switch (optname) - { - case SO_DEBUG: - name="SO_DEBUG"; - break; - case SO_ACCEPTCONN: - name="SO_ACCEPTCONN"; - break; - case SO_REUSEADDR: - name="SO_REUSEADDR"; - break; - case SO_KEEPALIVE: - name="SO_KEEPALIVE"; - break; - case SO_DONTROUTE: - name="SO_DONTROUTE"; - break; - case SO_BROADCAST: - name="SO_BROADCAST"; - break; - case SO_USELOOPBACK: - name="SO_USELOOPBACK"; - break; - case SO_LINGER: - name="SO_LINGER"; - break; - case SO_OOBINLINE: - name="SO_OOBINLINE"; - break; - case SO_ERROR: - name="SO_ERROR"; - break; - } + case SO_DEBUG: + name="SO_DEBUG"; + break; + case SO_ACCEPTCONN: + name="SO_ACCEPTCONN"; + break; + case SO_REUSEADDR: + name="SO_REUSEADDR"; + break; + case SO_KEEPALIVE: + name="SO_KEEPALIVE"; + break; + case SO_DONTROUTE: + name="SO_DONTROUTE"; + break; + case SO_BROADCAST: + name="SO_BROADCAST"; + break; + case SO_USELOOPBACK: + name="SO_USELOOPBACK"; + break; + case SO_LINGER: + name="SO_LINGER"; + break; + case SO_OOBINLINE: + name="SO_OOBINLINE"; + break; + case SO_ERROR: + name="SO_ERROR"; + break; + } - res = setsockopt (h->get_socket (), level, optname, - (const char *) optval, optlen); + if ((optval && __check_invalid_read_ptr_errno (optval, optlen)) || !fh) + res = -1; + else + { + res = setsockopt (fh->get_socket (), level, optname, + (const char *) optval, optlen); if (optlen == 4) syscall_printf ("setsockopt optval=%x", *(long *) optval); @@ -770,61 +668,63 @@ cygwin_setsockopt (int fd, set_winsock_errno (); } - syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %x, %d)", + syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %p, %d)", res, fd, level, optname, name, optval, optlen); return res; } /* exported as getsockopt: standards? */ extern "C" int -cygwin_getsockopt (int fd, - int level, - int optname, - void *optval, - int *optlen) +cygwin_getsockopt (int fd, int level, int optname, void *optval, int *optlen) { - fhandler_socket *h = get (fd); - int res = -1; + int res; + fhandler_socket *fh = get (fd); const char *name = "error"; - if (h) + + /* For the following debug_printf */ + switch (optname) { - /* For the following debug_printf */ - switch (optname) - { - case SO_DEBUG: - name="SO_DEBUG"; - break; - case SO_ACCEPTCONN: - name="SO_ACCEPTCONN"; - break; - case SO_REUSEADDR: - name="SO_REUSEADDR"; - break; - case SO_KEEPALIVE: - name="SO_KEEPALIVE"; - break; - case SO_DONTROUTE: - name="SO_DONTROUTE"; - break; - case SO_BROADCAST: - name="SO_BROADCAST"; - break; - case SO_USELOOPBACK: - name="SO_USELOOPBACK"; - break; - case SO_LINGER: - name="SO_LINGER"; - break; - case SO_OOBINLINE: - name="SO_OOBINLINE"; - break; - case SO_ERROR: - name="SO_ERROR"; - break; - } + case SO_DEBUG: + name="SO_DEBUG"; + break; + case SO_ACCEPTCONN: + name="SO_ACCEPTCONN"; + break; + case SO_REUSEADDR: + name="SO_REUSEADDR"; + break; + case SO_KEEPALIVE: + name="SO_KEEPALIVE"; + break; + case SO_DONTROUTE: + name="SO_DONTROUTE"; + break; + case SO_BROADCAST: + name="SO_BROADCAST"; + break; + case SO_USELOOPBACK: + name="SO_USELOOPBACK"; + break; + case SO_LINGER: + name="SO_LINGER"; + break; + case SO_OOBINLINE: + name="SO_OOBINLINE"; + break; + case SO_ERROR: + name="SO_ERROR"; + break; + } - res = getsockopt (h->get_socket (), level, optname, - (char *) optval, (int *) optlen); + if ((optval + && (check_null_invalid_struct_errno (optlen) + || __check_null_invalid_struct_errno (optval, (unsigned) *optlen))) + || !fh) + res = -1; + else + { + res = getsockopt (fh->get_socket (), level, optname, (char *) optval, + (int *) optlen); if (optname == SO_ERROR) { @@ -836,83 +736,27 @@ cygwin_getsockopt (int fd, set_winsock_errno (); } - syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %x, %d)", + syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %p, %p)", res, fd, level, optname, name, optval, optlen); return res; } /* exported as connect: standards? */ extern "C" int -cygwin_connect (int fd, - const struct sockaddr *name, - int namelen) +cygwin_connect (int fd, const struct sockaddr *name, int namelen) { int res; - BOOL secret_check_failed = FALSE; - BOOL in_progress = FALSE; - fhandler_socket *sock = get (fd); - sockaddr_in sin; - int secret [4]; sigframe thisframe (mainthread); - if (get_inet_addr (name, namelen, &sin, &namelen, secret) == 0) - return -1; + fhandler_socket *fh = get (fd); - if (!sock) - { - res = -1; - } + if (__check_invalid_read_ptr_errno (name, namelen) || !fh) + res = -1; else - { - res = connect (sock->get_socket (), (sockaddr *) &sin, namelen); - if (res) - { - /* Special handling for connect to return the correct error code - when called on a non-blocking socket. */ - if (sock->is_nonblocking ()) - { - DWORD err = WSAGetLastError (); - if (err == WSAEWOULDBLOCK || err == WSAEALREADY) - { - WSASetLastError (WSAEINPROGRESS); - in_progress = TRUE; - } - else if (err == WSAEINVAL) - WSASetLastError (WSAEISCONN); - } - set_winsock_errno (); - } - if (sock->get_addr_family () == AF_UNIX) - { - if (!res || in_progress) - { - if (!sock->create_secret_event (secret)) - { - secret_check_failed = TRUE; - } - else if (in_progress) - sock->signal_secret_event (); - } + res = fh->connect (name, namelen); - if (!secret_check_failed && !res) - { - if (!sock->check_peer_secret_event (&sin, secret)) - { - debug_printf ( "accept from unauthorized server" ); - secret_check_failed = TRUE; - } - } + syscall_printf ("%d = connect (%d, %p, %d)", res, fd, name, namelen); - if (secret_check_failed) - { - sock->close_secret_event (); - if (res) - closesocket (res); - set_errno (ECONNREFUSED); - res = -1; - } - } - } return res; } @@ -987,6 +831,10 @@ out: extern "C" struct servent * cygwin_getservbyname (const char *name, const char *proto) { + if (check_null_str_errno (name) + || (proto != NULL && check_null_str_errno (proto))) + return NULL; + free_servent_ptr (servent_buf); servent_buf = dup_servent_ptr (getservbyname (name, proto)); if (!servent_buf) @@ -1000,6 +848,9 @@ cygwin_getservbyname (const char *name, const char *proto) extern "C" struct servent * cygwin_getservbyport (int port, const char *proto) { + if (proto != NULL && check_null_str_errno (proto)) + return NULL; + free_servent_ptr (servent_buf); servent_buf = dup_servent_ptr (getservbyport (port, proto)); if (!servent_buf) @@ -1014,6 +865,9 @@ cygwin_gethostname (char *name, size_t len) { int PASCAL win32_gethostname (char*, int); + if (__check_null_invalid_struct_errno (name, len)) + return -1; + if (wsock32_handle == NULL || win32_gethostname (name, len) == SOCKET_ERROR) { @@ -1092,6 +946,9 @@ cygwin_gethostbyname (const char *name) static char *tmp_addr_list[2]; static int a, b, c, d; + if (check_null_str_errno (name)) + return NULL; + if (sscanf (name, "%d.%d.%d.%d", &a, &b, &c, &d) == 4) { /* In case you don't have DNS, at least x.x.x.x still works */ @@ -1100,7 +957,7 @@ cygwin_gethostbyname (const char *name) tmp_addr[1] = b; tmp_addr[2] = c; tmp_addr[3] = d; - tmp_addr_list[0] = (char *)tmp_addr; + tmp_addr_list[0] = (char *) tmp_addr; tmp.h_name = name; tmp.h_aliases = tmp_aliases; tmp.h_addrtype = 2; @@ -1128,6 +985,9 @@ cygwin_gethostbyname (const char *name) extern "C" struct hostent * cygwin_gethostbyaddr (const char *addr, int len, int type) { + if (__check_invalid_read_ptr_errno (addr, len)) + return NULL; + free_hostent_ptr (hostent_buf); hostent_buf = dup_hostent_ptr (gethostbyaddr (addr, len, type)); if (!hostent_buf) @@ -1147,91 +1007,19 @@ cygwin_gethostbyaddr (const char *addr, int len, int type) extern "C" int cygwin_accept (int fd, struct sockaddr *peer, int *len) { - int res = -1; - BOOL secret_check_failed = FALSE; - BOOL in_progress = FALSE; + int res; sigframe thisframe (mainthread); - fhandler_socket *sock = get (fd); - if (sock) - { - /* Allows NULL peer and len parameters. */ - struct sockaddr_in peer_dummy; - int len_dummy; - if (!peer) - peer = (struct sockaddr *) &peer_dummy; - if (!len) - { - len_dummy = sizeof (struct sockaddr_in); - len = &len_dummy; - } - - /* accept on NT fails if len < sizeof (sockaddr_in) - * some programs set len to - * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain - */ - if (len && ((unsigned) *len < sizeof (struct sockaddr_in))) - *len = sizeof (struct sockaddr_in); - - res = accept (sock->get_socket (), peer, len); // can't use a blocking call inside a lock + fhandler_socket *fh = get (fd); - if ((SOCKET) res == (SOCKET) INVALID_SOCKET && - WSAGetLastError () == WSAEWOULDBLOCK) - in_progress = TRUE; - - if (sock->get_addr_family () == AF_UNIX) - { - if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress) - { - if (!sock->create_secret_event ()) - secret_check_failed = TRUE; - else if (in_progress) - sock->signal_secret_event (); - } - - if (!secret_check_failed && - (SOCKET) res != (SOCKET) INVALID_SOCKET) - { - if (!sock->check_peer_secret_event ((struct sockaddr_in*) peer)) - { - debug_printf ("connect from unauthorized client"); - secret_check_failed = TRUE; - } - } - - if (secret_check_failed) - { - sock->close_secret_event (); - if ((SOCKET) res != (SOCKET) INVALID_SOCKET) - closesocket (res); - set_errno (ECONNABORTED); - res = -1; - goto done; - } - } - - SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept"); + if ((peer && (check_null_invalid_struct_errno (len) + || __check_null_invalid_struct_errno (peer, (unsigned) *len))) + || !fh) + res = -1; + else + res = fh->accept (peer, len); - int res_fd = cygheap->fdtab.find_unused_handle (); - if (res_fd == -1) - { - /* FIXME: what is correct errno? */ - set_errno (EMFILE); - goto lock_done; - } - if ((SOCKET) res == (SOCKET) INVALID_SOCKET) - set_winsock_errno (); - else - { - fhandler_socket* res_fh = fdsock (res_fd, sock->get_name (), res); - res_fh->set_addr_family (sock->get_addr_family ()); - res = res_fd; - } - } -lock_done: - ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept"); -done: - syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len); + syscall_printf ("%d = accept (%d, %p, %p)", res, fd, peer, len); return res; } @@ -1239,85 +1027,15 @@ done: extern "C" int cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen) { - int res = -1; - - fhandler_socket *sock = get (fd); - if (sock) - { - if (my_addr->sa_family == AF_UNIX) - { -#define un_addr ((struct sockaddr_un *) my_addr) - struct sockaddr_in sin; - int len = sizeof sin; - int fd; - - if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN) - { - set_errno (ENAMETOOLONG); - goto out; - } - sin.sin_family = AF_INET; - sin.sin_port = 0; - sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (bind (sock->get_socket (), (sockaddr *) &sin, len)) - { - syscall_printf ("AF_UNIX: bind failed %d", get_errno ()); - set_winsock_errno (); - goto out; - } - if (getsockname (sock->get_socket (), (sockaddr *) &sin, &len)) - { - syscall_printf ("AF_UNIX: getsockname failed %d", get_errno ()); - set_winsock_errno (); - goto out; - } - - sin.sin_port = ntohs (sin.sin_port); - debug_printf ("AF_UNIX: socket bound to port %u", sin.sin_port); - - /* bind must fail if file system socket object already exists - so _open () is called with O_EXCL flag. */ - fd = _open (un_addr->sun_path, - O_WRONLY | O_CREAT | O_EXCL | O_BINARY, - 0); - if (fd < 0) - { - if (get_errno () == EEXIST) - set_errno (EADDRINUSE); - goto out; - } - - sock->set_connect_secret (); - - char buf[sizeof (SOCKET_COOKIE) + 80]; - __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port); - sock->get_connect_secret (strchr (buf, '\0')); - len = strlen (buf) + 1; + int res; + fhandler_socket *fh = get (fd); - /* Note that the terminating nul is written. */ - if (_write (fd, buf, len) != len) - { - save_errno here; - _close (fd); - _unlink (un_addr->sun_path); - } - else - { - _close (fd); - chmod (un_addr->sun_path, - (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask); - res = 0; - } -#undef un_addr - } - else if (bind (sock->get_socket (), my_addr, addrlen)) - set_winsock_errno (); - else - res = 0; - } + if (__check_invalid_read_ptr_errno (my_addr, addrlen) || !fh) + res = -1; + else + res = fh->bind (my_addr, addrlen); -out: - syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen); + syscall_printf ("%d = bind (%d, %p, %d)", res, fd, my_addr, addrlen); return res; } @@ -1325,17 +1043,19 @@ out: extern "C" int cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen) { - int res = -1; + int res; + sigframe thisframe (mainthread); - fhandler_socket *sock = get (fd); - if (sock) - { - res = getsockname (sock->get_socket (), addr, namelen); - if (res) - set_winsock_errno (); + fhandler_socket *fh = get (fd); - } - syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen); + if (check_null_invalid_struct_errno (namelen) + || __check_null_invalid_struct_errno (addr, (unsigned) *namelen) + || !fh) + res = -1; + else + res = fh->getsockname (addr, namelen); + + syscall_printf ("%d = getsockname (%d, %p, %p)", res, fd, addr, namelen); return res; } @@ -1343,16 +1063,14 @@ cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen) extern "C" int cygwin_listen (int fd, int backlog) { - int res = -1; + int res; + fhandler_socket *fh = get (fd); + if (!fh) + res = -1; + else + res = fh->listen (backlog); - fhandler_socket *sock = get (fd); - if (sock) - { - res = listen (sock->get_socket (), backlog); - if (res) - set_winsock_errno (); - } syscall_printf ("%d = listen (%d, %d)", res, fd, backlog); return res; } @@ -1361,30 +1079,16 @@ cygwin_listen (int fd, int backlog) extern "C" int cygwin_shutdown (int fd, int how) { - int res = -1; + int res; sigframe thisframe (mainthread); - fhandler_socket *sock = get (fd); - if (sock) - { - res = shutdown (sock->get_socket (), how); - if (res) - set_winsock_errno (); - else - switch (how) - { - case SHUT_RD: - sock->set_shutdown_read (); - break; - case SHUT_WR: - sock->set_shutdown_write (); - break; - case SHUT_RDWR: - sock->set_shutdown_read (); - sock->set_shutdown_write (); - break; - } - } + 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; } @@ -1406,6 +1110,8 @@ cygwin_hstrerror (int err) extern "C" void cygwin_herror (const char *s) { + if (s && check_null_str (s)) + return; if (cygheap->fdtab.not_open (2)) return; @@ -1438,102 +1144,39 @@ cygwin_herror (const char *s) extern "C" int cygwin_getpeername (int fd, struct sockaddr *name, int *len) { - fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; + int res; + sigframe thisframe (mainthread); - debug_printf ("getpeername %d", h->get_socket ()); - int res = getpeername (h->get_socket (), name, len); - if (res) - set_winsock_errno (); + fhandler_socket *fh = get (fd); + + if (check_null_invalid_struct_errno (len) + || __check_null_invalid_struct_errno (name, (unsigned) *len) + || !fh) + res = -1; + else + res = fh->getpeername (name, len); - debug_printf ("%d = getpeername %d", res, h->get_socket ()); + syscall_printf ("%d = getpeername %d", res, (fh ? fh->get_socket () : -1)); return res; } /* exported as recv: standards? */ extern "C" int -cygwin_recv (int fd, void *buf, int len, unsigned int flags) +cygwin_recv (int fd, void *buf, int len, int flags) { - int res; - wsock_event wsock_evt; - LPWSAOVERLAPPED ovr; - fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; - sigframe thisframe (mainthread); - - if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ())) - { - debug_printf ("Fallback to winsock 1 recv call"); - if ((res = recv (h->get_socket (), (char *) buf, len, flags)) - == SOCKET_ERROR) - { - set_winsock_errno (); - res = -1; - } - } - else - { - WSABUF wsabuf = { len, (char *) buf }; - DWORD ret = 0; - if (WSARecv (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags, - ovr, NULL) != SOCKET_ERROR) - res = ret; - else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) - { - set_winsock_errno (); - res = -1; - } - else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) - set_winsock_errno (); - } - - syscall_printf ("%d = recv (%d, %x, %x, %x)", res, fd, buf, len, flags); - - return res; + return cygwin_recvfrom (fd, buf, len, flags, NULL, NULL); } /* exported as send: standards? */ extern "C" int -cygwin_send (int fd, const void *buf, int len, unsigned int flags) +cygwin_send (int fd, const void *buf, int len, int flags) { - int res; - wsock_event wsock_evt; - LPWSAOVERLAPPED ovr; - fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd]; - sigframe thisframe (mainthread); - - if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ())) - { - debug_printf ("Fallback to winsock 1 send call"); - if ((res = send (h->get_socket (), (const char *) buf, len, flags)) - == SOCKET_ERROR) - { - set_winsock_errno (); - res = -1; - } - } - else - { - WSABUF wsabuf = { len, (char *) buf }; - DWORD ret = 0; - if (WSASend (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags, - ovr, NULL) != SOCKET_ERROR) - res = ret; - else if ((res = WSAGetLastError ()) != WSA_IO_PENDING) - { - set_winsock_errno (); - res = -1; - } - else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1) - set_winsock_errno (); - } - - syscall_printf ("%d = send (%d, %x, %d, %x)", res, fd, buf, len, flags); - - return res; + return cygwin_sendto (fd, buf, len, flags, NULL, 0); } /* getdomainname: standards? */ extern "C" int -getdomainname (char *domain, int len) +getdomainname (char *domain, size_t len) { /* * This works for Win95 only if the machine is configured to use MS-TCP. @@ -1542,10 +1185,14 @@ getdomainname (char *domain, int len) * in use and include paths for the Domain name in each ? * Punt for now and assume MS-TCP on Win95. */ + if (__check_null_invalid_struct_errno (domain, len)) + return -1; + reg_key r (HKEY_LOCAL_MACHINE, KEY_READ, (!wincap.is_winnt ()) ? "System" : "SYSTEM", "CurrentControlSet", "Services", - (!wincap.is_winnt ()) ? "MSTCP" : "Tcpip", + (!wincap.is_winnt ()) ? "VxD" : "Tcpip", + (!wincap.is_winnt ()) ? "MSTCP" : "Parameters", NULL); /* FIXME: Are registry keys case sensitive? */ @@ -1569,7 +1216,7 @@ static void get_2k_ifconf (struct ifconf *ifc, int what) { int cnt = 0; - char eth[2] = "/", ppp[2] = "/", slp[2] = "/"; + char eth[2] = "/", ppp[2] = "/", slp[2] = "/", sub[2] = "0", tok[2] = "/"; /* Union maps buffer to correct struct */ struct ifreq *ifr = ifc->ifc_req; @@ -1582,91 +1229,110 @@ get_2k_ifconf (struct ifconf *ifc, int what) struct sockaddr_in *sa = NULL; struct sockaddr *so = NULL; - if (GetIfTable(NULL, &siz_if_table, TRUE) == ERROR_INSUFFICIENT_BUFFER && - GetIpAddrTable(NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER && + if (GetIfTable (NULL, &siz_if_table, TRUE) == ERROR_INSUFFICIENT_BUFFER && + GetIpAddrTable (NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER && (ift = (PMIB_IFTABLE) alloca (siz_if_table)) && (ipt = (PMIB_IPADDRTABLE) alloca (siz_ip_table)) && - !GetIfTable(ift, &siz_if_table, TRUE) && - !GetIpAddrTable(ipt, &siz_ip_table, TRUE)) + !GetIfTable (ift, &siz_if_table, TRUE) && + !GetIpAddrTable (ipt, &siz_ip_table, TRUE)) { + /* Iterate over all known interfaces */ for (if_cnt = 0; if_cnt < ift->dwNumEntries; ++if_cnt) { - switch (ift->table[if_cnt].dwType) - { - case MIB_IF_TYPE_ETHERNET: - ++*eth; - strcpy (ifr->ifr_name, "eth"); - strcat (ifr->ifr_name, eth); - break; - case MIB_IF_TYPE_PPP: - ++*ppp; - strcpy (ifr->ifr_name, "ppp"); - strcat (ifr->ifr_name, ppp); - break; - case MIB_IF_TYPE_SLIP: - ++*slp; - strcpy (ifr->ifr_name, "slp"); - strcat (ifr->ifr_name, slp); - break; - case MIB_IF_TYPE_LOOPBACK: - strcpy (ifr->ifr_name, "lo"); - break; - default: - continue; - } + *sub = '0'; + /* Iterate over all configured IP-addresses */ for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt) - if (ipt->table[ip_cnt].dwIndex == ift->table[if_cnt].dwIndex) - { - 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; + { + /* Does the IP address belong to the interface? */ + if (ipt->table[ip_cnt].dwIndex == ift->table[if_cnt].dwIndex) + { + /* Setup the interface name */ + switch (ift->table[if_cnt].dwType) + { + case MIB_IF_TYPE_TOKENRING: + ++*tok; + strcpy (ifr->ifr_name, "tok"); + strcat (ifr->ifr_name, tok); + break; + case MIB_IF_TYPE_ETHERNET: + if (*sub == '0') + ++*eth; + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + break; + case MIB_IF_TYPE_PPP: + ++*ppp; + strcpy (ifr->ifr_name, "ppp"); + strcat (ifr->ifr_name, ppp); + break; + case MIB_IF_TYPE_SLIP: + ++*slp; + strcpy (ifr->ifr_name, "slp"); + strcat (ifr->ifr_name, slp); + break; + case MIB_IF_TYPE_LOOPBACK: + strcpy (ifr->ifr_name, "lo"); + break; + default: + continue; + } + if (*sub > '0') + { + strcat (ifr->ifr_name, ":"); + strcat (ifr->ifr_name, sub); + } + ++*sub; + /* 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; + /* 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; + 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 >= ift->table[if_cnt].dwPhysAddrLen) - so->sa_data[i] = '\0'; - else - so->sa_data[i] = ift->table[if_cnt].bPhysAddr[i]; - so->sa_family = AF_INET; - break; - case SIOCGIFMETRIC: - ifr->ifr_metric = 1; - break; - case SIOCGIFMTU: - ifr->ifr_mtu = ift->table[if_cnt].dwMtu; - break; - } - ++cnt; - if ((caddr_t) ++ifr > - ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) - goto done; - break; - } + 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 >= ift->table[if_cnt].dwPhysAddrLen) + so->sa_data[i] = '\0'; + else + so->sa_data[i] = ift->table[if_cnt].bPhysAddr[i]; + so->sa_family = AF_INET; + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = 1; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = ift->table[if_cnt].dwMtu; + break; + } + ++cnt; + if ((caddr_t) ++ifr > + ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) + goto done; + } + } } } done: @@ -1921,7 +1587,7 @@ get_95_ifconf (struct ifconf *ifc, int what) ++i) { HKEY ifkey, subkey; - char driver[256], classname[256], bindname[256], netname[256]; + char driver[256], classname[256], netname[256]; char adapter[256], ip[256], np[256]; if (res != ERROR_SUCCESS @@ -1997,57 +1663,34 @@ get_95_ifconf (struct ifconf *ifc, int what) RegCloseKey (subkey); - if (RegOpenKeyEx (ifkey, "Bindings", - 0, KEY_READ, &subkey) != ERROR_SUCCESS) - { + 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; - } - - for (int j = 0; - (res = RegEnumValue (subkey, j, bindname, - (size = sizeof bindname, &size), - 0, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS; - ++j) - if (!strncasecmp (bindname, "VREDIR\\", 7)) - break; - - RegCloseKey (subkey); - - if (res == ERROR_SUCCESS) - { - strcpy (netname, "System\\CurrentControlSet\\Services\\Class\\Net\\"); - strcat (netname, bindname + 7); - - 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 + 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); - - } + { + ++*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; @@ -2067,6 +1710,9 @@ get_ifconf (struct ifconf *ifc, int what) unsigned long lip, lnp; struct sockaddr_in *sa; + if (check_null_invalid_struct_errno (ifc)) + return -1; + /* Union maps buffer to correct struct */ struct ifreq *ifr = ifc->ifc_req; @@ -2141,18 +1787,25 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, SOCKET fd2s; sigframe thisframe (mainthread); - int res_fd = cygheap->fdtab.find_unused_handle (); - if (res_fd == -1) + if (check_null_invalid_struct_errno (ahost) || + check_null_empty_str_errno (*ahost) || + (locuser && check_null_empty_str_errno (locuser)) || + (remuser && check_null_str_errno (remuser))) + return (int) INVALID_SOCKET; + + cygheap_fdnew res_fd; + if (res_fd < 0) goto done; if (fd2p) { - *fd2p = cygheap->fdtab.find_unused_handle (res_fd + 1); - if (*fd2p == -1) + cygheap_fdnew newfd (res_fd, false); + if (*fd2p < 0) goto done; + *fd2p = newfd; } - res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p? &fd2s: NULL); + res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p ? &fd2s : NULL); if (res == (int) INVALID_SOCKET) goto done; else @@ -2160,10 +1813,10 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, fdsock (res_fd, "/dev/tcp", res); res = res_fd; } + if (fd2p) - { - fdsock (*fd2p, "/dev/tcp", fd2s); - } + fdsock (*fd2p, "/dev/tcp", fd2s); + done: syscall_printf ("%d = rcmd (...)", res); return res; @@ -2173,22 +1826,26 @@ done: extern "C" int cygwin_rresvport (int *port) { - int res = -1; + int res; sigframe thisframe (mainthread); - int res_fd = cygheap->fdtab.find_unused_handle (); - if (res_fd == -1) - goto done; - res = rresvport (port); + if (check_null_invalid_struct_errno (port)) + return -1; - if (res == (int) INVALID_SOCKET) - goto done; + cygheap_fdnew res_fd; + if (res_fd < 0) + res = -1; else { - fdsock (res_fd, "/dev/tcp", res); - res = res_fd; + res = rresvport (port); + + if (res != (int) INVALID_SOCKET) + { + fdsock (res_fd, "/dev/tcp", res); + res = res_fd; + } } -done: + syscall_printf ("%d = rresvport (%d)", res, port ? *port : 0); return res; } @@ -2202,14 +1859,21 @@ cygwin_rexec (char **ahost, unsigned short inport, char *locuser, SOCKET fd2s; sigframe thisframe (mainthread); - int res_fd = cygheap->fdtab.find_unused_handle (); - if (res_fd == -1) + if (check_null_invalid_struct_errno (ahost) || + check_null_empty_str_errno (*ahost) || + (locuser && check_null_empty_str_errno (locuser)) || + (password && check_null_str_errno (password))) + return (int) INVALID_SOCKET; + + cygheap_fdnew res_fd; + if (res_fd < 0) goto done; if (fd2p) { - *fd2p = cygheap->fdtab.find_unused_handle (res_fd + 1); - if (*fd2p == -1) + cygheap_fdnew newfd (res_fd); + if (newfd < 0) goto done; + *fd2p = newfd; } res = rexec (ahost, inport, locuser, password, cmd, fd2p ? &fd2s : NULL); if (res == (int) INVALID_SOCKET) @@ -2230,29 +1894,48 @@ done: /* socketpair: standards? */ /* Win32 supports AF_INET only, so ignore domain and protocol arguments */ extern "C" int -socketpair (int, int type, int, int *sb) +socketpair (int family, int type, int protocol, int *sb) { int res = -1; SOCKET insock, outsock, newsock; - struct sockaddr_in sock_in; - int len = sizeof (sock_in); + struct sockaddr_in sock_in, sock_out; + int len; + cygheap_fdnew sb0; + fhandler_socket *fh; - SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socketpair"); + if (__check_null_invalid_struct_errno (sb, 2 * sizeof (int))) + return -1; - sb[0] = cygheap->fdtab.find_unused_handle (); - if (sb[0] == -1) + if (family != AF_LOCAL && family != AF_INET) + { + set_errno (EAFNOSUPPORT); + goto done; + } + if (type != SOCK_STREAM && type != SOCK_DGRAM) { - set_errno (EMFILE); + set_errno (EPROTOTYPE); goto done; } - sb[1] = cygheap->fdtab.find_unused_handle (sb[0] + 1); - if (sb[1] == -1) + if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL) + || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET)) { - set_errno (EMFILE); + set_errno (EPROTONOSUPPORT); goto done; } - /* create a listening socket */ + if (sb0 < 0) + goto done; + else + { + sb[0] = sb0; + cygheap_fdnew sb1 (sb0, false); + if (sb1 < 0) + goto done; + + sb[1] = sb1; + } + + /* create the first socket */ newsock = socket (AF_INET, type, 0); if (newsock == INVALID_SOCKET) { @@ -2265,7 +1948,6 @@ socketpair (int, int type, int, int *sb) 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"); @@ -2273,7 +1955,7 @@ socketpair (int, int type, int, int *sb) closesocket (newsock); goto done; } - + len = sizeof (sock_in); if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0) { debug_printf ("getsockname error"); @@ -2282,7 +1964,9 @@ socketpair (int, int type, int, int *sb) goto done; } - listen (newsock, 2); + /* For stream sockets, create a listener */ + if (type == SOCK_STREAM) + listen (newsock, 2); /* create a connecting socket */ outsock = socket (AF_INET, type, 0); @@ -2294,9 +1978,37 @@ socketpair (int, int type, int, int *sb) 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 = INADDR_ANY; + 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 and accept the connection */ + /* Do a connect */ if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) { @@ -2307,26 +2019,68 @@ socketpair (int, int type, int, int *sb) goto done; } - insock = accept (newsock, (struct sockaddr *) &sock_in, &len); - if (insock == INVALID_SOCKET) + if (type == SOCK_STREAM) { - debug_printf ("accept error"); - set_winsock_errno (); + /* 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); - closesocket (outsock); - goto done; + } + 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; } - closesocket (newsock); res = 0; - fdsock (sb[0], "/dev/tcp", insock); + if (family == AF_LOCAL) + { - fdsock (sb[1], "/dev/tcp", outsock); + fh = fdsock (sb[0], + type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket", + insock); + fh->set_sun_path (""); + fh->set_addr_family (AF_LOCAL); + fh->set_socket_type (type); + fh = fdsock (sb[1], + type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket", + outsock); + fh->set_sun_path (""); + fh->set_addr_family (AF_LOCAL); + fh->set_socket_type (type); + } + else + { + fh = fdsock (sb[0], type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", + insock); + fh->set_addr_family (AF_INET); + fh->set_socket_type (type); + fh = fdsock (sb[1], type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", + outsock); + fh->set_addr_family (AF_INET); + fh->set_socket_type (type); + } done: syscall_printf ("%d = socketpair (...)", res); - ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socketpair"); return res; } @@ -2341,3 +2095,55 @@ extern "C" void endhostent (void) { } + +/* exported as recvmsg: standards? */ +extern "C" int +cygwin_recvmsg (int fd, struct msghdr *msg, int flags) +{ + int res; + sigframe thisframe (mainthread); + + fhandler_socket *fh = get (fd); + + if (check_null_invalid_struct_errno (msg) + || (msg->msg_name + && __check_null_invalid_struct_errno (msg->msg_name, + (unsigned) msg->msg_namelen)) + || !fh) + res = -1; + else + { + res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); + if (res > 0) + res = fh->recvmsg (msg, flags, res); // res == iovec tot + } + + 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; + sigframe thisframe (mainthread); + + fhandler_socket *fh = get (fd); + + if (__check_invalid_read_ptr_errno (msg, sizeof msg) + || (msg->msg_name + && __check_invalid_read_ptr_errno (msg->msg_name, + (unsigned) msg->msg_namelen)) + || !fh) + res = -1; + else + { + res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); + if (res > 0) + res = fh->sendmsg (msg, flags, res); // res == iovec tot + } + + syscall_printf ("%d = sendmsg (%d, %p, %x)", res, fd, msg, flags); + return res; +} |