]> git.pond.sub.org Git - empserver/blob - src/lib/w32/w32sockets.c
3d80a2dae8a4e125f258f3ad26864673f33b9ab1
[empserver] / src / lib / w32 / w32sockets.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, 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-2010
31  *     Markus Armbruster, 2007-2013
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 "arpa/inet.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     BOOL val;
72     int size = sizeof(val);
73
74     sock = W32_FD_TO_SOCKET(fd);
75     if (sockp)
76         *sockp = sock;
77     return getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, &size)
78         == 0;
79 }
80
81 void
82 w32_set_winsock_errno(void)
83 {
84     int err = WSAGetLastError();
85     WSASetLastError(0);
86
87     /* Map some WSAE* errors to the runtime library's error codes. */
88     switch (err) {
89     case WSA_INVALID_HANDLE:
90         errno = EBADF;
91         break;
92     case WSA_NOT_ENOUGH_MEMORY:
93         errno = ENOMEM;
94         break;
95     case WSA_INVALID_PARAMETER:
96         errno = EINVAL;
97         break;
98     case WSAEWOULDBLOCK:
99         errno = EAGAIN;
100         break;
101     case WSAENAMETOOLONG:
102         errno = ENAMETOOLONG;
103         break;
104     case WSAENOTEMPTY:
105         errno = ENOTEMPTY;
106         break;
107     default:
108         errno = (err > 10000 && err < 10025) ? err - 10000 : err;
109         break;
110     }
111 }
112
113 #define SOCKET_FUNCTION(expr) do {              \
114         SOCKET sock = W32_FD_TO_SOCKET(fd);     \
115         int res = (expr);                       \
116         if (res == SOCKET_ERROR) {              \
117             w32_set_winsock_errno();            \
118             return -1;                          \
119         }                                       \
120         return res;                             \
121     } while (0)
122
123 /*
124  * POSIX equivalent for accept().
125  */
126 #undef accept
127 int
128 w32_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
129 {
130     SOCKET sock;
131
132     sock = accept(W32_FD_TO_SOCKET(fd), addr, addrlen);
133     if (sock == INVALID_SOCKET) {
134         w32_set_winsock_errno();
135         return -1;
136     }
137
138     return W32_SOCKET_TO_FD(sock);
139 }
140
141 /*
142  * POSIX equivalent for bind().
143  */
144 #undef bind
145 int
146 w32_bind(int fd, const struct sockaddr *name, socklen_t namelen)
147 {
148     SOCKET_FUNCTION(bind(sock, name, namelen));
149 }
150
151 /*
152  * POSIX compatible connect() replacement
153  */
154 #undef connect
155 int
156 w32_connect(int sockfd, const struct sockaddr *addr, int addrlen)
157 {
158     SOCKET sock = W32_FD_TO_SOCKET(sockfd);
159     int result;
160
161     result = connect(sock, addr, addrlen);
162     if (result == SOCKET_ERROR) {
163         /* FIXME map WSAEWOULDBLOCK to EINPROGRESS */
164         w32_set_winsock_errno();
165         return -1;
166     }
167     return result;
168 }
169
170 /*
171  * POSIX equivalent for listen().
172  */
173 #undef listen
174 int
175 w32_listen(int fd, int backlog)
176 {
177     SOCKET_FUNCTION(listen(sock, backlog));
178 }
179
180 /*
181  * POSIX equivalent for setsockopt().
182  */
183 #undef setsockopt
184 int
185 w32_setsockopt(int fd, int level, int optname,
186                const void *optval, socklen_t optlen)
187 {
188     /*
189      * SO_REUSEADDR requests to permit another bind even when the
190      * port is still in state TIME_WAIT.  Windows' SO_REUSEADDR is
191      * broken: it makes bind() succeed no matter what, even if
192      * there's another server running on the same port.  Luckily,
193      * bind() seems to be broken as well: it seems to succeed while
194      * the port is in state TIME_WAIT by default; thus we get the
195      * behavior we want by not setting SO_REUSEADDR.
196      */
197     if (level == SOL_SOCKET && optname == SO_REUSEADDR)
198         return 0;
199     {
200         SOCKET_FUNCTION(setsockopt(sock, level, optname, optval, optlen));
201     }
202 }
203
204 /*
205  * POSIX equivalent for shutdown().
206  */
207 #undef shutdown
208 int
209 w32_shutdown(int fd, int how)
210 {
211     SOCKET_FUNCTION(shutdown(sock, how));
212 }
213
214 /*
215  * POSIX equivalent for socket().
216  */
217 #undef socket
218 int
219 w32_socket(int domain, int type, int protocol)
220 {
221     SOCKET sock;
222
223     /*
224      * We have to use WSASocket() to create non-overlapped I/O sockets.
225      * Overlapped I/O sockets cannot be used with read/write.
226      */
227     sock = WSASocket(domain, type, protocol, NULL, 0, 0);
228     if (sock == INVALID_SOCKET) {
229         w32_set_winsock_errno();
230         return -1;
231     }
232     return W32_SOCKET_TO_FD(sock);
233 }
234
235 #ifdef HAVE_GETADDRINFO
236 const char *
237 inet_ntop(int af, const void *src, char *dst, socklen_t len)
238 {
239     struct sockaddr *sa;
240     struct sockaddr_in sin;
241     struct sockaddr_in6 sin6;
242     size_t salen;
243
244     if (af == AF_INET) {
245         memset(&sin, 0, sizeof(sin));
246         sin.sin_family = af;
247         memcpy(&sin.sin_addr, src, sizeof(sin.sin_addr));
248         sa = (struct sockaddr *)&sin;
249         salen = sizeof(sin);
250     } else if (af == AF_INET6) {
251         memset(&sin6, 0, sizeof(sin6));
252         sin6.sin6_family = af;
253         memcpy(&sin6.sin6_addr, src, sizeof(sin6.sin6_addr));
254         sa = (struct sockaddr *)&sin6;
255         salen = sizeof(sin6);
256     } else {
257         WSASetLastError(WSAEAFNOSUPPORT);
258         w32_set_winsock_errno();
259         return NULL;
260     }
261
262     if (getnameinfo(sa, salen, dst, len, NULL, 0, NI_NUMERICHOST)) {
263         WSASetLastError(WSAEAFNOSUPPORT);
264         w32_set_winsock_errno();
265         return NULL;
266     }
267
268     return dst;
269 }
270 #endif
271
272 /*
273  * POSIX equivalent for fcntl().
274  * Horrible hacks, just good enough support Empire's use of fcntl().
275  * F_GETFL / F_SETFL support making a socket (non-)blocking by getting
276  * flags, adding or removing O_NONBLOCK, and setting the result.
277  */
278 int
279 fcntl(int fd, int cmd, ...)
280 {
281     va_list ap;
282     int value;
283     unsigned long nonblocking;
284     SOCKET sock;
285
286     switch (cmd) {
287     case F_GETFL:
288         return 0;
289     case F_SETFL:
290         sock = W32_FD_TO_SOCKET(fd);
291         va_start(ap, cmd);
292         value = va_arg(ap, int);
293         va_end(ap);
294         nonblocking = (value & O_NONBLOCK) != 0;
295
296         if (ioctlsocket(sock, FIONBIO, &nonblocking) == SOCKET_ERROR) {
297             w32_set_winsock_errno();
298             return -1;
299         }
300         return 0;
301     }
302     errno = EINVAL;
303     return -1;
304 }
305
306 /*
307  * close() replacement that does the right thing for sockets
308  */
309 static int
310 w32_close_maybe_socket(int fd)
311 {
312     SOCKET sock;
313
314     if (fd_is_socket(fd, &sock)) {
315         if (closesocket(sock)) {
316             w32_set_winsock_errno();
317             return -1;
318         }
319         /*
320          * This always fails because the underlying handle is already
321          * gone, but it closes the fd just fine.
322          */
323         _close(fd);
324         return 0;
325     }
326     return _close(fd);
327 }
328
329 /*
330  * read() replacement that does the right thing for sockets
331  */
332 static int
333 w32_read_maybe_socket(int fd, void *buf, unsigned sz)
334 {
335     SOCKET sock;
336     ssize_t res;
337
338     if (fd_is_socket(fd, &sock)) {
339         res = recv(sock, buf, sz, 0);
340         if (res < 0)
341             w32_set_winsock_errno();
342         return res;
343     }
344     return _read(fd, buf, sz);
345 }
346
347 /*
348  * write() replacement that does the right thing for sockets
349  */
350 static int
351 w32_write_maybe_socket(int fd, const void *buf, unsigned sz)
352 {
353     SOCKET sock;
354     ssize_t res;
355
356     if (fd_is_socket(fd, &sock)) {
357         res = send(sock, buf, sz, 0);
358         if (res < 0)
359             w32_set_winsock_errno();
360         return res;
361     }
362     return _write(fd, buf, sz);
363 }
364
365 int
366 w32_socket_init(void)
367 {
368     int rc;
369     WORD wVersionRequested;
370     WSADATA wsaData;
371
372     wVersionRequested = MAKEWORD(2, 0);
373     rc = WSAStartup(wVersionRequested, &wsaData);
374     if (rc != 0)
375         return -1;
376
377     w32_close_function = w32_close_maybe_socket;
378     w32_read_function = w32_read_maybe_socket;
379     w32_write_function = w32_write_maybe_socket;
380     return 0;
381 }