summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--lib/sys_socket.in.h86
-rw-r--r--lib/winsock.c285
-rw-r--r--m4/sys_socket_h.m43
-rw-r--r--modules/poll-tests2
-rw-r--r--modules/sys_socket1
-rw-r--r--tests/test-poll.c2
7 files changed, 385 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index b4f29c71a2..f8bf89fae2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2008-09-23 Paolo Bonzini <bonzini@gnu.org>
+ * lib/sys_socket.in.h: Do not implement rpl_setsockopt here,
+ instead define prototypes for a full set of wrappers. Ensure
+ that Cygwin does not use the compatibility code, which is only
+ for MinGW.
+ * lib/winsock.c: New.
+ * m4/sys_socket_h.m4: Compile lib/winsock.c if WinSock is being used.
+ * modules/sys_socket: Add lib/winsock.c.
+
+ * modules/poll-tests: Add errno and perror.
+ * tests/test-poll.c: Use ioctl, not ioctlsocket.
+
+2008-09-23 Paolo Bonzini <bonzini@gnu.org>
+
* tests/test-poll.c: Downgrade minimum needed Winsock version.
2008-09-23 Bruno Haible <bruno@clisp.org>
diff --git a/lib/sys_socket.in.h b/lib/sys_socket.in.h
index 6cf3f47774..53c71956b6 100644
--- a/lib/sys_socket.in.h
+++ b/lib/sys_socket.in.h
@@ -58,6 +58,10 @@
#else
+# ifdef __CYGWIN__
+# error "Cygwin does have a sys/socket.h, doesn't it?!?"
+# endif
+
/* A platform that lacks <sys/socket.h>.
Currently only MinGW is supported. See the gnulib manual regarding
@@ -94,15 +98,85 @@
# define SHUT_RDWR SD_BOTH
# endif
-# if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
-# define setsockopt(a,b,c,d,e) rpl_setsockopt(a,b,c,d,e)
+# if @HAVE_WINSOCK2_H@
+/* Include headers needed by the emulation code. */
+# include <sys/types.h>
+# include <io.h>
+
+typedef int socklen_t;
+
+/* Re-define FD_ISSET to avoid a WSA call while we are not using
+ network sockets. */
static inline int
-rpl_setsockopt(int socket, int level, int optname, const void *optval,
- socklen_t optlen)
+rpl_fd_isset (int fd, fd_set * set)
{
- return (setsockopt)(socket, level, optname, optval, optlen);
+ int i;
+ if (set == NULL)
+ return 0;
+
+ for (i = 0; i < set->fd_count; i++)
+ if (set->fd_array[i] == fd)
+ return 1;
+
+ return 0;
}
-# endif
+
+# undef FD_ISSET
+# define FD_ISSET(fd, set) rpl_fd_isset(fd, set)
+
+/* Wrap everything else to use libc file descriptors for sockets. */
+
+# undef close
+# define close rpl_close
+# undef socket
+# define socket rpl_socket
+# undef connect
+# define connect rpl_connect
+# undef accept
+# define accept rpl_accept
+# undef bind
+# define bind rpl_bind
+# undef getpeername
+# define getpeername rpl_getpeername
+# undef getsockname
+# define getsockname rpl_getsockname
+# undef getsockopt
+# define getsockopt rpl_getsockopt
+# undef listen
+# define listen rpl_listen
+# undef ioctl
+# define ioctl rpl_ioctl
+# undef recv
+# define recv rpl_recv
+# undef send
+# define send rpl_send
+# undef recvfrom
+# define recvfrom rpl_recvfrom
+# undef sendto
+# define sendto rpl_sendto
+# undef setsockopt
+# define setsockopt rpl_setsockopt
+
+# undef select
+# define select select_not_supported_under_win32_use_poll
+
+extern int rpl_close(int);
+extern int rpl_socket (int, int, int protocol);
+extern int rpl_connect (int, struct sockaddr *, int);
+extern int rpl_accept (int, struct sockaddr *, int *);
+extern int rpl_bind (int, struct sockaddr *, int);
+extern int rpl_getpeername (int, struct sockaddr *, int *);
+extern int rpl_getsockname (int, struct sockaddr *, int *);
+extern int rpl_getsockopt (int, int, int, void *, int *);
+extern int rpl_listen (int, int);
+extern int rpl_ioctl (int, unsigned long, char *);
+extern int rpl_recv (int, void *, int, int);
+extern int rpl_send (int, const void *, int, int);
+extern int rpl_recvfrom (int, void *, int, int, struct sockaddr *, int *);
+extern int rpl_sendto (int, const void *, int, int, struct sockaddr *, int);
+extern int rpl_setsockopt (int, int, int, const void *, int);
+
+# endif /* HAVE_WINSOCK2_H */
#endif /* HAVE_SYS_SOCKET_H */
diff --git a/lib/winsock.c b/lib/winsock.c
new file mode 100644
index 0000000000..51fecf1800
--- /dev/null
+++ b/lib/winsock.c
@@ -0,0 +1,285 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+/* Written by Paolo Bonzini */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/socket.h>
+
+#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
+#undef strerror
+
+# 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)
+{
+ char buf[sizeof (int)];
+ int bufsize = sizeof (buf);
+ 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 WSAENAMETOOLONG:
+ errno = ENAMETOOLONG;
+ break;
+ case WSAENOTEMPTY:
+ errno = ENOTEMPTY;
+ break;
+ default:
+ errno = (err > 10000 && err < 10025) ? err - 10000 : err;
+ break;
+ }
+}
+
+int
+rpl_socket (int domain, int type, int protocol)
+{
+ int fd;
+
+ /* 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);
+}
+
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
diff --git a/m4/sys_socket_h.m4 b/m4/sys_socket_h.m4
index 2e4e2f6835..6a5b349930 100644
--- a/m4/sys_socket_h.m4
+++ b/m4/sys_socket_h.m4
@@ -64,6 +64,9 @@ AC_DEFUN([gl_HEADER_SYS_SOCKET],
HAVE_WS2TCPIP_H=0
fi
fi
+ if test x$ac_cv_header_winsock2_h = xyes; then
+ AC_LIBOBJ(winsock)
+ fi
AC_SUBST([HAVE_SYS_SOCKET_H])
AC_SUBST([HAVE_WINSOCK2_H])
AC_SUBST([HAVE_WS2TCPIP_H])
diff --git a/modules/poll-tests b/modules/poll-tests
index 33e277f6ac..1fa37bff09 100644
--- a/modules/poll-tests
+++ b/modules/poll-tests
@@ -8,6 +8,8 @@ netinet_in
arpa_inet
extensions
inet_pton
+errno
+perror
sockets
configure.ac:
diff --git a/modules/sys_socket b/modules/sys_socket
index d619a548cd..27ee5d881b 100644
--- a/modules/sys_socket
+++ b/modules/sys_socket
@@ -3,6 +3,7 @@ A POSIX-like <sys/socket.h>.
Files:
lib/sys_socket.in.h
+lib/winsock.c
m4/sys_socket_h.m4
m4/sockpfaf.m4
diff --git a/tests/test-poll.c b/tests/test-poll.c
index 8e9332afe7..b0cdb6087a 100644
--- a/tests/test-poll.c
+++ b/tests/test-poll.c
@@ -129,7 +129,7 @@ connect_to_socket (int blocking)
{
#ifdef WIN32_NATIVE
unsigned long iMode = 1;
- ioctlsocket (s, FIONBIO, (void *) &iMode);
+ ioctl (s, FIONBIO, (char *) &iMode);
#elif defined F_GETFL
int oldflags = fcntl (s, F_GETFL, NULL);