]> git.pond.sub.org Git - empserver/blobdiff - src/lib/w32/posixio.c
Update copyright notice
[empserver] / src / lib / w32 / posixio.c
index d7e88b63ccbb24997e7036f1a5a1c0c6343025ff..0f69f76897b2380c1a5a3a8ec861f351f05b2f79 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
  *  ---
  *
  *  posixio.c: POSIX IO emulation layer for WIN32
- * 
+ *
  *  Known contributors to this file:
  *     Ron Koenderink, 2007
+ *     Markus Armbruster, 2007-2008
  */
 
 /*
  */
 
 #include <config.h>
-#include <winsock2.h>
-#undef NS_ALL
-#include <io.h>
-#include <direct.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <share.h>
 
 #include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <share.h>
+#include <stdio.h>
+#include <stdarg.h>
+/*
+ * Need to include winsock2.h before ws2tcpip.h.
+ * Use sys/socket.h to ensure the #undef NS_ALL
+ * is not missed after including winsock2.h.
+ */
+#include "sys/socket.h"
+#include <sys/stat.h>
+#include <ws2tcpip.h>
 
+#include "misc.h"
+#include "sys/uio.h"
 #include "unistd.h"
-#include "empio.h"
-#include "prototypes.h"
 
 /*
  * FD_SETSIZE is the size for the maximum number of sockets.
@@ -129,7 +136,7 @@ set_fd(int fd, enum fdmap_io_type type, int handle)
     fdmap[fd].type = type;
 
     /*
-     * Garbage collection for posix_fileno(), currently not
+     * Garbage collection for fileno(), currently not
      * replacing fclose() and fcloseall() so do not know when
      * a stream is closed.
      */
@@ -192,7 +199,7 @@ int
 posix_fd2socket(int fd)
 {
     int handle;
-    enum dmap_io_type type;
+    enum fdmap_io_type type;
 
     if (!lookup_handle(fd, FDMAP_IO_SOCKET, WSAENOTSOCK,
        &type, &handle))
@@ -223,7 +230,8 @@ int
 posix_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
 {
     int new_fd;
-    int handle, new_handle;
+    int handle;
+    SOCKET new_handle;
 
     if (!lookup_handle(fd, FDMAP_IO_SOCKET, ENOTSOCK, NULL, &handle))
        return -1;
@@ -238,7 +246,7 @@ posix_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
        errno = WSAGetLastError();
        return -1;
     }
-    set_fd(new_fd, FDMAP_IO_SOCKET, new_handle);
+    set_fd(new_fd, FDMAP_IO_SOCKET, (int)new_handle);
     return new_fd;
 }
 
@@ -247,7 +255,7 @@ posix_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
  */
 #undef bind
 int
-posix_bind(int fd, const struct sockaddr *name, int namelen)
+posix_bind(int fd, const struct sockaddr *name, socklen_t namelen)
 {
     SOCKET_FUNCTION(bind(handle, name, namelen))
 }
@@ -268,10 +276,23 @@ posix_listen(int fd, int backlog)
 #undef setsockopt
 int
 posix_setsockopt(int fd, int level, int optname,
-                     const char *optval, int optlen)
+                     const void *optval, socklen_t optlen)
 {
-    SOCKET_FUNCTION(setsockopt(handle, level, optname,
-                   optval, optlen))
+    /*
+     * SO_REUSEADDR requests to permit another bind even when the
+     * port is still in state TIME_WAIT.  Windows' SO_REUSEADDR is
+     * broken: it makes bind() succeed no matter what, even if
+     * there's another server running on the same port.  Luckily,
+     * bind() seems to be broken as well: it seems to succeed while
+     * the port is in state TIME_WAIT by default; thus we get the
+     * behavior we want by not setting SO_REUSEADDR.
+     */
+    if (level == SOL_SOCKET && optname == SO_REUSEADDR)
+       return 0;
+    {
+       SOCKET_FUNCTION(setsockopt(handle, level, optname,
+                       optval, optlen))
+    }
 }
 
 /*
@@ -291,9 +312,9 @@ posix_shutdown(int fd, int how)
 int
 posix_socket(int domain, int type, int protocol)
 {
-    int handle;
+    SOCKET handle;
     int new_fd;
-    
+
     if ((new_fd = get_fd()) < 0)
        return -1;
 
@@ -303,10 +324,45 @@ posix_socket(int domain, int type, int protocol)
        errno = WSAGetLastError();
        return -1;
     }
-    set_fd(new_fd, FDMAP_IO_SOCKET, handle);
+    set_fd(new_fd, FDMAP_IO_SOCKET, (int)handle);
     return new_fd;
 }
 
+#ifdef HAVE_GETADDRINFO
+const char *
+inet_ntop(int af, const void *src, char *dst, socklen_t len)
+{
+    struct sockaddr *sa;
+    struct sockaddr_in sin;
+    struct sockaddr_in6 sin6;
+    size_t salen;
+
+    if (af == AF_INET) {
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = af;
+       memcpy(&sin.sin_addr, src, sizeof(sin.sin_addr));
+       sa = (struct sockaddr *)&sin;
+       salen = sizeof(sin);
+    } else if (af == AF_INET6) {
+       memset(&sin6, 0, sizeof(sin6));
+       sin6.sin6_family = af;
+       memcpy(&sin6.sin6_addr, src, sizeof(sin6.sin6_addr));
+       sa = (struct sockaddr *)&sin6;
+       salen = sizeof(sin6);
+    } else {
+       errno = EAFNOSUPPORT;
+       return NULL;
+    }
+
+    if (getnameinfo(sa, salen, dst, len, NULL, 0, NI_NUMERICHOST)) {
+       errno = EAFNOSUPPORT;
+       return NULL;
+    }
+
+    return dst;
+}
+#endif
+
 #define FILE_FUNCTION(type, expr)                              \
     int handle;                                                        \
                                                                \
@@ -339,9 +395,10 @@ posix_close(int fd)
        return result;
     case FDMAP_IO_FILE:
        return _close(handle);
+    default:
+       CANT_REACH();
+       return -1;
     }
-    CANT_REACH();
-    return -1;
 }
 
 /*
@@ -356,6 +413,15 @@ posix_fsync(int fd)
     FILE_FUNCTION(FDMAP_IO_FILE, _commit(handle))
 }
 
+/*
+ * POSIX ftruncate()
+ */
+int
+ftruncate(int fd, off_t length)
+{
+    FILE_FUNCTION(FDMAP_IO_FILE, _chsize(handle, length))
+}
+
 /*
  * POSIX equivalent for fstat().
  * fstat() is used instead of _fstat(),
@@ -372,8 +438,8 @@ posix_fstat(int fd, struct stat *buffer)
 /*
  * POSIX equivalent for lseek().
  */
