Copy --version support from gnulib-tool to posix-modules.
[gnulib.git] / lib / winsock.c
1 /* winsock.c --- wrappers for Windows socket functions
2
3    Copyright (C) 2008 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 /* Written by Paolo Bonzini */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <io.h>
26 #include <sys/socket.h>
27
28 #undef close
29 #undef socket
30 #undef connect
31 #undef accept
32 #undef bind
33 #undef getpeername
34 #undef getsockname
35 #undef getsockopt
36 #undef listen
37 #undef recv
38 #undef send
39 #undef recvfrom
40 #undef sendto
41 #undef setsockopt
42 #undef strerror
43
44 # define FD_TO_SOCKET(fd)   ((SOCKET) _get_osfhandle ((fd)))
45 # define SOCKET_TO_FD(fh)   (_open_osfhandle ((long) (fh), O_RDWR | O_BINARY))
46
47
48 /* Wrappers for libc functions.  */
49
50 int
51 rpl_close (int fd)
52 {
53   char buf[sizeof (int)];
54   int bufsize = sizeof (buf);
55   SOCKET sock = FD_TO_SOCKET (fd);
56   WSANETWORKEVENTS ev;
57
58   ev.lNetworkEvents = 0xDEADBEEF;
59   WSAEnumNetworkEvents (sock, NULL, &ev);
60   if (ev.lNetworkEvents != 0xDEADBEEF)
61     {
62       /* FIXME: other applications, like squid, use an undocumented
63          _free_osfhnd free function.  Instead, here we just close twice
64          the file descriptor.  I could not get the former to work
65          (pb, Sep 22 2008).  */ 
66       int r = closesocket (sock);
67       _close (fd);
68       return r;
69     }
70   else
71     return _close (fd);
72 }
73
74
75 /* Wrappers for WinSock functions.  */
76
77 static inline void
78 set_winsock_errno (void)
79 {
80   int err = WSAGetLastError ();
81   WSASetLastError (0);
82
83   /* Map some WSAE* errors to the runtime library's error codes.  */
84   switch (err)
85     {
86     case WSA_INVALID_HANDLE:
87       errno = EBADF;
88       break;
89     case WSA_NOT_ENOUGH_MEMORY:
90       errno = ENOMEM;
91       break;
92     case WSA_INVALID_PARAMETER:
93       errno = EINVAL;
94       break;
95     case WSAENAMETOOLONG:
96       errno = ENAMETOOLONG;
97       break;
98     case WSAENOTEMPTY:
99       errno = ENOTEMPTY;
100       break;
101     default:
102       errno = (err > 10000 && err < 10025) ? err - 10000 : err;
103       break;
104     }
105 }
106
107 int
108 rpl_socket (int domain, int type, int protocol)
109 {
110   int fd;
111
112   /* We have to use WSASocket() to create non-overlapped IO sockets.
113      Overlapped IO sockets cannot be used with read/write.  */
114   SOCKET fh = WSASocket (domain, type, protocol, NULL, 0, 0);
115
116   if (fh == INVALID_SOCKET)
117     {
118       set_winsock_errno ();
119       return -1;
120     }
121   else
122     return SOCKET_TO_FD (fh);
123 }
124
125
126 int
127 rpl_connect (int fd, struct sockaddr *sockaddr, int len)
128 {
129   SOCKET sock = FD_TO_SOCKET (fd);
130   int r = connect (sock, sockaddr, len);
131   if (r < 0)
132     {
133       /* EINPROGRESS is not returned by WinSock 2.0; for backwards
134          compatibility, connect(2) uses EWOULDBLOCK.  */
135       if (WSAGetLastError () == WSAEWOULDBLOCK)
136         WSASetLastError (WSAEINPROGRESS);
137
138       set_winsock_errno ();
139     }
140
141   return r;
142 }
143
144 int
145 rpl_accept (int fd, struct sockaddr *addr, int *addrlen)
146 {
147   SOCKET fh = accept (FD_TO_SOCKET (fd), addr, addrlen);
148   if (fh == INVALID_SOCKET)
149     {
150       set_winsock_errno ();
151       return -1;
152     }
153   else
154     return SOCKET_TO_FD (fh);
155 }
156
157 int
158 rpl_bind (int fd, struct sockaddr *sockaddr, int len)
159 {
160   SOCKET sock = FD_TO_SOCKET (fd);
161   int r = bind (sock, sockaddr, len);
162   if (r < 0)
163     set_winsock_errno ();
164
165   return r;
166 }
167
168 int
169 rpl_getpeername (int fd, struct sockaddr *addr, int *addrlen)
170 {
171   SOCKET sock = FD_TO_SOCKET (fd);
172   int r = getpeername (sock, addr, addrlen);
173   if (r < 0)
174     set_winsock_errno ();
175
176   return r;
177 }
178
179 int
180 rpl_getsockname (int fd, struct sockaddr *addr, int *addrlen)
181 {
182   SOCKET sock = FD_TO_SOCKET (fd);
183   int r = getsockname (sock, addr, addrlen);
184   if (r < 0)
185     set_winsock_errno ();
186
187   return r;
188 }
189
190 int
191 rpl_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
192 {
193   SOCKET sock = FD_TO_SOCKET (fd);
194   int r = getsockopt (sock, level, optname, optval, optlen);
195   if (r < 0)
196     set_winsock_errno ();
197
198   return r;
199 }
200
201 int
202 rpl_listen (int fd, int backlog)
203 {
204   SOCKET sock = FD_TO_SOCKET (fd);
205   int r = listen (sock, backlog);
206   if (r < 0)
207     set_winsock_errno ();
208
209   return r;
210 }
211
212 int
213 rpl_ioctl (int fd, unsigned long req, char *buf)
214 {
215   SOCKET sock = FD_TO_SOCKET (fd);
216   int r = ioctlsocket (sock, req, (void *) buf);
217   if (r < 0)
218     set_winsock_errno ();
219
220   return r;
221 }
222
223 int
224 rpl_recv (int fd, void *buf, int len, int flags)
225 {
226   SOCKET sock = FD_TO_SOCKET (fd);
227   int r = recv (sock, buf, len, flags);
228   if (r < 0)
229     set_winsock_errno ();
230
231   return r;
232 }
233
234 int
235 rpl_send (int fd, const void *buf, int len, int flags)
236 {
237   SOCKET sock = FD_TO_SOCKET (fd);
238   int r = send (sock, buf, len, flags);
239   if (r < 0)
240     set_winsock_errno ();
241
242   return r;
243 }
244
245 int
246 rpl_recvfrom (int fd, void *buf, int len, int flags, struct sockaddr *from,
247               int *fromlen)
248 {
249   int frombufsize = *fromlen;
250   SOCKET sock = FD_TO_SOCKET (fd);
251   int r = recvfrom (sock, buf, len, flags, from, fromlen);
252
253   if (r < 0)
254     set_winsock_errno ();
255
256   /* Winsock recvfrom() only returns a valid 'from' when the socket is
257      connectionless.  POSIX gives a valid 'from' for all types of sockets.  */
258   else if (*fromlen == frombufsize)
259     rpl_getpeername (fd, from, fromlen);
260
261   return r;
262 }
263
264 int
265 rpl_sendto (int fd, const void *buf, int len, int flags,
266             struct sockaddr *to, int tolen)
267 {
268   SOCKET sock = FD_TO_SOCKET (fd);
269   int r = sendto (sock, buf, len, flags, to, tolen);
270   if (r < 0)
271     set_winsock_errno ();
272
273   return r;
274 }
275
276 int
277 rpl_setsockopt (int fd, int level, int optname, const void *optval, int optlen)
278 {
279   SOCKET sock = FD_TO_SOCKET (fd);
280   int r = setsockopt (sock, level, optname, optval, optlen);
281   if (r < 0)
282     set_winsock_errno ();
283
284   return r;
285 }