535145a813aac869044cba26876e33a4c5ecb796
[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 #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   SOCKET sock = FD_TO_SOCKET (fd);
55   WSANETWORKEVENTS ev;
56
57   ev.lNetworkEvents = 0xDEADBEEF;
58   WSAEnumNetworkEvents (sock, NULL, &ev);
59   if (ev.lNetworkEvents != 0xDEADBEEF)
60     {
61       /* FIXME: other applications, like squid, use an undocumented
62          _free_osfhnd free function.  Instead, here we just close twice
63          the file descriptor.  I could not get the former to work
64          (pb, Sep 22 2008).  */
65       int r = closesocket (sock);
66       _close (fd);
67       return r;
68     }
69   else
70     return _close (fd);
71 }
72
73
74 /* Wrappers for WinSock functions.  */
75
76 static inline void
77 set_winsock_errno (void)
78 {
79   int err = WSAGetLastError ();
80   WSASetLastError (0);
81
82   /* Map some WSAE* errors to the runtime library's error codes.  */
83   switch (err)
84     {
85     case WSA_INVALID_HANDLE:
86       errno = EBADF;
87       break;
88     case WSA_NOT_ENOUGH_MEMORY:
89       errno = ENOMEM;
90       break;
91     case WSA_INVALID_PARAMETER:
92       errno = EINVAL;
93       break;
94     case WSAENAMETOOLONG:
95       errno = ENAMETOOLONG;
96       break;
97     case WSAENOTEMPTY:
98       errno = ENOTEMPTY;
99       break;
100     default:
101       errno = (err > 10000 && err < 10025) ? err - 10000 : err;
102       break;
103     }
104 }
105
106 int
107 rpl_socket (int domain, int type, int protocol)
108 {
109   /* We have to use WSASocket() to create non-overlapped IO sockets.
110      Overlapped IO sockets cannot be used with read/write.  */
111   SOCKET fh = WSASocket (domain, type, protocol, NULL, 0, 0);
112
113   if (fh == INVALID_SOCKET)
114     {
115       set_winsock_errno ();
116       return -1;
117     }
118   else
119     return SOCKET_TO_FD (fh);
120 }
121
122
123 int
124 rpl_connect (int fd, struct sockaddr *sockaddr, int len)
125 {
126   SOCKET sock = FD_TO_SOCKET (fd);
127   int r = connect (sock, sockaddr, len);
128   if (r < 0)
129     {
130       /* EINPROGRESS is not returned by WinSock 2.0; for backwards
131          compatibility, connect(2) uses EWOULDBLOCK.  */
132       if (WSAGetLastError () == WSAEWOULDBLOCK)
133         WSASetLastError (WSAEINPROGRESS);
134
135       set_winsock_errno ();
136     }
137
138   return r;
139 }
140
141 int
142 rpl_accept (int fd, struct sockaddr *addr, int *addrlen)
143 {
144   SOCKET fh = accept (FD_TO_SOCKET (fd), addr, addrlen);
145   if (fh == INVALID_SOCKET)
146     {
147       set_winsock_errno ();
148       return -1;
149     }
150   else
151     return SOCKET_TO_FD (fh);
152 }
153
154 int
155 rpl_bind (int fd, struct sockaddr *sockaddr, int len)
156 {
157   SOCKET sock = FD_TO_SOCKET (fd);
158   int r = bind (sock, sockaddr, len);
159   if (r < 0)
160     set_winsock_errno ();
161
162   return r;
163 }
164
165 int
166 rpl_getpeername (int fd, struct sockaddr *addr, int *addrlen)
167 {
168   SOCKET sock = FD_TO_SOCKET (fd);
169   int r = getpeername (sock, addr, addrlen);
170   if (r < 0)
171     set_winsock_errno ();
172
173   return r;
174 }
175
176 int
177 rpl_getsockname (int fd, struct sockaddr *addr, int *addrlen)
178 {
179   SOCKET sock = FD_TO_SOCKET (fd);
180   int r = getsockname (sock, addr, addrlen);
181   if (r < 0)
182     set_winsock_errno ();
183
184   return r;
185 }
186
187 int
188 rpl_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
189 {
190   SOCKET sock = FD_TO_SOCKET (fd);
191   int r = getsockopt (sock, level, optname, optval, optlen);
192   if (r < 0)
193     set_winsock_errno ();
194
195   return r;
196 }
197
198 int
199 rpl_listen (int fd, int backlog)
200 {
201   SOCKET sock = FD_TO_SOCKET (fd);
202   int r = listen (sock, backlog);
203   if (r < 0)
204     set_winsock_errno ();
205
206   return r;
207 }
208
209 int
210 rpl_ioctl (int fd, unsigned long req, char *buf)
211 {
212   SOCKET sock = FD_TO_SOCKET (fd);
213   int r = ioctlsocket (sock, req, (void *) buf);
214   if (r < 0)
215     set_winsock_errno ();
216
217   return r;
218 }
219
220 int
221 rpl_recv (int fd, void *buf, int len, int flags)
222 {
223   SOCKET sock = FD_TO_SOCKET (fd);
224   int r = recv (sock, buf, len, flags);
225   if (r < 0)
226     set_winsock_errno ();
227
228   return r;
229 }
230
231 int
232 rpl_send (int fd, const void *buf, int len, int flags)
233 {
234   SOCKET sock = FD_TO_SOCKET (fd);
235   int r = send (sock, buf, len, flags);
236   if (r < 0)
237     set_winsock_errno ();
238
239   return r;
240 }
241
242 int
243 rpl_recvfrom (int fd, void *buf, int len, int flags, struct sockaddr *from,
244               int *fromlen)
245 {
246   int frombufsize = *fromlen;
247   SOCKET sock = FD_TO_SOCKET (fd);
248   int r = recvfrom (sock, buf, len, flags, from, fromlen);
249
250   if (r < 0)
251     set_winsock_errno ();
252
253   /* Winsock recvfrom() only returns a valid 'from' when the socket is
254      connectionless.  POSIX gives a valid 'from' for all types of sockets.  */
255   else if (*fromlen == frombufsize)
256     rpl_getpeername (fd, from, fromlen);
257
258   return r;
259 }
260
261 int
262 rpl_sendto (int fd, const void *buf, int len, int flags,
263             struct sockaddr *to, int tolen)
264 {
265   SOCKET sock = FD_TO_SOCKET (fd);
266   int r = sendto (sock, buf, len, flags, to, tolen);
267   if (r < 0)
268     set_winsock_errno ();
269
270   return r;
271 }
272
273 int
274 rpl_setsockopt (int fd, int level, int optname, const void *optval, int optlen)
275 {
276   SOCKET sock = FD_TO_SOCKET (fd);
277   int r = setsockopt (sock, level, optname, optval, optlen);
278   if (r < 0)
279     set_winsock_errno ();
280
281   return r;
282 }