]> git.pond.sub.org Git - empserver/blob - src/lib/w32/w32sockets.c
client: Unbreak standalone build
[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 /*
236  * POSIX equivalent for fcntl().
237  * Horrible hacks, just good enough support Empire's use of fcntl().
238  * F_GETFL / F_SETFL support making a socket (non-)blocking by getting
239  * flags, adding or removing O_NONBLOCK, and setting the result.
240  */
241 int
242 fcntl(int fd, int cmd, ...)
243 {
244     va_list ap;
245     int value;
246     unsigned long nonblocking;
247     SOCKET sock;
248
249     switch (cmd) {
250     case F_GETFL:
251         return 0;
252     case F_SETFL:
253         sock = W32_FD_TO_SOCKET(fd);
254         va_start(ap, cmd);
255         value = va_arg(ap, int);
256         va_end(ap);
257         nonblocking = (value & O_NONBLOCK) != 0;
258
259         if (ioctlsocket(sock, FIONBIO, &nonblocking) == SOCKET_ERROR) {
260             w32_set_winsock_errno();
261             return -1;
262         }
263         return 0;
264     }
265     errno = EINVAL;
266     return -1;
267 }
268
269 /*
270  * close() replacement that does the right thing for sockets
271  */
272 static int
273 w32_close_maybe_socket(int fd)
274 {
275     SOCKET sock;
276
277     if (fd_is_socket(fd, &sock)) {
278         if (closesocket(sock)) {
279             w32_set_winsock_errno();
280             return -1;
281         }
282         /*
283          * This always fails because the underlying handle is already
284          * gone, but it closes the fd just fine.
285          */
286         _close(fd);
287         return 0;
288     }
289     return _close(fd);
290 }
291
292 /*
293  * read() replacement that does the right thing for sockets
294  */
295 static int
296 w32_read_maybe_socket(int fd, void *buf, unsigned sz)
297 {
298     SOCKET sock;
299     ssize_t res;
300
301     if (fd_is_socket(fd, &sock)) {
302         res = recv(sock, buf, sz, 0);
303         if (res < 0)
304             w32_set_winsock_errno();
305         return res;
306     }
307     return _read(fd, buf, sz);
308 }
309
310 /*
311  * write() replacement that does the right thing for sockets
312  */
313 static int
314 w32_write_maybe_socket(int fd, const void *buf, unsigned sz)
315 {
316     SOCKET sock;
317     ssize_t res;
318
319     if (fd_is_socket(fd, &sock)) {
320         res = send(sock, buf, sz, 0);
321         if (res < 0)
322             w32_set_winsock_errno();
323         return res;
324     }
325     return _write(fd, buf, sz);
326 }
327
328 int
329 w32_socket_init(void)
330 {
331     int rc;
332     WORD wVersionRequested;
333     WSADATA wsaData;
334
335     wVersionRequested = MAKEWORD(2, 0);
336     rc = WSAStartup(wVersionRequested, &wsaData);
337     if (rc != 0)
338         return -1;
339
340     w32_close_function = w32_close_maybe_socket;
341     w32_read_function = w32_read_maybe_socket;
342     w32_write_function = w32_write_maybe_socket;
343     return 0;
344 }