From: Paolo Bonzini Date: Fri, 12 Sep 2008 06:43:03 +0000 (+0200) Subject: add sockets wrappers X-Git-Tag: v0.1~7016 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=77041ebc885b2af4e2d48fd49cf5529759351076;p=gnulib.git add sockets wrappers 2008-09-23 Paolo Bonzini * 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. --- diff --git a/ChangeLog b/ChangeLog index b4f29c71a..f8bf89fae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 2008-09-23 Paolo Bonzini + * 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 + * tests/test-poll.c: Downgrade minimum needed Winsock version. 2008-09-23 Bruno Haible diff --git a/lib/sys_socket.in.h b/lib/sys_socket.in.h index 6cf3f4777..53c71956b 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 . 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 +# include + +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 000000000..51fecf180 --- /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 . */ + +/* 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 +#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 2e4e2f683..6a5b34993 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 33e277f6a..1fa37bff0 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 d619a548c..27ee5d881 100644 --- a/modules/sys_socket +++ b/modules/sys_socket @@ -3,6 +3,7 @@ A POSIX-like . 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 8e9332afe..b0cdb6087 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);