-int
-posix_lseek(int fd, long offset, int origin)
+off_t
+posix_lseek(int fd, off_t offset, int origin)
 {
     FILE_FUNCTION(FDMAP_IO_FILE, _lseek(handle, offset, origin))
 }
@@ -403,7 +469,7 @@ posix_open(const char *fname, int oflag, ...)
      * We don't implement fcntl() for F_SETLK.  Instead, we lock *all*
      * files we open.  Not ideal, but it works for Empire.
      */
-    _sopen_s(&handle, fname, oflag,
+    handle = _sopen(fname, oflag,
        oflag & O_RDONLY ? SH_DENYNO : SH_DENYWR, pmode);
     if (handle == -1) {
        free_fd(new_fd);
@@ -431,30 +497,114 @@ posix_open(const char *fname, int oflag, ...)
        return result;                                              \
     case FDMAP_IO_FILE:                                                    \
        return (file_expr);                                         \
-    }                                                              \
-    CANT_REACH();                                                  \
-    return -1;
+    default:                                                       \
+       CANT_REACH();                                               \
+       return -1;                                                  \
+    }
 
 /*
  * POSIX equivalent for read().
  */
-int
-posix_read(int fd, void *buffer, unsigned int count)
+ssize_t
+posix_read(int fd, void *buffer, size_t count)
 {
     SHARED_FUNCTION(recv(handle, buffer, count, 0),
        _read(handle, buffer, count))
 }
 
+/*
+ * POSIX equivalent for readv
+ * Modelled after the GNU's libc/sysdeps/posix/readv.c
+ */
+ssize_t
+readv(int fd, const struct iovec *iov, int iovcnt)
+{
+    int i;
+    unsigned char *buffer, *buffer_location;
+    size_t total_bytes = 0;
+    int bytes_read;
+    size_t bytes_left;
+
+    for (i = 0; i < iovcnt; i++) {
+       total_bytes += iov[i].iov_len;
+    }
+
+    buffer = malloc(total_bytes);
+    if (buffer == NULL && total_bytes != 0) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    bytes_read = posix_read(fd, buffer, total_bytes);
+    if (bytes_read <= 0) {
+       free(buffer);
+       return -1;
+    }
+
+    bytes_left = bytes_read;
+    buffer_location = buffer;
+    for (i = 0; i < iovcnt; i++) {
+       size_t copy = MIN(iov[i].iov_len, bytes_left);
+
+       memcpy(iov[i].iov_base, buffer_location, copy);
+
+       buffer_location += copy;
+       bytes_left -= copy;
+       if (bytes_left == 0)
+           break;
+    }
+
+    free(buffer);
+
+    return bytes_read;
+}
+
 /*
  * POSIX equivalent for write().
  */
-int
-posix_write(int fd, const void *buffer, unsigned int count)
+ssize_t
+posix_write(int fd, const void *buffer, size_t count)
 {
     SHARED_FUNCTION(send(handle, buffer, count, 0),
        _write(handle, buffer, count))
 }
 
+/*
+ * POSIX equivalent for writev
+ * Modelled after the GNU's libc/sysdeps/posix/writev.c
+ */
+ssize_t
+writev(int fd, const struct iovec *iov, int iovcnt)
+{
+    int i;
+    unsigned char *buffer, *buffer_location;
+    size_t total_bytes = 0;
+    int bytes_written;
+
+    for (i = 0; i < iovcnt; i++)
+       total_bytes += iov[i].iov_len;
+
+    buffer = malloc(total_bytes);
+    if (buffer == NULL && total_bytes != 0) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    buffer_location = buffer;
+    for (i = 0; i < iovcnt; i++) {
+       memcpy(buffer_location, iov[i].iov_base, iov[i].iov_len);
+       buffer_location += iov[i].iov_len;
+    }
+
+    bytes_written = posix_write(fd, buffer, total_bytes);
+
+    free(buffer);
+
+    if (bytes_written <= 0)
+       return -1;
+    return bytes_written;
+}
+
 /*
  * POSIX equivalent for fileno().
  * As fopen/fclose/fcloseall are not implemented as POSIX
@@ -464,7 +614,7 @@ posix_write(int fd, const void *buffer, unsigned int count)
  * handle is reused.
  */
 int
-posix_fileno(FILE *stream)
+fileno(FILE *stream)
 {
     int fd;
     int handle;
@@ -519,7 +669,7 @@ fcntl(int fd, int cmd, ...)
        if (type == FDMAP_IO_SOCKET) {
            result = WSAIoctl(handle, FIONBIO, NULL, 0,&nonblocking,
                sizeof (nonblocking), &bytes_returned, NULL, NULL);
-       
+
            if(result < 0) {
                errno = WSAGetLastError();
                return -1;