Cygwin: encapsulate Winsock based fhandler_socket classes
Insert another class fhandler_socket_wsock between fhandler_socket and fhandler_socket_inet/fhandler_socket_local. Also, add a new method fhandler::is_wsock_socket to allow asking for sockets in general (is_socket) vs. Winsock-based sockets (is_wsock_socket). This allows to develop a new handler_socket_unix class as derived class from fhandler_socket without any trace of wsock code left in fhandler_socket. While this is basically a temporary measure at this time, it may prove useful for later interoperability with the upcoming Windows 10 AF_UNIX implementation at one point. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
@@ -221,9 +221,10 @@ get_ext_funcptr (SOCKET sock, void *funcptr)
|
||||
}
|
||||
|
||||
fhandler_socket_local::fhandler_socket_local () :
|
||||
fhandler_socket (),
|
||||
fhandler_socket_wsock (),
|
||||
sun_path (NULL),
|
||||
peer_sun_path (NULL)
|
||||
peer_sun_path (NULL),
|
||||
status ()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1044,73 +1045,7 @@ fhandler_socket_local::getpeername (struct sockaddr *name, int *namelen)
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_socket_local::shutdown (int how)
|
||||
{
|
||||
int res = ::shutdown (get_socket (), how);
|
||||
|
||||
/* Linux allows to call shutdown for any socket, even if it's not connected.
|
||||
This also disables to call accept on this socket, if shutdown has been
|
||||
called with the SHUT_RD or SHUT_RDWR parameter. In contrast, WinSock
|
||||
only allows to call shutdown on a connected socket. The accept function
|
||||
is in no way affected. So, what we do here is to fake success, and to
|
||||
change the event settings so that an FD_CLOSE event is triggered for the
|
||||
calling Cygwin function. The evaluate_events method handles the call
|
||||
from accept specially to generate a Linux-compatible behaviour. */
|
||||
if (res && WSAGetLastError () != WSAENOTCONN)
|
||||
set_winsock_errno ();
|
||||
else
|
||||
{
|
||||
res = 0;
|
||||
switch (how)
|
||||
{
|
||||
case SHUT_RD:
|
||||
saw_shutdown_read (true);
|
||||
wsock_events->events |= FD_CLOSE;
|
||||
SetEvent (wsock_evt);
|
||||
break;
|
||||
case SHUT_WR:
|
||||
saw_shutdown_write (true);
|
||||
break;
|
||||
case SHUT_RDWR:
|
||||
saw_shutdown_read (true);
|
||||
saw_shutdown_write (true);
|
||||
wsock_events->events |= FD_CLOSE;
|
||||
SetEvent (wsock_evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_socket_local::close ()
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
release_events ();
|
||||
while ((res = ::closesocket (get_socket ())) != 0)
|
||||
{
|
||||
if (WSAGetLastError () != WSAEWOULDBLOCK)
|
||||
{
|
||||
set_winsock_errno ();
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if (cygwait (10) == WAIT_SIGNALED)
|
||||
{
|
||||
set_errno (EINTR);
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
WSASetLastError (0);
|
||||
}
|
||||
|
||||
debug_printf ("%d = fhandler_socket::close()", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline ssize_t
|
||||
ssize_t
|
||||
fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
@@ -1279,235 +1214,6 @@ fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fhandler_socket_local::recvfrom (void *in_ptr, size_t len, int flags,
|
||||
struct sockaddr *from, int *fromlen)
|
||||
{
|
||||
char *ptr = (char *) in_ptr;
|
||||
|
||||
#ifdef __x86_64__
|
||||
/* size_t is 64 bit, but the len member in WSABUF is 32 bit.
|
||||
Split buffer if necessary. */
|
||||
DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0);
|
||||
WSABUF wsabuf[bufcnt];
|
||||
WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0,
|
||||
wsabuf, bufcnt,
|
||||
{ 0, NULL },
|
||||
(DWORD) flags };
|
||||
/* Don't use len as loop condition, it could be 0. */
|
||||
for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr)
|
||||
{
|
||||
wsaptr->len = MIN (len, UINT32_MAX);
|
||||
wsaptr->buf = ptr;
|
||||
len -= wsaptr->len;
|
||||
ptr += wsaptr->len;
|
||||
}
|
||||
#else
|
||||
WSABUF wsabuf = { len, ptr };
|
||||
WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0,
|
||||
&wsabuf, 1,
|
||||
{ 0, NULL},
|
||||
(DWORD) flags };
|
||||
#endif
|
||||
ssize_t ret = recv_internal (&wsamsg, false);
|
||||
if (fromlen)
|
||||
*fromlen = wsamsg.namelen;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fhandler_socket_local::recvmsg (struct msghdr *msg, int flags)
|
||||
{
|
||||
/* TODO: Descriptor passing on AF_LOCAL sockets. */
|
||||
|
||||
/* Disappointing but true: Even if WSARecvMsg is supported, it's only
|
||||
supported for datagram and raw sockets. */
|
||||
bool use_recvmsg = true;
|
||||
if (get_socket_type () == SOCK_STREAM || get_addr_family () == AF_LOCAL)
|
||||
{
|
||||
use_recvmsg = false;
|
||||
msg->msg_controllen = 0;
|
||||
}
|
||||
|
||||
WSABUF wsabuf[msg->msg_iovlen];
|
||||
WSABUF *wsaptr = wsabuf + msg->msg_iovlen;
|
||||
const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen;
|
||||
while (--wsaptr >= wsabuf)
|
||||
{
|
||||
wsaptr->len = (--iovptr)->iov_len;
|
||||
wsaptr->buf = (char *) iovptr->iov_base;
|
||||
}
|
||||
WSAMSG wsamsg = { (struct sockaddr *) msg->msg_name, msg->msg_namelen,
|
||||
wsabuf, (DWORD) msg->msg_iovlen,
|
||||
{ (DWORD) msg->msg_controllen, (char *) msg->msg_control },
|
||||
(DWORD) flags };
|
||||
ssize_t ret = recv_internal (&wsamsg, use_recvmsg);
|
||||
if (ret >= 0)
|
||||
{
|
||||
msg->msg_namelen = wsamsg.namelen;
|
||||
msg->msg_controllen = wsamsg.Control.len;
|
||||
if (!CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR)
|
||||
msg->msg_flags = wsamsg.dwFlags;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __reg3
|
||||
fhandler_socket_local::read (void *in_ptr, size_t& len)
|
||||
{
|
||||
char *ptr = (char *) in_ptr;
|
||||
|
||||
#ifdef __x86_64__
|
||||
/* size_t is 64 bit, but the len member in WSABUF is 32 bit.
|
||||
Split buffer if necessary. */
|
||||
DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0);
|
||||
WSABUF wsabuf[bufcnt];
|
||||
WSAMSG wsamsg = { NULL, 0, wsabuf, bufcnt, { 0, NULL }, 0 };
|
||||
/* Don't use len as loop condition, it could be 0. */
|
||||
for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr)
|
||||
{
|
||||
wsaptr->len = MIN (len, UINT32_MAX);
|
||||
wsaptr->buf = ptr;
|
||||
len -= wsaptr->len;
|
||||
ptr += wsaptr->len;
|
||||
}
|
||||
#else
|
||||
WSABUF wsabuf = { len, ptr };
|
||||
WSAMSG wsamsg = { NULL, 0, &wsabuf, 1, { 0, NULL }, 0 };
|
||||
#endif
|
||||
|
||||
len = recv_internal (&wsamsg, false);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fhandler_socket_local::readv (const struct iovec *const iov, const int iovcnt,
|
||||
ssize_t tot)
|
||||
{
|
||||
WSABUF wsabuf[iovcnt];
|
||||
WSABUF *wsaptr = wsabuf + iovcnt;
|
||||
const struct iovec *iovptr = iov + iovcnt;
|
||||
while (--wsaptr >= wsabuf)
|
||||
{
|
||||
wsaptr->len = (--iovptr)->iov_len;
|
||||
wsaptr->buf = (char *) iovptr->iov_base;
|
||||
}
|
||||
WSAMSG wsamsg = { NULL, 0, wsabuf, (DWORD) iovcnt, { 0, NULL}, 0 };
|
||||
return recv_internal (&wsamsg, false);
|
||||
}
|
||||
|
||||
inline ssize_t
|
||||
fhandler_socket_local::send_internal (struct _WSAMSG *wsamsg, int flags)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
DWORD ret = 0, sum = 0;
|
||||
WSABUF out_buf[wsamsg->dwBufferCount];
|
||||
bool use_sendmsg = false;
|
||||
DWORD wait_flags = flags & MSG_DONTWAIT;
|
||||
bool nosignal = !!(flags & MSG_NOSIGNAL);
|
||||
|
||||
flags &= (MSG_OOB | MSG_DONTROUTE);
|
||||
if (wsamsg->Control.len > 0)
|
||||
use_sendmsg = true;
|
||||
/* Workaround for MSDN KB 823764: Split a message into chunks <= SO_SNDBUF.
|
||||
in_idx is the index of the current lpBuffers from the input wsamsg buffer.
|
||||
in_off is used to keep track of the next byte to write from a wsamsg
|
||||
buffer which only gets partially written. */
|
||||
for (DWORD in_idx = 0, in_off = 0;
|
||||
in_idx < wsamsg->dwBufferCount;
|
||||
in_off >= wsamsg->lpBuffers[in_idx].len && (++in_idx, in_off = 0))
|
||||
{
|
||||
/* Split a message into the least number of pieces to minimize the
|
||||
number of WsaSendTo calls. Don't split datagram messages (bad idea).
|
||||
out_idx is the index of the next buffer in the out_buf WSABUF,
|
||||
also the number of buffers given to WSASendTo.
|
||||
out_len is the number of bytes in the buffers given to WSASendTo.
|
||||
Don't split datagram messages (very bad idea). */
|
||||
DWORD out_idx = 0;
|
||||
DWORD out_len = 0;
|
||||
if (get_socket_type () == SOCK_STREAM)
|
||||
{
|
||||
do
|
||||
{
|
||||
out_buf[out_idx].buf = wsamsg->lpBuffers[in_idx].buf + in_off;
|
||||
out_buf[out_idx].len = wsamsg->lpBuffers[in_idx].len - in_off;
|
||||
out_len += out_buf[out_idx].len;
|
||||
out_idx++;
|
||||
}
|
||||
while (out_len < (unsigned) wmem ()
|
||||
&& (in_off = 0, ++in_idx < wsamsg->dwBufferCount));
|
||||
/* Tweak len of the last out_buf buffer so the entire number of bytes
|
||||
is (less than or) equal to wmem (). Fix out_len as well since it's
|
||||
used in a subsequent test expression. */
|
||||
if (out_len > (unsigned) wmem ())
|
||||
{
|
||||
out_buf[out_idx - 1].len -= out_len - (unsigned) wmem ();
|
||||
out_len = (unsigned) wmem ();
|
||||
}
|
||||
/* Add the bytes written from the current last buffer to in_off,
|
||||
so in_off points to the next byte to be written from that buffer,
|
||||
or beyond which lets the outper loop skip to the next buffer. */
|
||||
in_off += out_buf[out_idx - 1].len;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (use_sendmsg)
|
||||
res = WSASendMsg (get_socket (), wsamsg, flags, &ret, NULL, NULL);
|
||||
else if (get_socket_type () == SOCK_STREAM)
|
||||
res = WSASendTo (get_socket (), out_buf, out_idx, &ret, flags,
|
||||
wsamsg->name, wsamsg->namelen, NULL, NULL);
|
||||
else
|
||||
res = WSASendTo (get_socket (), wsamsg->lpBuffers,
|
||||
wsamsg->dwBufferCount, &ret, flags,
|
||||
wsamsg->name, wsamsg->namelen, NULL, NULL);
|
||||
if (res && (WSAGetLastError () == WSAEWOULDBLOCK))
|
||||
{
|
||||
LOCK_EVENTS;
|
||||
wsock_events->events &= ~FD_WRITE;
|
||||
UNLOCK_EVENTS;
|
||||
}
|
||||
}
|
||||
while (res && (WSAGetLastError () == WSAEWOULDBLOCK)
|
||||
&& !(res = wait_for_events (FD_WRITE | FD_CLOSE, wait_flags)));
|
||||
|
||||
if (!res)
|
||||
{
|
||||
sum += ret;
|
||||
/* For streams, return to application if the number of bytes written
|
||||
is less than the number of bytes we intended to write in a single
|
||||
call to WSASendTo. Otherwise we would have to add code to
|
||||
backtrack in the input buffers, which is questionable. There was
|
||||
probably a good reason we couldn't write more. */
|
||||
if (get_socket_type () != SOCK_STREAM || ret < out_len)
|
||||
break;
|
||||
}
|
||||
else if (is_nonblocking () || WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sum)
|
||||
res = sum;
|
||||
else if (res == SOCKET_ERROR)
|
||||
{
|
||||
set_winsock_errno ();
|
||||
|
||||
/* Special handling for EPIPE and SIGPIPE.
|
||||
|
||||
EPIPE is generated if the local end has been shut down on a connection
|
||||
oriented socket. In this case the process will also receive a SIGPIPE
|
||||
unless MSG_NOSIGNAL is set. */
|
||||
if ((get_errno () == ECONNABORTED || get_errno () == ESHUTDOWN)
|
||||
&& get_socket_type () == SOCK_STREAM)
|
||||
{
|
||||
set_errno (EPIPE);
|
||||
if (!nosignal)
|
||||
raise (SIGPIPE);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fhandler_socket_local::sendto (const void *in_ptr, size_t len, int flags,
|
||||
const struct sockaddr *to, int tolen)
|
||||
@@ -1578,48 +1284,6 @@ fhandler_socket_local::sendmsg (const struct msghdr *msg, int flags)
|
||||
return send_internal (&wsamsg, flags);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fhandler_socket_local::write (const void *in_ptr, size_t len)
|
||||
{
|
||||
char *ptr = (char *) in_ptr;
|
||||
|
||||
#ifdef __x86_64__
|
||||
/* size_t is 64 bit, but the len member in WSABUF is 32 bit.
|
||||
Split buffer if necessary. */
|
||||
DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0);
|
||||
WSABUF wsabuf[bufcnt];
|
||||
WSAMSG wsamsg = { NULL, 0, wsabuf, bufcnt, { 0, NULL }, 0 };
|
||||
/* Don't use len as loop condition, it could be 0. */
|
||||
for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr)
|
||||
{
|
||||
wsaptr->len = MIN (len, UINT32_MAX);
|
||||
wsaptr->buf = ptr;
|
||||
len -= wsaptr->len;
|
||||
ptr += wsaptr->len;
|
||||
}
|
||||
#else
|
||||
WSABUF wsabuf = { len, ptr };
|
||||
WSAMSG wsamsg = { NULL, 0, &wsabuf, 1, { 0, NULL }, 0 };
|
||||
#endif
|
||||
return send_internal (&wsamsg, 0);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fhandler_socket_local::writev (const struct iovec *const iov, const int iovcnt,
|
||||
ssize_t tot)
|
||||
{
|
||||
WSABUF wsabuf[iovcnt];
|
||||
WSABUF *wsaptr = wsabuf;
|
||||
const struct iovec *iovptr = iov;
|
||||
for (int i = 0; i < iovcnt; ++i)
|
||||
{
|
||||
wsaptr->len = iovptr->iov_len;
|
||||
(wsaptr++)->buf = (char *) (iovptr++)->iov_base;
|
||||
}
|
||||
WSAMSG wsamsg = { NULL, 0, wsabuf, (DWORD) iovcnt, { 0, NULL}, 0 };
|
||||
return send_internal (&wsamsg, 0);
|
||||
}
|
||||
|
||||
void
|
||||
fhandler_socket_local::set_sun_path (const char *path)
|
||||
{
|
||||
@@ -1907,86 +1571,3 @@ fhandler_socket_local::getsockopt (int level, int optname, const void *optval,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_socket_local::ioctl (unsigned int cmd, void *p)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* FIXME: These have to be handled differently in future. */
|
||||
case FIOASYNC:
|
||||
#ifdef __x86_64__
|
||||
case _IOW('f', 125, u_long):
|
||||
#endif
|
||||
res = WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO,
|
||||
*(int *) p ? ASYNC_MASK : 0);
|
||||
syscall_printf ("Async I/O on socket %s",
|
||||
*(int *) p ? "started" : "cancelled");
|
||||
async_io (*(int *) p != 0);
|
||||
/* If async_io is switched off, revert the event handling. */
|
||||
if (*(int *) p == 0)
|
||||
WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK);
|
||||
break;
|
||||
case FIONREAD:
|
||||
#ifdef __x86_64__
|
||||
case _IOR('f', 127, u_long):
|
||||
#endif
|
||||
/* Make sure to use the Winsock definition of FIONREAD. */
|
||||
res = ::ioctlsocket (get_socket (), _IOR('f', 127, u_long), (u_long *) p);
|
||||
if (res == SOCKET_ERROR)
|
||||
set_winsock_errno ();
|
||||
break;
|
||||
case FIONBIO:
|
||||
case SIOCATMARK:
|
||||
/* Sockets are always non-blocking internally. So we just note the
|
||||
state here. */
|
||||
#ifdef __x86_64__
|
||||
/* Convert the different idea of u_long in the definition of cmd. */
|
||||
if (((cmd >> 16) & IOCPARM_MASK) == sizeof (unsigned long))
|
||||
cmd = (cmd & ~(IOCPARM_MASK << 16)) | (sizeof (u_long) << 16);
|
||||
#endif
|
||||
if (cmd == FIONBIO)
|
||||
{
|
||||
syscall_printf ("socket is now %sblocking",
|
||||
*(int *) p ? "non" : "");
|
||||
set_nonblocking (*(int *) p);
|
||||
res = 0;
|
||||
}
|
||||
else
|
||||
res = ::ioctlsocket (get_socket (), cmd, (u_long *) p);
|
||||
break;
|
||||
default:
|
||||
res = fhandler_socket::ioctl (cmd, p);
|
||||
break;
|
||||
}
|
||||
syscall_printf ("%d = ioctl_socket(%x, %p)", res, cmd, p);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_socket_local::fcntl (int cmd, intptr_t arg)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case F_SETOWN:
|
||||
{
|
||||
pid_t pid = (pid_t) arg;
|
||||
LOCK_EVENTS;
|
||||
wsock_events->owner = pid;
|
||||
UNLOCK_EVENTS;
|
||||
debug_printf ("owner set to %d", pid);
|
||||
}
|
||||
break;
|
||||
case F_GETOWN:
|
||||
res = wsock_events->owner;
|
||||
break;
|
||||
default:
|
||||
res = fhandler_socket::fcntl (cmd, arg);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user