/*
* 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 "unistd.h"
+#include "misc.h"
#include "sys/uio.h"
-#include "empio.h"
-#include "prototypes.h"
+#include "unistd.h"
/*
* FD_SETSIZE is the size for the maximum number of sockets.
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.
*/
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))
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;
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;
}
*/
#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))
}
#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))
+ }
}
/*
int
posix_socket(int domain, int type, int protocol)
{
- int handle;
+ SOCKET handle;
int new_fd;
-
+
if ((new_fd = get_fd()) < 0)
return -1;
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; \
\
return result;
case FDMAP_IO_FILE:
return _close(handle);
+ default:
+ CANT_REACH();
+ return -1;
}
- CANT_REACH();
- return -1;
}
/*
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(),
/*
* 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))
}
* 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);
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))
}
buffer = malloc(total_bytes);
- if (buffer == NULL)
+ if (buffer == NULL && total_bytes != 0) {
+ errno = ENOMEM;
return -1;
+ }
bytes_read = posix_read(fd, buffer, total_bytes);
if (bytes_read <= 0) {
/*
* 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))
for (i = 0; i < iovcnt; i++)
total_bytes += iov[i].iov_len;
- if (total_bytes == 0)
- return 0;
-
buffer = malloc(total_bytes);
- if (buffer == NULL)
+ if (buffer == NULL && total_bytes != 0) {
+ errno = ENOMEM;
return -1;
+ }
buffer_location = buffer;
for (i = 0; i < iovcnt; i++) {
* handle is reused.
*/
int
-posix_fileno(FILE *stream)
+fileno(FILE *stream)
{
int fd;
int handle;
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;