/* winsock.c --- wrappers for Windows socket functions
Copyright (C) 2008 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/* Written by Paolo Bonzini */
#include
#include
#include
#include
#include
#include
#include
#undef close
#undef socket
#undef connect
#undef accept
#undef bind
#undef getpeername
#undef getsockname
#undef getsockopt
#undef listen
#undef recv
#undef send
#undef recvfrom
#undef sendto
#undef setsockopt
# define FD_TO_SOCKET(fd) ((SOCKET) _get_osfhandle ((fd)))
# define SOCKET_TO_FD(fh) (_open_osfhandle ((long) (fh), O_RDWR | O_BINARY))
/* Wrappers for libc functions. */
int
rpl_close (int fd)
{
SOCKET sock = FD_TO_SOCKET (fd);
WSANETWORKEVENTS ev;
ev.lNetworkEvents = 0xDEADBEEF;
WSAEnumNetworkEvents (sock, NULL, &ev);
if (ev.lNetworkEvents != 0xDEADBEEF)
{
/* FIXME: other applications, like squid, use an undocumented
_free_osfhnd free function. Instead, here we just close twice
the file descriptor. I could not get the former to work
(pb, Sep 22 2008). */
int r = closesocket (sock);
_close (fd);
return r;
}
else
return _close (fd);
}
/* Wrappers for WinSock functions. */
static inline void
set_winsock_errno (void)
{
int err = WSAGetLastError ();
WSASetLastError (0);
/* Map some WSAE* errors to the runtime library's error codes. */
switch (err)
{
case WSA_INVALID_HANDLE:
errno = EBADF;
break;
case WSA_NOT_ENOUGH_MEMORY:
errno = ENOMEM;
break;
case WSA_INVALID_PARAMETER:
errno = EINVAL;
break;
case WSAEWOULDBLOCK:
errno = EWOULDBLOCK;
break;
case WSAENAMETOOLONG:
errno = ENAMETOOLONG;
break;
case WSAENOTEMPTY:
errno = ENOTEMPTY;
break;
default:
errno = (err > 10000 && err < 10025) ? err - 10000 : err;
break;
}
}
#if GNULIB_SOCKET
int
rpl_socket (int domain, int type, int protocol)
{
/* We have to use WSASocket() to create non-overlapped IO sockets.
Overlapped IO sockets cannot be used with read/write. */
SOCKET fh = WSASocket (domain, type, protocol, NULL, 0, 0);
if (fh == INVALID_SOCKET)
{
set_winsock_errno ();
return -1;
}
else
return SOCKET_TO_FD (fh);
}
#endif
#if GNULIB_CONNECT
int
rpl_connect (int fd, struct sockaddr *sockaddr, int len)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = connect (sock, sockaddr, len);
if (r < 0)
{
/* EINPROGRESS is not returned by WinSock 2.0; for backwards
compatibility, connect(2) uses EWOULDBLOCK. */
if (WSAGetLastError () == WSAEWOULDBLOCK)
WSASetLastError (WSAEINPROGRESS);
set_winsock_errno ();
}
return r;
}
#endif
#if GNULIB_ACCEPT
int
rpl_accept (int fd, struct sockaddr *addr, int *addrlen)
{
SOCKET fh = accept (FD_TO_SOCKET (fd), addr, addrlen);
if (fh == INVALID_SOCKET)
{
set_winsock_errno ();
return -1;
}
else
return SOCKET_TO_FD (fh);
}
#endif
#if GNULIB_BIND
int
rpl_bind (int fd, struct sockaddr *sockaddr, int len)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = bind (sock, sockaddr, len);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_GETPEERNAME
int
rpl_getpeername (int fd, struct sockaddr *addr, int *addrlen)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = getpeername (sock, addr, addrlen);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_GETSOCKNAME
int
rpl_getsockname (int fd, struct sockaddr *addr, int *addrlen)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = getsockname (sock, addr, addrlen);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_GETSOCKOPT
int
rpl_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = getsockopt (sock, level, optname, optval, optlen);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_LISTEN
int
rpl_listen (int fd, int backlog)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = listen (sock, backlog);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
int
rpl_ioctl (int fd, unsigned long req, char *buf)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = ioctlsocket (sock, req, (void *) buf);
if (r < 0)
set_winsock_errno ();
return r;
}
#if GNULIB_RECV
int
rpl_recv (int fd, void *buf, int len, int flags)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = recv (sock, buf, len, flags);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_SEND
int
rpl_send (int fd, const void *buf, int len, int flags)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = send (sock, buf, len, flags);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_RECVFROM
int
rpl_recvfrom (int fd, void *buf, int len, int flags, struct sockaddr *from,
int *fromlen)
{
int frombufsize = *fromlen;
SOCKET sock = FD_TO_SOCKET (fd);
int r = recvfrom (sock, buf, len, flags, from, fromlen);
if (r < 0)
set_winsock_errno ();
/* Winsock recvfrom() only returns a valid 'from' when the socket is
connectionless. POSIX gives a valid 'from' for all types of sockets. */
else if (*fromlen == frombufsize)
rpl_getpeername (fd, from, fromlen);
return r;
}
#endif
#if GNULIB_SENDTO
int
rpl_sendto (int fd, const void *buf, int len, int flags,
struct sockaddr *to, int tolen)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = sendto (sock, buf, len, flags, to, tolen);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif
#if GNULIB_SETSOCKOPT
int
rpl_setsockopt (int fd, int level, int optname, const void *optval, int optlen)
{
SOCKET sock = FD_TO_SOCKET (fd);
int r = setsockopt (sock, level, optname, optval, optlen);
if (r < 0)
set_winsock_errno ();
return r;
}
#endif