Tiny tweaks.
[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 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
43 # define FD_TO_SOCKET(fd)   ((SOCKET) _get_osfhandle ((fd)))
44 # define SOCKET_TO_FD(fh)   (_open_osfhandle ((long) (fh), O_RDWR | O_BINARY))
45
46
47 /* Wrappers for libc functions.  */
48
49 int
50 rpl_close (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
71
72 /* Wrappers for WinSock functions.  */
73
74 static inline void
75 set_winsock_errno (void)
76 {
77   int err = WSAGetLastError ();
78   WSASetLastError (0);
79
80   /* Map some WSAE* errors to the runtime library's error codes.  */
81   switch (err)
82     {
83     case WSA_INVALID_HANDLE:
84       errno = EBADF;
85       break;
86     case WSA_NOT_ENOUGH_MEMORY:
87       errno = ENOMEM;
88       break;
89     case WSA_INVALID_PARAMETER:
90       errno = EINVAL;
91       break;
92     case WSAEWOULDBLOCK:
93       errno = EWOULDBLOCK;
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   /* We have to use WSASocket() to create non-overlapped IO sockets.
111      Overlapped IO sockets cannot be used with read/write.  */
112   SOCKET fh = WSASocket (domain, type, protocol, NULL, 0, 0);
113
114   if (fh == INVALID_SOCKET)
115     {
116       set_winsock_errno ();
117       return -1;
118     }
119   else
120     return SOCKET_TO_FD (fh);
121 }
122
123
124 int
125 rpl_connect (int fd, struct sockaddr *sockaddr, int len)
126 {
127   SOCKET sock = FD_TO_SOCKET (fd);
128   int r = connect (sock, sockaddr, len);
129   if (r < 0)
130     {
131       /* EINPROGRESS is not returned by WinSock 2.0; for backwards
132          compatibility, connect(2) uses EWOULDBLOCK.  */
133       if (WSAGetLastError () == WSAEWOULDBLOCK)
134         WSASetLastError (WSAEINPROGRESS);
135
136       set_winsock_errno ();
137     }
138
139   return r;
140 }
141
142 int
143 rpl_accept (int fd, struct sockaddr *addr, int *addrlen)
144 {
145   SOCKET fh = accept (FD_TO_SOCKET (fd), addr, addrlen);
146   if (fh == INVALID_SOCKET)
147     {
148       set_winsock_errno ();
149       return -1;
150     }
151   else
152     return SOCKET_TO_FD (fh);
153 }
154
155 int
156 rpl_bind (int fd, struct sockaddr *sockaddr, int len)
157 {
158   SOCKET sock = FD_TO_SOCKET (fd);
159   int r = bind (sock, sockaddr, len);
160   if (r < 0)
161     set_winsock_errno ();
162
163   return r;
164 }
165
166 int
167 rpl_getpeername (int fd, struct sockaddr *addr, int *addrlen)
168 {
169   SOCKET sock = FD_TO_SOCKET (fd);
170   int r = getpeername (sock, addr, addrlen);
171   if (r < 0)
172     set_winsock_errno ();
173
174   return r;
175 }
176
177 int
178 rpl_getsockname (int fd, struct sockaddr *addr, int *addrlen)
179 {
180   SOCKET sock = FD_TO_SOCKET (fd);
181   int r = getsockname (sock, addr, addrlen);
182   if (r < 0)
183     set_winsock_errno ();
184
185   return r;
186 }
187
188 int
189 rpl_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
190 {
191   SOCKET sock = FD_TO_SOCKET (fd);
192   int r = getsockopt (sock, level, optname, optval, optlen);
193   if (r < 0)
194     set_winsock_errno ();
195
196   return r;
197 }
198
199 int
200 rpl_listen (int fd, int backlog)
201 {
202   SOCKET sock = FD_TO_SOCKET (fd);
203   int r = listen (sock, backlog);
204   if (r < 0)
205     set_winsock_errno ();
206
207   return r;
208 }
209
210 int
211 rpl_ioctl (int fd, unsigned long req, char *buf)
212 {
213   SOCKET sock = FD_TO_SOCKET (fd);
214   int r = ioctlsocket (sock, req, (void *) buf);
215   if (r < 0)
216     set_winsock_errno ();
217
218   return r;
219 }
220
221 int
222 rpl_recv (int fd, void *buf, int len, int flags)
223 {
224   SOCKET sock = FD_TO_SOCKET (fd);
225   int r = recv (sock, buf, len, flags);
226   if (r < 0)
227     set_winsock_errno ();
228
229   return r;
230 }
231
232 int
233 rpl_send (int fd, const void *buf, int len, int flags)
234 {
235   SOCKET sock = FD_TO_SOCKET (fd);
236   int r = send (sock, buf, len, flags);
237   if (r < 0)
238     set_winsock_errno ();
239
240   return r;
241 }
242
243 int
244 rpl_recvfrom (int fd, void *buf, int len, int flags, struct sockaddr *from,
245               int *fromlen)
246 {
247   int frombufsize = *fromlen;
248   SOCKET sock = FD_TO_SOCKET (fd);
249   int r = recvfrom (sock, buf, len, flags, from, fromlen);
250
251   if (r < 0)
252     set_winsock_errno ();
253
254   /* Winsock recvfrom() only returns a valid 'from' when the socket is
255      connectionless.  POSIX gives a valid 'from' for all types of sockets.  */
256   else if (*fromlen == frombufsize)
257     rpl_getpeername (fd, from, fromlen);
258
259   return r;
260 }
261
262 int
263 rpl_sendto (int fd, const void *buf, int len, int flags,
264             struct sockaddr *to, int tolen)
265 {
266   SOCKET sock = FD_TO_SOCKET (fd);
267   int r = sendto (sock, buf, len, flags, to, tolen);
268   if (r < 0)
269     set_winsock_errno ();
270
271   return r;
272 }
273
274 int
275 rpl_setsockopt (int fd, int level, int optname, const void *optval, int optlen)
276 {
277   SOCKET sock = FD_TO_SOCKET (fd);
278   int r = setsockopt (sock, level, optname, optval, optlen);
279   if (r < 0)
280     set_winsock_errno ();
281
282   return r;
283 }