* lib/fclose.c: Fix typo in comment: s/close/fclose/.
[pspp] / 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 <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <io.h>
27 #include <sys/socket.h>
28 #if GNULIB_IOCTL
29 #include <sys/ioctl.h>
30 #endif
31
32 #undef socket
33 #undef connect
34 #undef accept
35 #undef bind
36 #undef getpeername
37 #undef getsockname
38 #undef getsockopt
39 #undef listen
40 #undef recv
41 #undef send
42 #undef recvfrom
43 #undef sendto
44 #undef setsockopt
45
46 # define FD_TO_SOCKET(fd)   ((SOCKET) _get_osfhandle ((fd)))
47 # define SOCKET_TO_FD(fh)   (_open_osfhandle ((long) (fh), O_RDWR | O_BINARY))
48
49
50 static inline void
51 set_winsock_errno (void)
52 {
53   int err = WSAGetLastError ();
54   WSASetLastError (0);
55
56   /* Map some WSAE* errors to the runtime library's error codes.  */
57   switch (err)
58     {
59     case WSA_INVALID_HANDLE:
60       errno = EBADF;
61       break;
62     case WSA_NOT_ENOUGH_MEMORY:
63       errno = ENOMEM;
64       break;
65     case WSA_INVALID_PARAMETER:
66       errno = EINVAL;
67       break;
68     case WSAEWOULDBLOCK:
69       errno = EWOULDBLOCK;
70       break;
71     case WSAENAMETOOLONG:
72       errno = ENAMETOOLONG;
73       break;
74     case WSAENOTEMPTY:
75       errno = ENOTEMPTY;
76       break;
77     default:
78       errno = (err > 10000 && err < 10025) ? err - 10000 : err;
79       break;
80     }
81 }
82
83
84 /* Hook for gnulib module close.  */
85
86 #if HAVE__GL_CLOSE_FD_MAYBE_SOCKET
87 int
88 _gl_close_fd_maybe_socket (int fd)
89 {
90   SOCKET sock = FD_TO_SOCKET (fd);
91   WSANETWORKEVENTS ev;
92
93   ev.lNetworkEvents = 0xDEADBEEF;
94   WSAEnumNetworkEvents (sock, NULL, &ev);
95   if (ev.lNetworkEvents != 0xDEADBEEF)
96     {
97       /* FIXME: other applications, like squid, use an undocumented
98          _free_osfhnd free function.  But this is not enough: The 'osfile'
99          flags for fd also needs to be cleared, but it is hard to access it.
100          Instead, here we just close twice the file descriptor.  */
101       if (closesocket (sock))
102         {
103           set_winsock_errno ();
104           return -1;
105         }
106       else
107         {
108           /* This call frees the file descriptor and does a
109              CloseHandle ((HANDLE) _get_osfhandle (fd)), which fails.  */
110           _close (fd);
111           return 0;
112         }
113     }
114   else
115     return _close (fd);
116 }
117 #endif
118
119
120 /* Wrappers for WinSock functions.  */
121
122 #if GNULIB_SOCKET
123 int
124 rpl_socket (int domain, int type, int protocol)
125 {
126   /* We have to use WSASocket() to create non-overlapped IO sockets.
127      Overlapped IO sockets cannot be used with read/write.  */
128   SOCKET fh = WSASocket (domain, type, protocol, NULL, 0, 0);
129
130   if (fh == INVALID_SOCKET)
131     {
132       set_winsock_errno ();
133       return -1;
134     }
135   else
136     return SOCKET_TO_FD (fh);
137 }
138 #endif
139
140 #if GNULIB_CONNECT
141 int
142 rpl_connect (int fd, struct sockaddr *sockaddr, int len)
143 {
144   SOCKET sock = FD_TO_SOCKET (fd);
145   int r = connect (sock, sockaddr, len);
146   if (r < 0)
147     {
148       /* EINPROGRESS is not returned by WinSock 2.0; for backwards
149          compatibility, connect(2) uses EWOULDBLOCK.  */
150       if (WSAGetLastError () == WSAEWOULDBLOCK)
151         WSASetLastError (WSAEINPROGRESS);
152
153       set_winsock_errno ();
154     }
155
156   return r;
157 }
158 #endif
159
160 #if GNULIB_ACCEPT
161 int
162 rpl_accept (int fd, struct sockaddr *addr, int *addrlen)
163 {
164   SOCKET fh = accept (FD_TO_SOCKET (fd), addr, addrlen);
165   if (fh == INVALID_SOCKET)
166     {
167       set_winsock_errno ();
168       return -1;
169     }
170   else
171     return SOCKET_TO_FD (fh);
172 }
173 #endif
174
175 #if GNULIB_BIND
176 int
177 rpl_bind (int fd, struct sockaddr *sockaddr, int len)
178 {
179   SOCKET sock = FD_TO_SOCKET (fd);
180   int r = bind (sock, sockaddr, len);
181   if (r < 0)
182     set_winsock_errno ();
183
184   return r;
185 }
186 #endif
187
188 #if GNULIB_GETPEERNAME
189 int
190 rpl_getpeername (int fd, struct sockaddr *addr, int *addrlen)
191 {
192   SOCKET sock = FD_TO_SOCKET (fd);
193   int r = getpeername (sock, addr, addrlen);
194   if (r < 0)
195     set_winsock_errno ();
196
197   return r;
198 }
199 #endif
200
201 #if GNULIB_GETSOCKNAME
202 int
203 rpl_getsockname (int fd, struct sockaddr *addr, int *addrlen)
204 {
205   SOCKET sock = FD_TO_SOCKET (fd);
206   int r = getsockname (sock, addr, addrlen);
207   if (r < 0)
208     set_winsock_errno ();
209
210   return r;
211 }
212 #endif
213
214 #if GNULIB_GETSOCKOPT
215 int
216 rpl_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
217 {
218   SOCKET sock = FD_TO_SOCKET (fd);
219   int r = getsockopt (sock, level, optname, optval, optlen);
220   if (r < 0)
221     set_winsock_errno ();
222
223   return r;
224 }
225 #endif
226
227 #if GNULIB_LISTEN
228 int
229 rpl_listen (int fd, int backlog)
230 {
231   SOCKET sock = FD_TO_SOCKET (fd);
232   int r = listen (sock, backlog);
233   if (r < 0)
234     set_winsock_errno ();
235
236   return r;
237 }
238 #endif
239
240 #if GNULIB_IOCTL
241 int
242 rpl_ioctl (int fd, int req, ...)
243 {
244   void *buf;
245   va_list args;
246   SOCKET sock;
247   int r;
248
249   va_start (args, req);
250   buf = va_arg (args, void *);
251   va_end (args);
252
253   sock = FD_TO_SOCKET (fd);
254   r = ioctlsocket (sock, req, buf);
255   if (r < 0)
256     set_winsock_errno ();
257
258   return r;
259 }
260 #endif
261
262 #if GNULIB_RECV
263 int
264 rpl_recv (int fd, void *buf, int len, int flags)
265 {
266   SOCKET sock = FD_TO_SOCKET (fd);
267   int r = recv (sock, buf, len, flags);
268   if (r < 0)
269     set_winsock_errno ();
270
271   return r;
272 }
273 #endif
274
275 #if GNULIB_SEND
276 int
277 rpl_send (int fd, const void *buf, int len, int flags)
278 {
279   SOCKET sock = FD_TO_SOCKET (fd);
280   int r = send (sock, buf, len, flags);
281   if (r < 0)
282     set_winsock_errno ();
283
284   return r;
285 }
286 #endif
287
288 #if GNULIB_RECVFROM
289 int
290 rpl_recvfrom (int fd, void *buf, int len, int flags, struct sockaddr *from,
291               int *fromlen)
292 {
293   int frombufsize = *fromlen;
294   SOCKET sock = FD_TO_SOCKET (fd);
295   int r = recvfrom (sock, buf, len, flags, from, fromlen);
296
297   if (r < 0)
298     set_winsock_errno ();
299
300   /* Winsock recvfrom() only returns a valid 'from' when the socket is
301      connectionless.  POSIX gives a valid 'from' for all types of sockets.  */
302   else if (*fromlen == frombufsize)
303     rpl_getpeername (fd, from, fromlen);
304
305   return r;
306 }
307 #endif
308
309 #if GNULIB_SENDTO
310 int
311 rpl_sendto (int fd, const void *buf, int len, int flags,
312             struct sockaddr *to, int tolen)
313 {
314   SOCKET sock = FD_TO_SOCKET (fd);
315   int r = sendto (sock, buf, len, flags, to, tolen);
316   if (r < 0)
317     set_winsock_errno ();
318
319   return r;
320 }
321 #endif
322
323 #if GNULIB_SETSOCKOPT
324 int
325 rpl_setsockopt (int fd, int level, int optname, const void *optval, int optlen)
326 {
327   SOCKET sock = FD_TO_SOCKET (fd);
328   int r = setsockopt (sock, level, optname, optval, optlen);
329   if (r < 0)
330     set_winsock_errno ();
331
332   return r;
333 }
334 #endif