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/fhandler_socket.cc')
-rw-r--r--winsup/cygwin/fhandler_socket.cc919
1 files changed, 856 insertions, 63 deletions
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index a34272f6a..95633e4b5 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -1,6 +1,6 @@
/* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -15,11 +15,12 @@
#include "winsup.h"
#include <errno.h>
#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
#include <asm/byteorder.h>
#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock2.h>
#include "cygerrno.h"
@@ -31,22 +32,73 @@
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
+#include "wsock_event.h"
#define SECRET_EVENT_NAME "cygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x"
#define ENTROPY_SOURCE_NAME "/dev/urandom"
#define ENTROPY_SOURCE_DEV_UNIT 9
+extern fhandler_socket *fdsock (int& fd, const char *name, SOCKET soc);
+extern "C" {
+int sscanf (const char *, const char *, ...);
+} /* End of "C" section */
+
fhandler_dev_random* entropy_source;
+/* cygwin internal: map sockaddr into internet domain address */
+static int
+get_inet_addr (const struct sockaddr *in, int inlen,
+ struct sockaddr_in *out, int *outlen, 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_LOCAL)
+ {
+ 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;
+ }
+}
+
/**********************************************************************/
/* fhandler_socket */
-fhandler_socket::fhandler_socket (const char *name) :
- fhandler_base (FH_SOCKET, name)
+fhandler_socket::fhandler_socket ()
+ : fhandler_base (FH_SOCKET), sun_path (NULL)
{
- set_cb (sizeof *this);
set_need_fork_fixup ();
- prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF,
+ prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF,
sizeof (WSAPROTOCOL_INFOA));
}
@@ -54,6 +106,8 @@ fhandler_socket::~fhandler_socket ()
{
if (prot_info_ptr)
cfree (prot_info_ptr);
+ if (sun_path)
+ cfree (sun_path);
}
void
@@ -62,11 +116,10 @@ fhandler_socket::set_connect_secret ()
if (!entropy_source)
{
void *buf = malloc (sizeof (fhandler_dev_random));
- entropy_source = new (buf) fhandler_dev_random (ENTROPY_SOURCE_NAME,
- ENTROPY_SOURCE_DEV_UNIT);
+ entropy_source = new (buf) fhandler_dev_random (ENTROPY_SOURCE_DEV_UNIT);
}
if (entropy_source &&
- !entropy_source->open (ENTROPY_SOURCE_NAME, O_RDONLY))
+ !entropy_source->open (NULL, O_RDONLY))
{
delete entropy_source;
entropy_source = NULL;
@@ -93,7 +146,7 @@ fhandler_socket::create_secret_event (int* secret)
struct sockaddr_in sin;
int sin_len = sizeof (sin);
- if (getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
+ if (::getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
{
debug_printf ("error getting local socket name (%d)", WSAGetLastError ());
return NULL;
@@ -102,12 +155,17 @@ fhandler_socket::create_secret_event (int* secret)
__small_sprintf (buf, SECRET_EVENT_NAME, sin.sin_port,
secret_ptr [0], secret_ptr [1],
secret_ptr [2], secret_ptr [3]);
- secret_event = CreateEvent (get_inheritance(true), FALSE, FALSE, buf);
+ LPSECURITY_ATTRIBUTES sec = get_inheritance (true);
+ secret_event = CreateEvent (sec, FALSE, FALSE, buf);
if (!secret_event && GetLastError () == ERROR_ALREADY_EXISTS)
secret_event = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
- if (secret_event)
+ if (!secret_event)
+ /* nothing to do */;
+ else if (sec == &sec_all_nih || sec == &sec_none_nih)
ProtectHandle (secret_event);
+ else
+ ProtectHandleINH (secret_event);
return secret_event;
}
@@ -115,8 +173,13 @@ fhandler_socket::create_secret_event (int* secret)
void
fhandler_socket::signal_secret_event ()
{
- if (secret_event)
- SetEvent (secret_event);
+ if (!secret_event)
+ debug_printf ("no secret event?");
+ else
+ {
+ SetEvent (secret_event);
+ debug_printf ("signaled secret_event");
+ }
}
void
@@ -140,7 +203,7 @@ fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
ev = CreateEvent (&sec_all_nih, FALSE, FALSE, buf);
if (!ev && GetLastError () == ERROR_ALREADY_EXISTS)
{
- debug_printf ("%s event already exist");
+ debug_printf ("event \"%s\" already exists", buf);
ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
}
@@ -160,54 +223,51 @@ fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
void
fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
{
- int ret = 1;
-
- if (prot_info_ptr &&
- (ret = WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr)))
+ if (!winsock2_active)
{
- debug_printf ("WSADuplicateSocket error");
- set_winsock_errno ();
- }
- if (!ret && ws2_32_handle)
- {
- debug_printf ("WSADuplicateSocket went fine, dwServiceFlags1=%d",
- prot_info_ptr->dwServiceFlags1);
+ fhandler_base::fixup_before_fork_exec (win_proc_id);
+ debug_printf ("Without Winsock 2.0");
}
+ else if (!WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr))
+ debug_printf ("WSADuplicateSocket went fine, sock %p, win_proc_id %d, prot_info_ptr %p",
+ get_socket (), win_proc_id, prot_info_ptr);
else
{
- fhandler_base::fixup_before_fork_exec (win_proc_id);
- debug_printf ("Without Winsock 2.0");
+ debug_printf ("WSADuplicateSocket error, sock %p, win_proc_id %d, prot_info_ptr %p",
+ get_socket (), win_proc_id, prot_info_ptr);
+ set_winsock_errno ();
}
}
+extern "C" void __stdcall load_wsock32 ();
void
fhandler_socket::fixup_after_fork (HANDLE parent)
{
- SOCKET new_sock = INVALID_SOCKET;
+ SOCKET new_sock;
debug_printf ("WSASocket begin, dwServiceFlags1=%d",
prot_info_ptr->dwServiceFlags1);
- if (prot_info_ptr &&
- (new_sock = WSASocketA (FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- prot_info_ptr, 0, 0)) == INVALID_SOCKET)
+
+ if ((new_sock = WSASocketA (FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ prot_info_ptr, 0, 0)) == INVALID_SOCKET)
{
debug_printf ("WSASocket error");
set_winsock_errno ();
}
- if (new_sock != INVALID_SOCKET && ws2_32_handle)
+ else if (!new_sock && !winsock2_active)
{
- debug_printf ("WSASocket went fine");
- set_io_handle ((HANDLE) new_sock);
+ load_wsock32 ();
+ fhandler_base::fixup_after_fork (parent);
+ debug_printf ("Without Winsock 2.0");
}
else
{
-#if 0
- fhandler_base::fixup_after_fork (parent);
-#endif
- debug_printf ("Without Winsock 2.0");
+ debug_printf ("WSASocket went fine new_sock %p, old_sock %p", new_sock, get_io_handle ());
+ set_io_handle ((HANDLE) new_sock);
}
+
if (secret_event)
fork_fixup (parent, secret_event, "secret_event");
}
@@ -215,21 +275,27 @@ fhandler_socket::fixup_after_fork (HANDLE parent)
void
fhandler_socket::fixup_after_exec (HANDLE parent)
{
- extern WSADATA wsadata;
+ debug_printf ("here");
if (!get_close_on_exec ())
fixup_after_fork (parent);
- else if (wsadata.wVersion < 512) /* < Winsock 2.0 */
+#if 0
+ else if (!winsock2_active)
closesocket (get_socket ());
+#endif
}
int
fhandler_socket::dup (fhandler_base *child)
{
+ debug_printf ("here");
fhandler_socket *fhs = (fhandler_socket *) child;
fhs->addr_family = addr_family;
fhs->set_io_handle (get_io_handle ());
+ if (get_addr_family () == AF_LOCAL)
+ fhs->set_sun_path (get_sun_path ());
+
fhs->fixup_before_fork_exec (GetCurrentProcessId ());
- if (ws2_32_handle)
+ if (winsock2_active)
{
fhs->fixup_after_fork (hMainProc);
return 0;
@@ -237,38 +303,753 @@ fhandler_socket::dup (fhandler_base *child)
return fhandler_base::dup (child);
}
+int __stdcall
+fhandler_socket::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ int res = fhandler_base::fstat (buf, pc);
+ if (!res)
+ {
+ buf->st_mode &= ~_IFMT;
+ buf->st_mode |= _IFSOCK;
+ buf->st_ino = (ino_t) get_handle ();
+ }
+ return res;
+}
+
+int
+fhandler_socket::bind (const struct sockaddr *name, int namelen)
+{
+ int res = -1;
+
+ if (name->sa_family == AF_LOCAL)
+ {
+#define un_addr ((struct sockaddr_un *) name)
+ 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 (get_socket (), (sockaddr *) &sin, len))
+ {
+ syscall_printf ("AF_LOCAL: bind failed %d", get_errno ());
+ set_winsock_errno ();
+ goto out;
+ }
+ if (::getsockname (get_socket (), (sockaddr *) &sin, &len))
+ {
+ syscall_printf ("AF_LOCAL: getsockname failed %d", get_errno ());
+ set_winsock_errno ();
+ goto out;
+ }
+
+ sin.sin_port = ntohs (sin.sin_port);
+ debug_printf ("AF_LOCAL: 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;
+ }
+
+ set_connect_secret ();
+
+ char buf[sizeof (SOCKET_COOKIE) + 80];
+ __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);
+ get_connect_secret (strchr (buf, '\0'));
+ len = strlen (buf) + 1;
+
+ /* 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);
+ set_sun_path (un_addr->sun_path);
+ res = 0;
+ }
+#undef un_addr
+ }
+ else if (::bind (get_socket (), name, namelen))
+ set_winsock_errno ();
+ else
+ res = 0;
+
+out:
+ return res;
+}
+
+int
+fhandler_socket::connect (const struct sockaddr *name, int namelen)
+{
+ int res = -1;
+ BOOL secret_check_failed = FALSE;
+ BOOL in_progress = FALSE;
+ sockaddr_in sin;
+ int secret [4];
+
+ if (!get_inet_addr (name, namelen, &sin, &namelen, secret))
+ return -1;
+
+ res = ::connect (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 (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 (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
+ {
+ if (!res || in_progress)
+ {
+ if (!create_secret_event (secret))
+ {
+ secret_check_failed = TRUE;
+ }
+ else if (in_progress)
+ signal_secret_event ();
+ }
+
+ if (!secret_check_failed && !res)
+ {
+ if (!check_peer_secret_event (&sin, secret))
+ {
+ debug_printf ( "accept from unauthorized server" );
+ secret_check_failed = TRUE;
+ }
+ }
+
+ if (secret_check_failed)
+ {
+ close_secret_event ();
+ if (res)
+ closesocket (res);
+ set_errno (ECONNREFUSED);
+ res = -1;
+ }
+ }
+
+ if (WSAGetLastError () == WSAEINPROGRESS)
+ set_connect_state (CONNECT_PENDING);
+ else
+ set_connect_state (CONNECTED);
+ return res;
+}
+
+int
+fhandler_socket::listen (int backlog)
+{
+ int res = ::listen (get_socket (), backlog);
+ if (res)
+ set_winsock_errno ();
+ else
+ set_connect_state (CONNECTED);
+ return res;
+}
+
+int
+fhandler_socket::accept (struct sockaddr *peer, int *len)
+{
+ int res = -1;
+ WSAEVENT ev[2] = { WSA_INVALID_EVENT, signal_arrived };
+ BOOL secret_check_failed = FALSE;
+ BOOL in_progress = FALSE;
+
+ /* 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);
+
+ if (!is_nonblocking ())
+ {
+ ev[0] = WSACreateEvent ();
+
+ if (ev[0] != WSA_INVALID_EVENT &&
+ !WSAEventSelect (get_socket (), ev[0], FD_ACCEPT))
+ {
+ WSANETWORKEVENTS sock_event;
+ int wait_result;
+
+ wait_result = WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE,
+ FALSE);
+ if (wait_result == WSA_WAIT_EVENT_0)
+ WSAEnumNetworkEvents (get_socket (), ev[0], &sock_event);
+
+ /* Unset events for listening socket and
+ switch back to blocking mode */
+ WSAEventSelect (get_socket (), ev[0], 0);
+ unsigned long nonblocking = 0;
+ ioctlsocket (get_socket (), FIONBIO, &nonblocking);
+
+ switch (wait_result)
+ {
+ case WSA_WAIT_EVENT_0:
+ if (sock_event.lNetworkEvents & FD_ACCEPT)
+ {
+ if (sock_event.iErrorCode[FD_ACCEPT_BIT])
+ {
+ WSASetLastError (sock_event.iErrorCode[FD_ACCEPT_BIT]);
+ set_winsock_errno ();
+ res = -1;
+ goto done;
+ }
+ }
+ /* else; : Should never happen since FD_ACCEPT is the only event
+ that has been selected */
+ break;
+ case WSA_WAIT_EVENT_0 + 1:
+ debug_printf ("signal received during accept");
+ set_errno (EINTR);
+ res = -1;
+ goto done;
+ case WSA_WAIT_FAILED:
+ default: /* Should never happen */
+ WSASetLastError (WSAEFAULT);
+ set_winsock_errno ();
+ res = -1;
+ goto done;
+ }
+ }
+ }
+
+ res = ::accept (get_socket (), peer, len);
+
+ if ((SOCKET) res == (SOCKET) INVALID_SOCKET &&
+ WSAGetLastError () == WSAEWOULDBLOCK)
+ in_progress = TRUE;
+
+ if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
+ {
+ if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress)
+ {
+ if (!create_secret_event ())
+ secret_check_failed = TRUE;
+ else if (in_progress)
+ signal_secret_event ();
+ }
+
+ if (!secret_check_failed &&
+ (SOCKET) res != (SOCKET) INVALID_SOCKET)
+ {
+ if (!check_peer_secret_event ((struct sockaddr_in*) peer))
+ {
+ debug_printf ("connect from unauthorized client");
+ secret_check_failed = TRUE;
+ }
+ }
+
+ if (secret_check_failed)
+ {
+ close_secret_event ();
+ if ((SOCKET) res != (SOCKET) INVALID_SOCKET)
+ closesocket (res);
+ set_errno (ECONNABORTED);
+ res = -1;
+ goto done;
+ }
+ }
+
+ {
+ cygheap_fdnew res_fd;
+ if (res_fd < 0)
+ /* FIXME: what is correct errno? */;
+ else if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
+ set_winsock_errno ();
+ else
+ {
+ fhandler_socket* res_fh = fdsock (res_fd, get_name (), res);
+ if (get_addr_family () == AF_LOCAL)
+ res_fh->set_sun_path (get_sun_path ());
+ res_fh->set_addr_family (get_addr_family ());
+ res_fh->set_socket_type (get_socket_type ());
+ res = res_fd;
+ }
+ }
+
+done:
+ if (ev[0] != WSA_INVALID_EVENT)
+ WSACloseEvent (ev[0]);
+
+ return res;
+}
+
+int
+fhandler_socket::getsockname (struct sockaddr *name, int *namelen)
+{
+ int res = -1;
+
+ if (get_addr_family () == AF_LOCAL)
+ {
+ struct sockaddr_un *sun = (struct sockaddr_un *) name;
+ memset (sun, 0, *namelen);
+ sun->sun_family = AF_LOCAL;
+
+ if (!get_sun_path ())
+ sun->sun_path[0] = '\0';
+ else
+ /* According to SUSv2 "If the actual length of the address is
+ greater than the length of the supplied sockaddr structure, the
+ stored address will be truncated." We play it save here so
+ that the path always has a trailing 0 even if it's truncated. */
+ strncpy (sun->sun_path, get_sun_path (),
+ *namelen - sizeof *sun + sizeof sun->sun_path - 1);
+
+ *namelen = sizeof *sun - sizeof sun->sun_path
+ + strlen (sun->sun_path) + 1;
+ res = 0;
+ }
+ else
+ {
+ res = ::getsockname (get_socket (), name, namelen);
+ if (res)
+ set_winsock_errno ();
+ }
+
+ return res;
+}
+
int
-fhandler_socket::read (void *ptr, size_t len)
+fhandler_socket::getpeername (struct sockaddr *name, int *namelen)
{
- sigframe thisframe (mainthread);
- int res = recv (get_socket (), (char *) ptr, len, 0);
+ int res = ::getpeername (get_socket (), name, namelen);
+ if (res)
+ set_winsock_errno ();
+
+ return res;
+}
+
+int
+fhandler_socket::readv (const struct iovec *const iov, const int iovcnt,
+ ssize_t tot)
+{
+ struct msghdr msg =
+ {
+ msg_name: NULL,
+ msg_namelen: 0,
+ msg_iov: (struct iovec *) iov, // const_cast
+ msg_iovlen: iovcnt,
+ msg_accrights: NULL,
+ msg_accrightslen: 0
+ };
+
+ return recvmsg (&msg, 0, tot);
+}
+
+int
+fhandler_socket::recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen)
+{
+ int res;
+ DWORD ret;
+
+ flags &= MSG_WINMASK;
+ if (!winsock2_active)
+ ret = res = ::recvfrom (get_socket (),
+ (char *) ptr, len, flags,
+ from, fromlen);
+ else
+ {
+ WSABUF wsabuf = { len, (char *) ptr };
+
+ if (is_nonblocking ())
+ res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags,
+ from, fromlen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags,
+ from, fromlen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+ }
+
if (res == SOCKET_ERROR)
{
+ res = -1;
set_winsock_errno ();
}
+ else
+ res = ret;
+
+ return res;
+}
+
+int
+fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot)
+{
+ if (get_addr_family () == AF_LOCAL)
+ {
+ /* On AF_LOCAL sockets the (fixed-size) name of the shared memory
+ area used for descriptor passing is transmitted first.
+ If this string is empty, no descriptors are passed and we can
+ go ahead recv'ing the normal data blocks. Otherwise start
+ special handling for descriptor passing. */
+ /*TODO*/
+ }
+
+ struct iovec *const iov = msg->msg_iov;
+ const int iovcnt = msg->msg_iovlen;
+
+ int res;
+
+ if (!winsock2_active)
+ {
+ if (iovcnt == 1)
+ res = recvfrom (iov->iov_base, iov->iov_len, flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen);
+ else
+ {
+ if (tot == -1) // i.e. if not pre-calculated by the caller.
+ {
+ tot = 0;
+ const struct iovec *iovptr = iov + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ tot += iovptr->iov_len;
+ }
+ while (iovptr != iov);
+ }
+
+ char *buf = (char *) alloca (tot);
+
+ if (!buf)
+ {
+ set_errno (ENOMEM);
+ res = -1;
+ }
+ else
+ {
+ res = recvfrom (buf, tot, flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen);
+
+ const struct iovec *iovptr = iov;
+ int nbytes = res;
+
+ while (nbytes > 0)
+ {
+ const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
+ memcpy (iovptr->iov_base, buf, frag);
+ buf += frag;
+ iovptr += 1;
+ nbytes -= frag;
+ }
+ }
+ }
+ }
+ else
+ {
+ WSABUF wsabuf[iovcnt];
+
+ {
+ const struct iovec *iovptr = iov + iovcnt;
+ WSABUF *wsaptr = wsabuf + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ wsaptr -= 1;
+ wsaptr->len = iovptr->iov_len;
+ wsaptr->buf = (char *) iovptr->iov_base;
+ }
+ while (wsaptr != wsabuf);
+ }
+
+ DWORD ret;
+
+ if (is_nonblocking ())
+ res = WSARecvFrom (get_socket (),
+ wsabuf, iovcnt, &ret, (DWORD *) &flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSARecvFrom (get_socket (),
+ wsabuf, iovcnt, &ret, (DWORD *) &flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+
+ if (res == SOCKET_ERROR)
+ {
+ res = -1;
+ set_winsock_errno ();
+ }
+ else
+ res = ret;
+ }
+
return res;
}
int
-fhandler_socket::write (const void *ptr, size_t len)
+fhandler_socket::writev (const struct iovec *const iov, const int iovcnt,
+ ssize_t tot)
+{
+ struct msghdr msg =
+ {
+ msg_name: NULL,
+ msg_namelen: 0,
+ msg_iov: (struct iovec *) iov, // const_cast
+ msg_iovlen: iovcnt,
+ msg_accrights: NULL,
+ msg_accrightslen: 0
+ };
+
+ return sendmsg (&msg, 0, tot);
+}
+
+int
+fhandler_socket::sendto (const void *ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen)
{
- sigframe thisframe (mainthread);
- int res = send (get_socket (), (const char *) ptr, len, 0);
+ sockaddr_in sin;
+
+ if (to && !get_inet_addr (to, tolen, &sin, &tolen))
+ return -1;
+
+ int res;
+ DWORD ret;
+
+ if (!winsock2_active)
+ res = ::sendto (get_socket (), (const char *) ptr, len,
+ flags & MSG_WINMASK,
+ (to ? (const struct sockaddr *) &sin : NULL), tolen);
+ else
+ {
+ WSABUF wsabuf = { len, (char *) ptr };
+
+ if (is_nonblocking ())
+ res = WSASendTo (get_socket (), &wsabuf, 1, &ret,
+ flags & MSG_WINMASK,
+ (to ? (const struct sockaddr *) &sin : NULL), tolen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSASendTo (get_socket (), &wsabuf, 1, &ret,
+ flags & MSG_WINMASK,
+ (to ? (const struct sockaddr *) &sin : NULL), tolen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+ }
+
if (res == SOCKET_ERROR)
{
+ res = -1;
set_winsock_errno ();
- if (get_errno () == ECONNABORTED || get_errno () == ECONNRESET)
+ }
+ else
+ res = ret;
+
+ /* Special handling for SIGPIPE */
+ if (res == -1 && get_errno () == ESHUTDOWN)
+ {
+ set_errno (EPIPE);
+ if (! (flags & MSG_NOSIGNAL))
_raise (SIGPIPE);
}
+
+ return res;
+}
+
+int
+fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot)
+{
+ if (get_addr_family () == AF_LOCAL)
+ {
+ /* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start
+ the special handling for descriptor passing. Otherwise just
+ transmit an empty string to tell the receiver that no
+ descriptor passing is done. */
+ /*TODO*/
+ }
+
+ struct iovec *const iov = msg->msg_iov;
+ const int iovcnt = msg->msg_iovlen;
+
+ int res;
+
+ if (!winsock2_active)
+ {
+ if (iovcnt == 1)
+ res = sendto (iov->iov_base, iov->iov_len, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen);
+ else
+ {
+ if (tot == -1) // i.e. if not pre-calculated by the caller.
+ {
+ tot = 0;
+ const struct iovec *iovptr = iov + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ tot += iovptr->iov_len;
+ }
+ while (iovptr != iov);
+ }
+
+ char *const buf = (char *) alloca (tot);
+
+ if (!buf)
+ {
+ set_errno (ENOMEM);
+ res = -1;
+ }
+ else
+ {
+ char *bufptr = buf;
+ const struct iovec *iovptr = iov;
+ int nbytes = tot;
+
+ while (nbytes != 0)
+ {
+ const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
+ memcpy (bufptr, iovptr->iov_base, frag);
+ bufptr += frag;
+ iovptr += 1;
+ nbytes -= frag;
+ }
+
+ res = sendto (buf, tot, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen);
+ }
+ }
+ }
+ else
+ {
+ WSABUF wsabuf[iovcnt];
+
+ {
+ const struct iovec *iovptr = iov + iovcnt;
+ WSABUF *wsaptr = wsabuf + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ wsaptr -= 1;
+ wsaptr->len = iovptr->iov_len;
+ wsaptr->buf = (char *) iovptr->iov_base;
+ }
+ while (wsaptr != wsabuf);
+ }
+
+ DWORD ret;
+
+ if (is_nonblocking ())
+ res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+
+ if (res == SOCKET_ERROR)
+ {
+ res = -1;
+ set_winsock_errno ();
+ }
+ else
+ res = ret;
+ }
+
+ return res;
+}
+
+int
+fhandler_socket::shutdown (int how)
+{
+ int res = ::shutdown (get_socket (), how);
+
+ if (res)
+ set_winsock_errno ();
+ else
+ switch (how)
+ {
+ case SHUT_RD:
+ set_shutdown_read ();
+ break;
+ case SHUT_WR:
+ set_shutdown_write ();
+ break;
+ case SHUT_RDWR:
+ set_shutdown_read ();
+ set_shutdown_write ();
+ break;
+ }
return res;
}
-/* Cygwin internal */
int
fhandler_socket::close ()
{
int res = 0;
- sigframe thisframe (mainthread);
/* HACK to allow a graceful shutdown even if shutdown() hasn't been
called by the application. Note that this isn't the ultimate
@@ -279,10 +1060,21 @@ fhandler_socket::close ()
setsockopt (get_socket (), SOL_SOCKET, SO_LINGER,
(const char *)&linger, sizeof linger);
- if (closesocket (get_socket ()))
+ while ((res = closesocket (get_socket ())) != 0)
{
- set_winsock_errno ();
- res = -1;
+ if (WSAGetLastError () != WSAEWOULDBLOCK)
+ {
+ set_winsock_errno ();
+ res = -1;
+ break;
+ }
+ if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0)
+ {
+ set_errno (EINTR);
+ res = -1;
+ break;
+ }
+ WSASetLastError (0);
}
close_secret_event ();
@@ -293,7 +1085,6 @@ fhandler_socket::close ()
#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
-/* Cygwin internal */
int
fhandler_socket::ioctl (unsigned int cmd, void *p)
{
@@ -301,7 +1092,6 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
int res;
struct ifconf ifc, *ifcp;
struct ifreq *ifr, *ifrp;
- sigframe thisframe (mainthread);
switch (cmd)
{
@@ -414,7 +1204,7 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
if (cmd == FIONBIO)
{
syscall_printf ("socket is now %sblocking",
- *(int *) p ? "un" : "");
+ *(int *) p ? "non" : "");
/* Start AsyncSelect if async socket unblocked */
if (*(int *) p && get_async ())
WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO, ASYNC_MASK);
@@ -460,11 +1250,14 @@ fhandler_socket::fcntl (int cmd, void *arg)
void
fhandler_socket::set_close_on_exec (int val)
{
-#if 0
- extern WSADATA wsadata;
- if (wsadata.wVersion < 512) /* < Winsock 2.0 */
+ if (!winsock2_active) /* < Winsock 2.0 */
set_inheritance (get_handle (), val);
-#endif
set_close_on_exec_flag (val);
debug_printf ("set close_on_exec for %s to %d", get_name (), val);
}
+
+void
+fhandler_socket::set_sun_path (const char *path)
+{
+ sun_path = path ? cstrdup (path) : NULL;
+}