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