2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
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.
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.
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
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.
28 * posixio.c: POSIX IO emulation layer for WIN32
30 * Known contributors to this file:
31 * Ron Koenderink, 2007
35 * POSIX has just one kind of file descriptors, while Windows has (at
36 * least) two: one for sockets and one for files, with separate
37 * functions to operate on them. To present a more POSIX-like
38 * interface to our application code, we provide a compatibility layer
39 * that maps POSIX file descriptors to sockets and file handles behind
40 * the scenes. This actual mapping is done by the fdmap. It doesn't
41 * implement the finer points of POSIX correctly. In particular, the
42 * actual values of the file descriptors usually differ.
58 #include "prototypes.h"
61 * FD_SETSIZE is the size for the maximum number of sockets.
62 * The number of file descriptors is in a variable _nhandle
63 * based on the assertion output. In order the simplify the
64 * code and skip dynamic allocation, used double the socket size.
66 #define MAX_FDS (FD_SETSIZE * 2)
72 FDMAP_IO_ANY /* used for searching only (lookup_handle) */
77 enum fdmap_io_type type;
80 static struct fdmap fdmap[MAX_FDS] = {
88 * Allocate a POSIX equivalent file descriptor.
89 * Note once get_fd() is called either free_fd() or set_fd()
90 * must be called before thread mutex is released as the
91 * allocation/deallocation code is not thread safe.
98 for (fd = 0; fd < nfd && fdmap[fd].type != FDMAP_IO_NOTUSED; fd++) ;
104 fdmap[fd].type = FDMAP_IO_NOTUSED;
111 * Deallocate a POSIX equivalent file descriptor.
116 fdmap[fd].type = FDMAP_IO_NOTUSED;
117 for(; fdmap[nfd - 1].type == FDMAP_IO_NOTUSED; nfd--) ;
121 * Complete the allocation of the file descriptor.
124 set_fd(int fd, enum fdmap_io_type type, int handle)
128 fdmap[fd].handle = handle;
129 fdmap[fd].type = type;
132 * Garbage collection for posix_fileno(), currently not
133 * replacing fclose() and fcloseall() so do not know when
134 * a stream is closed.
136 for (i = 0; i < nfd; i++) {
137 if (i != fd && type == fdmap[i].type && handle == fdmap[i].handle)
143 * Find the windows handle (file or socket) for file descriptor.
144 * Return windows handle and type of handle.
145 * You can search for a specific type (FDMAP_IO_FILE or FDMAP_IO_SOCKET)
146 * or for both search by using FDMAP_IO_ANY.
147 * FDMAP_IO_NOTUSED is not valid type to search with.
150 lookup_handle(int fd, enum fdmap_io_type d_type, int error,
151 enum fdmap_io_type *type_ptr, int *handle_ptr)
154 if (fd < 0 || fd >= MAX_FDS) {
158 } else if ((fdmap[fd].type != d_type && d_type != FDMAP_IO_ANY) ||
159 (fdmap[fd].type == FDMAP_IO_NOTUSED && d_type == FDMAP_IO_ANY)) {
164 if (type_ptr != NULL)
165 *type_ptr = fdmap[fd].type;
166 if (handle_ptr != NULL)
167 *handle_ptr = fdmap[fd].handle;
172 * Find and return the file descriptor associated with windows handle.
173 * You can search for FDMAP_IO_FILE or FDMAP_IO_SOCKET.
174 * FDMAP_IO_ANY or FDMAP_IO_NOTUSED is not considered valid search
178 lookup_fd(int handle, enum fdmap_io_type d_type)
182 for (i = 0; i < nfd; i++)
183 if (fdmap[i].handle == handle && fdmap[i].type == d_type)
189 * Get the window socket handle for POSIX file descriptor.
192 posix_fd2socket(int fd)
195 enum dmap_io_type type;
197 if (!lookup_handle(fd, FDMAP_IO_SOCKET, WSAENOTSOCK,
199 return INVALID_SOCKET;
203 #define SOCKET_FUNCTION(expr) \
207 if (!lookup_handle(fd, FDMAP_IO_SOCKET, \
208 ENOTSOCK, NULL, &handle)) \
212 if (result == SOCKET_ERROR) { \
213 errno = WSAGetLastError(); \
219 * POSIX equivalent for accept().
223 posix_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
226 int handle, new_handle;
228 if (!lookup_handle(fd, FDMAP_IO_SOCKET, ENOTSOCK, NULL, &handle))
235 new_handle = accept(handle, addr, addrlen);
236 if (new_handle == INVALID_SOCKET) {
238 errno = WSAGetLastError();
241 set_fd(new_fd, FDMAP_IO_SOCKET, new_handle);
246 * POSIX equivalent for bind().
250 posix_bind(int fd, const struct sockaddr *name, int namelen)
252 SOCKET_FUNCTION(bind(handle, name, namelen))
256 * POSIX equivalent for listen().
260 posix_listen(int fd, int backlog)
262 SOCKET_FUNCTION(listen(handle, backlog))
266 * POSIX equivalent for setsockopt().
270 posix_setsockopt(int fd, int level, int optname,
271 const char *optval, int optlen)
273 SOCKET_FUNCTION(setsockopt(handle, level, optname,
278 * POSIX equivalent for shutdown().
282 posix_shutdown(int fd, int how)
284 SOCKET_FUNCTION(shutdown(handle, how))
288 * POSIX equivalent for socket().
292 posix_socket(int domain, int type, int protocol)
297 if ((new_fd = get_fd()) < 0)
300 handle = socket(domain, type, protocol);
301 if (handle == INVALID_SOCKET) {
303 errno = WSAGetLastError();
306 set_fd(new_fd, FDMAP_IO_SOCKET, handle);
310 #define FILE_FUNCTION(type, expr) \
313 if (!lookup_handle(fd, (type), EBADF, NULL, &handle)) \
319 * POSIX equivalent for close().
326 enum fdmap_io_type type;
328 if (!lookup_handle(fd, FDMAP_IO_ANY, EBADF, &type, &handle))
333 case FDMAP_IO_SOCKET:
334 result = closesocket(handle);
335 if (result == SOCKET_ERROR) {
336 errno = WSAGetLastError();
341 return _close(handle);
348 * posix_fsync forces file sync with the disk.
349 * In order for the power report report to accurate timestamp,
350 * the _commit() is to force a sync with disk and therefore
351 * an update for file time.
356 FILE_FUNCTION(FDMAP_IO_FILE, _commit(handle))
360 * POSIX equivalent for fstat().
361 * fstat() is used instead of _fstat(),
362 * otherwise problems with the 32/64 time definitions
367 posix_fstat(int fd, struct stat *buffer)
369 FILE_FUNCTION(FDMAP_IO_ANY, fstat(handle, buffer))
373 * POSIX equivalent for lseek().
376 posix_lseek(int fd, long offset, int origin)
378 FILE_FUNCTION(FDMAP_IO_FILE, _lseek(handle, offset, origin))
382 * POSIX equivalent for open().
383 * Implements file locks when opening files to provide equivalent
387 posix_open(const char *fname, int oflag, ...)
390 int pmode = 0, new_fd;
393 if (oflag & O_CREAT) {
395 pmode = va_arg(ap, int);
399 if ((new_fd = get_fd()) < 0)
403 * We don't implement fcntl() for F_SETLK. Instead, we lock *all*
404 * files we open. Not ideal, but it works for Empire.
406 _sopen_s(&handle, fname, oflag,
407 oflag & O_RDONLY ? SH_DENYNO : SH_DENYWR, pmode);
412 set_fd(new_fd, FDMAP_IO_FILE, handle);
416 #define SHARED_FUNCTION(socket_expr, file_expr) \
419 enum fdmap_io_type type; \
421 if (!lookup_handle(fd, FDMAP_IO_ANY, EBADF, &type, &handle)) \
425 case FDMAP_IO_SOCKET: \
426 result = (socket_expr); \
427 if (result == SOCKET_ERROR) { \
428 errno = WSAGetLastError(); \
432 case FDMAP_IO_FILE: \
433 return (file_expr); \
439 * POSIX equivalent for read().
442 posix_read(int fd, void *buffer, unsigned int count)
444 SHARED_FUNCTION(recv(handle, buffer, count, 0),
445 _read(handle, buffer, count))
449 * POSIX equivalent for write().
452 posix_write(int fd, const void *buffer, unsigned int count)
454 SHARED_FUNCTION(send(handle, buffer, count, 0),
455 _write(handle, buffer, count))
459 * POSIX equivalent for fileno().
460 * As fopen/fclose/fcloseall are not implemented as POSIX
461 * equivalent functions, the mapping is done when required
462 * by a call to fileno(). The garbage collection of the
463 * file descriptors allocated is done in set_fd() when the
467 posix_fileno(FILE *stream)
472 if (stream == NULL) {
477 handle = _fileno(stream);
479 fd = lookup_fd(handle, FDMAP_IO_FILE);
483 if ((fd = get_fd()) < 0) {
488 set_fd(fd, FDMAP_IO_FILE, handle);
493 * POSIX equivalent for fcntl().
494 * Currently supports only the F_GETFL/F_SETFL/O_NONBLOCK
495 * Currently ignores F_GETLK/F_SETLK as the file locks are
496 * implement in open()
499 fcntl(int fd, int cmd, ...)
503 unsigned int nonblocking;
507 enum fdmap_io_type type;
509 if (!lookup_handle(fd, FDMAP_IO_ANY, EBADF, &type, &handle))
516 * F_GETFL and F_SETFL only support O_NONBLOCK
517 * for sockets currently
519 if (type == FDMAP_IO_SOCKET) {
520 result = WSAIoctl(handle, FIONBIO, NULL, 0,&nonblocking,
521 sizeof (nonblocking), &bytes_returned, NULL, NULL);
524 errno = WSAGetLastError();
535 if (type == FDMAP_IO_SOCKET) {
537 value = va_arg(ap, int);
539 if (value & O_NONBLOCK)
544 result = WSAIoctl(handle, FIONBIO, &nonblocking,
545 sizeof (nonblocking), NULL, 0, &bytes_returned,
549 errno = WSAGetLastError();
557 * The POSIX equivalent is not available in WIN32
558 * That implement the file locking in the file open
559 * by using sopen instead of open.