]> git.pond.sub.org Git - empserver/blob - src/lib/w32/w32sockets.c
bc2e07bf7516297baa616e4935bedd3d26c68ce6
[empserver] / src / lib / w32 / w32sockets.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  w32sockets.c: POSIX socket emulation layer for Windows
28  *
29  *  Known contributors to this file:
30  *     Ron Koenderink, 2007
31  *     Markus Armbruster, 2007-2009
32  */
33
34 /*
35  * POSIX sockets are file descriptors.  Windows sockets are something
36  * else, with a separate set of functions to operate on them.  To
37  * present a more POSIX-like interface to our application code, we
38  * provide a compatibility layer that wraps file descriptors around
39  * sockets.
40  */
41
42 #include <config.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <io.h>
47 /*
48  * Need to include winsock2.h before ws2tcpip.h.
49  * Use sys/socket.h to ensure the #undef NS_ALL
50  * is not missed after including winsock2.h.
51  */
52 #include "sys/socket.h"
53 #include <sys/stat.h>
54 #include <ws2tcpip.h>
55 #include "unistd.h"
56
57 #define W32_FD_TO_SOCKET(fd) ((SOCKET)_get_osfhandle((fd)))
58 #define W32_SOCKET_TO_FD(fh) (_open_osfhandle((long)(fh), O_RDWR | O_BINARY))
59
60 SOCKET
61 w32_fd2socket(int fd)
62 {
63     return W32_FD_TO_SOCKET(fd);
64 }
65
66 static int
67 fd_is_socket(int fd, SOCKET *sockp)
68 {
69     SOCKET sock;
70     BOOL val;
71     int size = sizeof(val);
72
73     sock = W32_FD_TO_SOCKET(fd);
74     if (sockp)
75         *sockp = sock;
76     return getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, &size)
77         == 0;
78 }
79
80 void
81 w32_set_winsock_errno(void)
82 {
83     int err = WSAGetLastError();
84     WSASetLastError(0);
85
86     /* Map some WSAE* errors to the runtime library's error codes.  */
87     switch (err) {
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 compatible connect() replacement
152  */
153 #undef connect
154 int
155 w32_connect(int sockfd, const struct sockaddr *addr, int addrlen)
156 {
157     SOCKET sock = W32_FD_TO_SOCKET(sockfd);
158     int result;
159
160     result = connect(sock, addr, addrlen);
161     if (result == SOCKET_ERROR) {
162         /* FIXME map WSAEWOULDBLOCK to EINPROGRESS */
163         w32_set_winsock_errno();
164         return -1;
165     }
166     return result;
167 }
168
169 /*
170  * POSIX equivalent for listen().
171  */
172 #undef listen
173 int
174 w32_listen(int fd, int backlog)
175 {
176     SOCKET_FUNCTION(listen(sock, backlog));
177 }
178
179 /*
180  * POSIX equivalent for setsockopt().
181  */
182 #undef setsockopt
183 int
184 w32_setsockopt(int fd, int level, int optname,
185                const void *optval, socklen_t optlen)
186 {
187     /*
188      * SO_REUSEADDR requests to permit another bind even when the
189      * port is still in state TIME_WAIT.  Windows' SO_REUSEADDR is
190      * broken: it makes bind() succeed no matter what, even if
191      * there's another server running on the same port.  Luckily,
192      * bind() seems to be broken as well: it seems to succeed while
193      * the port is in state TIME_WAIT by default; thus we get the
194      * behavior we want by not setting SO_REUSEADDR.
195      */
196     if (level == SOL_SOCKET && optname == SO_REUSEADDR)
197         return 0;
198     {
199         SOCKET_FUNCTION(setsockopt(sock, level, optname, optval, optlen));
200     }
201 }
202
203 /*
204  * POSIX equivalent for shutdown().
205  */
206 #undef shutdown
207 int
208 w32_shutdown(int fd, int how)
209 {
210     SOCKET_FUNCTION(shutdown(sock, how));
211 }
212
213 /*
214  * POSIX equivalent for socket().
215  */
216 #undef socket
217 int
218 w32_socket(int domain, int type, int protocol)
219 {
220     SOCKET sock;
221
222     /*
223      * We have to use WSASocket() to create non-overlapped IO sockets.
224      * Overlapped IO sockets cannot be used with read/write.
225      */
226     sock = WSASocket(domain, type, protocol, NULL, 0, 0);
227     if (sock == INVALID_SOCKET) {
228         w32_set_winsock_errno();
229         return -1;
230     }
231     return W32_SOCKET_TO_FD(sock);
232 }
233
234 #ifdef HAVE_GETADDRINFO
235 const char *
236 inet_ntop(int af, const void *src, char *dst, socklen_t len)
237 {
238     struct sockaddr *sa;
239     struct sockaddr_in sin;
240     struct sockaddr_in6 sin6;
241     size_t salen;
242
243     if (af == AF_INET) {
244         memset(&sin, 0, sizeof(sin));
245         sin.sin_family = af;
246         memcpy(&sin.sin_addr, src, sizeof(sin.sin_addr));
247         sa = (struct sockaddr *)&sin;
248         salen = sizeof(sin);
249     } else if (af == AF_INET6) {
250         memset(&sin6, 0, sizeof(sin6));
251         sin6.sin6_family = af;
252         memcpy(&sin6.sin6_addr, src, sizeof(sin6.sin6_addr));
253         sa = (struct sockaddr *)&sin6;
254         salen = sizeof(sin6);
255     } else {
256         WSASetLastError(WSAEAFNOSUPPORT);
257         w32_set_winsock_errno();
258         return NULL;
259     }
260
261     if (getnameinfo(sa, salen, dst, len, NULL, 0, NI_NUMERICHOST)) {
262         WSASetLastError(WSAEAFNOSUPPORT);
263         w32_set_winsock_errno();
264         return NULL;
265     }
266
267     return dst;
268 }
269 #endif
270
271 /*
272  * POSIX equivalent for fcntl().
273  * Horrible hacks, just good enough support Empire's use of fcntl().
274  * F_GETFL / F_SETFL support making a socket (non-)blocking by getting
275  * flags, adding or removing O_NONBLOCK, and setting the result.
276  */
277 int
278 fcntl(int fd, int cmd, ...)
279 {
280     va_list ap;
281     int value;
282     unsigned long nonblocking;
283     SOCKET sock;
284
285     switch (cmd) {
286     case F_GETFL:
287         return 0;
288     case F_SETFL:
289         sock = W32_FD_TO_SOCKET(fd);
290         va_start(ap, cmd);
291         value = va_arg(ap, int);
292         va_end(ap);
293         nonblocking = (value & O_NONBLOCK) != 0;
294
295         if (ioctlsocket(sock, FIONBIO, &nonblocking) == SOCKET_ERROR) {
296             w32_set_winsock_errno();
297             return -1;
298         }
299         return 0;
300     }
301     errno = EINVAL;
302     return -1;
303 }
304
305 /*
306  * close() replacement that does the right thing for sockets
307  */
308 static int
309 w32_close_maybe_socket(int fd)
310 {
311     SOCKET sock;
312
313     if (fd_is_socket(fd, &sock)) {
314         if (closesocket(sock)) {
315             w32_set_winsock_errno();
316             return -1;
317         }
318         /*
319          * This always fails because the underlying handle is already
320          * gone, but it closes the fd just fine.
321          */
322         _close(fd);
323         return 0;
324     }
325     return _close(fd);
326 }
327
328 /*
329  * read() replacement that does the right thing for sockets
330  */
331 static int
332 w32_read_maybe_socket(int fd, void *buf, unsigned sz)
333 {
334     SOCKET sock;
335     ssize_t res;
336
337     if (fd_is_socket(fd, &sock)) {
338         res = recv(sock, buf, sz, 0);
339         if (res < 0)
340             w32_set_winsock_errno();
341         return res;
342     }
343     return _read(fd, buf, sz);
344 }
345
346 /*
347  * write() replacement that does the right thing for sockets
348  */
349 static int
350 w32_write_maybe_socket(int fd, const void *buf, unsigned sz)
351 {
352     SOCKET sock;
353     ssize_t res;
354
355     if (fd_is_socket(fd, &sock)) {
356         res = send(sock, buf, sz, 0);
357         if (res < 0)
358             w32_set_winsock_errno();
359         return res;
360     }
361     return _write(fd, buf, sz);
362 }
363
364 int
365 w32_socket_init(void)
366 {
367     int rc;
368     WORD wVersionRequested;
369     WSADATA wsaData;
370
371     wVersionRequested = MAKEWORD(2, 0);
372     rc = WSAStartup(wVersionRequested, &wsaData);
373     if (rc != 0)
374         return -1;
375
376     w32_close_function = w32_close_maybe_socket;
377     w32_read_function = w32_read_maybe_socket;
378     w32_write_function = w32_write_maybe_socket;
379     return 0;
380 }