changeset 30157:27e770162c3f

add sockets wrappers 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.
author Paolo Bonzini <bonzini@gnu.org>
date Fri, 12 Sep 2008 08:43:03 +0200
parents c47a6f165a9a
children 680a8ef0afb2
files ChangeLog lib/sys_socket.in.h lib/winsock.c m4/sys_socket_h.m4 modules/poll-tests modules/sys_socket tests/test-poll.c
diffstat 7 files changed, 385 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Sep 22 18:30:44 2008 +0200
+++ b/ChangeLog	Fri Sep 12 08:43:03 2008 +0200
@@ -1,3 +1,16 @@
+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.
--- a/lib/sys_socket.in.h	Mon Sep 22 18:30:44 2008 +0200
+++ b/lib/sys_socket.in.h	Fri Sep 12 08:43:03 2008 +0200
@@ -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 */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/winsock.c	Fri Sep 12 08:43:03 2008 +0200
@@ -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;
+}
--- a/m4/sys_socket_h.m4	Mon Sep 22 18:30:44 2008 +0200
+++ b/m4/sys_socket_h.m4	Fri Sep 12 08:43:03 2008 +0200
@@ -64,6 +64,9 @@
         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])
--- a/modules/poll-tests	Mon Sep 22 18:30:44 2008 +0200
+++ b/modules/poll-tests	Fri Sep 12 08:43:03 2008 +0200
@@ -8,6 +8,8 @@
 arpa_inet
 extensions
 inet_pton
+errno
+perror
 sockets
 
 configure.ac:
--- a/modules/sys_socket	Mon Sep 22 18:30:44 2008 +0200
+++ b/modules/sys_socket	Fri Sep 12 08:43:03 2008 +0200
@@ -3,6 +3,7 @@
 
 Files:
 lib/sys_socket.in.h
+lib/winsock.c
 m4/sys_socket_h.m4
 m4/sockpfaf.m4
 
--- a/tests/test-poll.c	Mon Sep 22 18:30:44 2008 +0200
+++ b/tests/test-poll.c	Fri Sep 12 08:43:03 2008 +0200
@@ -129,7 +129,7 @@
     {
 #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);