]> git.pond.sub.org Git - empserver/blob - src/lib/w32/w32sockets.c
318949d4bae01d737cd23c56267acea58488f8b7
[empserver] / src / lib / w32 / w32sockets.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  w32sockets.c: POSIX socket emulation layer for Windows
29  *
30  *  Known contributors to this file:
31  *     Ron Koenderink, 2007
32  *     Markus Armbruster, 2007-2009
33  */
34
35 /*
36  * POSIX sockets are file descriptors.  Windows sockets are something
37  * else, with a separate set of functions to operate on them.  To
38  * present a more POSIX-like interface to our application code, we
39  * provide a compatibility layer that wraps file descriptors around
40  * sockets.
41  */
42
43 #include <config.h>
44
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <io.h>
48 /*
49  * Need to include winsock2.h before ws2tcpip.h.
50  * Use sys/socket.h to ensure the #undef NS_ALL
51  * is not missed after including winsock2.h.
52  */
53 #include "sys/socket.h"
54 #include <sys/stat.h>
55 #include <ws2tcpip.h>
56 #include "unistd.h"
57
58 #define W32_FD_TO_SOCKET(fd) ((SOCKET)_get_osfhandle((fd)))
59 #define W32_SOCKET_TO_FD(fh) (_open_osfhandle((long)(fh), O_RDWR | O_BINARY))
60
61 SOCKET
62 w32_fd2socket(int fd)
63 {
64     return W32_FD_TO_SOCKET(fd);
65 }
66
67 static int
68 fd_is_socket(int fd, SOCKET *sockp)
69 {
70     SOCKET sock;
71     WSANETWORKEVENTS ev;
72
73     sock = W32_FD_TO_SOCKET(fd);
74     if (sockp)
75         *sockp = sock;
76     return WSAEnumNetworkEvents(sock, NULL, &ev) == 0;
77 }
78
79 void
80 w32_set_winsock_errno(void)
81 {
82   int err = WSAGetLastError();
83   WSASetLastError(0);
84
85   /* Map some WSAE* errors to the runtime library's error codes.  */
86   switch (err)
87     {
88     case WSA_INVALID_HANDLE:
89       errno = EBADF;
90       break;
91     case WSA_NOT_ENOUGH_MEMORY:
92       errno = ENOMEM;
93       break;
94     case WSA_INVALID_PARAMETER:
95       errno = EINVAL;
96       break;
97     case WSAEWOULDBLOCK:
98       errno = EAGAIN;
99       break;
100     case WSAENAMETOOLONG:
101       errno = ENAMETOOLONG;
102       break;
103     case WSAENOTEMPTY:
104       errno = ENOTEMPTY;
105       break;
106     default:
107       errno = (err > 10000 && err < 10025) ? err - 10000 : err;
108       break;
109     }
110 }
111
112 #define SOCKET_FUNCTION(expr) do {              \
113         SOCKET sock = W32_FD_TO_SOCKET(fd);     \
114         int res = (expr);                       \
115         if (res == SOCKET_ERROR) {              \
116             w32_set_winsock_errno();            \
117             return -1;                          \
118         }                                       \
119         return res;                             \
120     } while (0)
121
122 /*
123  * POSIX equivalent for accept().
124  */
125 #undef accept
126 int
127 w32_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
128 {
129     SOCKET sock;
130
131     sock = accept(W32_FD_TO_SOCKET(fd), addr, addrlen);
132     if (sock == INVALID_SOCKET) {
133         w32_set_winsock_errno();
134         return -1;
135     }
136
137     return W32_SOCKET_TO_FD(sock);
138 }
139
140 /*
141  * POSIX equivalent for bind().
142  */
143 #undef bind
144 int
145 w32_bind(int fd, const struct sockaddr *name, socklen_t namelen)
146 {
147     SOCKET_FUNCTION(bind(sock, name, namelen));
148 }
149
150 /*
151  * POSIX equivalent for listen().
152  */
153 #undef listen
154 int
155 w32_listen(int fd, int backlog)
156 {
157     SOCKET_FUNCTION(listen(sock, backlog));
158 }
159
160 /*
161  * POSIX equivalent for setsockopt().
162  */
163 #undef setsockopt
164 int
165 w32_setsockopt(int fd, int level, int optname,
166                const void *optval, socklen_t optlen)
167 {
168     /*
169      * SO_REUSEADDR requests to permit another bind even when the
170      * port is still in state TIME_WAIT.  Windows' SO_REUSEADDR is
171      * broken: it makes bind() succeed no matter what, even if
172      * there's another server running on the same port.  Luckily,
173      * bind() seems to be broken as well: it seems to succeed while
174      * the port is in state TIME_WAIT by default; thus we get the
175      * behavior we want by not setting SO_REUSEADDR.
176      */
177     if (level == SOL_SOCKET && optname == SO_REUSEADDR)
178         return 0;
179     {
180         SOCKET_FUNCTION(setsockopt(sock, level, optname, optval, optlen));
181     }
182 }
183
184 /*
185  * POSIX equivalent for shutdown().
186  */
187 #undef shutdown
188 int
189 w32_shutdown(int fd, int how)
190 {
191     SOCKET_FUNCTION(shutdown(sock, how));
192 }
193
194 /*
195  * POSIX equivalent for socket().
196  */
197 #undef socket
198 int
199 w32_socket(int domain, int type, int protocol)
200 {
201     SOCKET sock;
202
203     /*
204      * We have to use WSASocket() to create non-overlapped IO sockets.
205      * Overlapped IO sockets cannot be used with read/write.
206      */
207     sock = WSASocket(domain, type, protocol, NULL, 0, 0);
208     if (sock == INVALID_SOCKET) {
209         w32_set_winsock_errno();
210         return -1;
211     }
212     return W32_SOCKET_TO_FD(sock);
213 }
214
215 #ifdef HAVE_GETADDRINFO
216 const char *
217 inet_ntop(int af, const void *src, char *dst, socklen_t len)
218 {
219     struct sockaddr *sa;
220     struct sockaddr_in sin;
221     struct sockaddr_in6 sin6;
222     size_t salen;
223
224     if (af == AF_INET) {
225         memset(&sin, 0, sizeof(sin));
226         sin.sin_family = af;
227         memcpy(&sin.sin_addr, src, sizeof(sin.sin_addr));
228         sa = (struct sockaddr *)&sin;
229         salen = sizeof(sin);
230     } else if (af == AF_INET6) {
231         memset(&sin6, 0, sizeof(sin6));
232         sin6.sin6_family = af;
233         memcpy(&sin6.sin6_addr, src, sizeof(sin6.sin6_addr));
234         sa = (struct sockaddr *)&sin6;
235         salen = sizeof(sin6);
236     } else {
237         WSASetLastError(WSAEAFNOSUPPORT);
238         w32_set_winsock_errno();
239         return NULL;
240     }
241
242     if (getnameinfo(sa, salen, dst, len, NULL, 0, NI_NUMERICHOST)) {
243         WSASetLastError(WSAEAFNOSUPPORT);
244         w32_set_winsock_errno();
245         return NULL;
246     }
247
248     return dst;
249 }
250 #endif
251
252 /*
253  * POSIX equivalent for fcntl().
254  * Horrible hacks, just good enough support Empire's use of fcntl().
255  * F_GETFL / F_SETFL support making a socket (non-)blocking by getting
256  * flags, adding or removing O_NONBLOCK, and setting the result.
257  */
258 int
259 fcntl(int fd, int cmd, ...)
260 {
261     va_list ap;
262     int value;
263     unsigned long nonblocking;
264     SOCKET sock;
265
266     switch (cmd)
267     {
268     case F_GETFL:
269         return 0;
270     case F_SETFL:
271         sock = W32_FD_TO_SOCKET(fd);
272         va_start(ap, cmd);
273         value = va_arg(ap, int);
274         va_end(ap);
275         nonblocking = (value & O_NONBLOCK) != 0;
276
277         if (ioctlsocket(sock, FIONBIO, &nonblocking) == SOCKET_ERROR) {
278             w32_set_winsock_errno();
279             return -1;
280         }
281         return 0;
282     }
283     errno = EINVAL;
284     return -1;
285 }
286
287 /*
288  * close() replacement that does the right thing for sockets
289  */
290 static int
291 w32_close_maybe_socket(int fd)
292 {
293     SOCKET sock;
294
295     if (fd_is_socket(fd, &sock)) {
296         if (closesocket(sock)) {
297             w32_set_winsock_errno();
298             return -1;
299         }
300         /*
301          * This always fails because the underlying handle is already
302          * gone, but it closes the fd just fine.
303          */
304         _close(fd);
305         return 0;
306     }
307     return _close(fd);
308 }
309
310 /*
311  * read() replacement that does the right thing for sockets
312  */
313 static int
314 w32_read_maybe_socket(int fd, void *buf, unsigned sz)
315 {
316     SOCKET sock;
317     ssize_t res;
318
319     if (fd_is_socket(fd, &sock)) {
320         res = recv(sock, buf, sz, 0);
321         if (res < 0)
322             w32_set_winsock_errno();
323         return res;
324     }
325     return _read(fd, buf, sz);
326 }
327
328 /*
329  * write() replacement that does the right thing for sockets
330  */
331 static int
332 w32_write_maybe_socket(int fd, const void *buf, unsigned sz)
333 {
334     SOCKET sock;
335     ssize_t res;
336
337     if (fd_is_socket(fd, &sock)) {
338         res = send(sock, buf, sz, 0);
339         if (res < 0)
340             w32_set_winsock_errno();
341         return res;
342     }
343     return _write(fd, buf, sz);
344 }
345
346 int
347 w32_socket_init(void)
348 {
349     int rc;
350     WORD wVersionRequested;
351     WSADATA wsaData;
352
353     wVersionRequested = MAKEWORD(2, 0);
354     rc = WSAStartup(wVersionRequested, &wsaData);
355     if (rc != 0)
356         return -1;
357
358     w32_close_function = w32_close_maybe_socket;
359     w32_read_function = w32_read_maybe_socket;
360     w32_write_function = w32_write_maybe_socket;
361     return 0;
362 }