diff --git a/src/client/Makefile.in b/src/client/Makefile.in index f0bdc474..9b5e5a56 100644 --- a/src/client/Makefile.in +++ b/src/client/Makefile.in @@ -88,7 +88,7 @@ play.$O: linebuf.h misc.h sysdep_w32.h proto.h ringbuf.h secure.h ringbuf.$O: misc.h sysdep_w32.h ringbuf.h secure.$O: ringbuf.h secure.h servcmd.$O: misc.h sysdep_w32.h proto.h secure.h -sysdep_w32.$O: misc.h sysdep_w32.h linebuf.h ringbuf.h secure.h +sysdep_w32.$O: misc.h sysdep_w32.h termlib.$O: misc.h version.$O: version.h $(obj): config.h diff --git a/src/client/host.c b/src/client/host.c index f662335f..d7ea626c 100644 --- a/src/client/host.c +++ b/src/client/host.c @@ -47,8 +47,6 @@ #include #include #include -#else -#define close(fd) w32_close_socket((fd)) #endif #include "misc.h" diff --git a/src/client/main.c b/src/client/main.c index 718cbf9c..3df9d3ba 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -31,7 +31,7 @@ * Dave Pare, 1986 * Steve McClure, 1998 * Ron Koenderink, 2004-2005 - * Markus Armbruster, 2005-2008 + * Markus Armbruster, 2005-2009 */ #include @@ -47,6 +47,7 @@ #ifdef _WIN32 #define getuid() 0 #define getpwuid(uid) ((void)(uid), w32_getpw()) +#define sysdep_init() w32_sysdep_init() #else #define sysdep_init() ((void)0) #endif diff --git a/src/client/play.c b/src/client/play.c index 8fa48fd4..7f5e8f45 100644 --- a/src/client/play.c +++ b/src/client/play.c @@ -28,7 +28,7 @@ * play.c: Playing the game * * Known contributors to this file: - * Markus Armbruster, 2007 + * Markus Armbruster, 2007-2009 * Ron Koenderink, 2007-2009 */ @@ -71,6 +71,11 @@ static HANDLE bounce_full; static HANDLE ctrl_c_event; static int bounce_status, bounce_error; +struct sigaction { + int sa_flags; + void (*sa_handler)(int sig); +}; + #define SIGPIPE -1 static void (*ctrl_handler)(int sig) = { SIG_DFL }; @@ -170,45 +175,45 @@ sysdep_stdin_init(void) /* * This function uses to WaitForMultipleObjects to wait for both * stdin and socket reading or writing. - * Stdin is treated special in WIN32. Waiting for stdin is done + * Stdin is treated special in WIN32. Waiting for stdin is done * via a bounce_full event which is set in the stdin thread. - * Execute command file reading is done via handle. Execute - * command is read via CreateFile/ReadFile instead open/read - * because a file descriptor is not waitable. - * WaitForMultipleObjects will only respond with one object + * Execute command file reading is done via handle. + * WaitForMultipleObjects will only respond with one object, * so an additonal select is also done to determine - * which individual events are active for the sock. + * which individual events are active. */ static int w32_select(int nfds, fd_set *rdfd, fd_set *wrfd, fd_set *errfd, struct timeval* time) { HANDLE handles[3]; SOCKET sock; - int inp, result, s_result, num_handles; + int inp, sockfd, result, s_result, num_handles; struct timeval tv_time = {0, 0}; - fd_set rdfd2; + fd_set rdsock, wrsock; switch (rdfd->fd_count) { case 1: inp = -1; - sock = rdfd->fd_array[0]; + sockfd = rdfd->fd_array[0]; break; case 2: inp = rdfd->fd_array[0]; - sock = rdfd->fd_array[1]; + sockfd = rdfd->fd_array[1]; break; default: assert(0); } + sock = W32_FD_TO_SOCKET(sockfd); assert(wrfd->fd_count == 0 - || (wrfd->fd_count == 1 && wrfd->fd_array[0] == sock)); + || (wrfd->fd_count == 1 && wrfd->fd_array[0] == (SOCKET)sockfd)); assert(inp < 0 || inp == input_fd); num_handles = 0; handles[num_handles++] = ctrl_c_event; if (inp >= 0) - handles[num_handles++] = inp ? (HANDLE)inp : bounce_full; + handles[num_handles++] + = inp ? (HANDLE)_get_osfhandle(inp) : bounce_full; /* always wait on the socket */ handles[num_handles++] = WSACreateEvent(); @@ -232,20 +237,27 @@ w32_select(int nfds, fd_set *rdfd, fd_set *wrfd, fd_set *errfd, struct timeval* return -1; } - FD_ZERO(&rdfd2); - FD_SET(sock, &rdfd2); - s_result = select(sock + 1, &rdfd2, wrfd, NULL, &tv_time); + FD_ZERO(&rdsock); + FD_ZERO(&wrsock); + FD_SET(sock, &rdsock); + if (wrfd->fd_count) + FD_SET(sock, &wrsock); + s_result = select(sock + 1, &rdsock, &wrsock, NULL, &tv_time); if (s_result < 0) { - errno = WSAGetLastError(); + w32_set_winsock_errno(); return s_result; } - *rdfd = rdfd2; - if (inp >= 0 && result == WAIT_OBJECT_0 + 1) { - FD_SET((SOCKET)inp, rdfd); + if (!FD_ISSET(sock, &rdsock)) + FD_CLR((SOCKET)sockfd, rdfd); + if (!FD_ISSET(sock, &wrsock)) + FD_CLR((SOCKET)sockfd, wrfd); + if (inp >= 0 && result == WAIT_OBJECT_0 + 1) s_result++; - } + else + FD_CLR((SOCKET)inp, rdfd); + return s_result; } @@ -282,7 +294,6 @@ w32_ring_from_file_or_bounce_buf(struct ring *r, int fd) return res; } #define ring_from_file w32_ring_from_file_or_bounce_buf -#define close(fd) w32_close_handle((fd)) #define read(sock, buffer, buf_size) \ w32_recv((sock), (buffer), (buf_size), 0) #define select(nfds, rd, wr, error, time) \ diff --git a/src/client/ringbuf.c b/src/client/ringbuf.c index 27c97a14..72ee7ba0 100644 --- a/src/client/ringbuf.c +++ b/src/client/ringbuf.c @@ -28,7 +28,7 @@ * ringbuf.c: Simple ring buffer * * Known contributors to this file: - * Markus Armbruster, 2007 + * Markus Armbruster, 2007-2009 */ #include @@ -41,7 +41,7 @@ #include #else #define readv(fd, iov, iovcnt) \ - w32_readv_handle((fd), (iov), (iovcnt)) + w32_readv_fd((fd), (iov), (iovcnt)) #define writev(fd, iov, iovcnt) \ w32_writev_socket((fd), (iov), (iovcnt)) #endif diff --git a/src/client/servcmd.c b/src/client/servcmd.c index 8d57600c..20ccfc98 100644 --- a/src/client/servcmd.c +++ b/src/client/servcmd.c @@ -31,7 +31,7 @@ * Dave Pare, 1989 * Steve McClure, 1998 * Ron Koenderink, 2005 - * Markus Armbruster, 2005-2007 + * Markus Armbruster, 2005-2009 */ #include @@ -46,13 +46,6 @@ #include "proto.h" #include "secure.h" -#ifdef _WIN32 - #define open(filename, flags, ...) \ - ((flags & O_CREAT) \ - ? w32_openfd((filename), (flags), ## __VA_ARGS__) \ - : w32_openhandle((filename), (flags))) -#endif - int eight_bit_clean; FILE *auxfp; diff --git a/src/client/sysdep_w32.c b/src/client/sysdep_w32.c index a703c228..61c129ec 100644 --- a/src/client/sysdep_w32.c +++ b/src/client/sysdep_w32.c @@ -29,18 +29,58 @@ * * Known contributors to this file: * Ron Koenderink, 2007 + * Markus Armbruster, 2009 */ #ifdef _WIN32 -#include #include #include -#include -#include #include "misc.h" -#include "linebuf.h" -#include "ringbuf.h" -#include "secure.h" + +static int +fd_is_socket(int fd, SOCKET *sockp) +{ + SOCKET sock; + WSANETWORKEVENTS ev; + + sock = W32_FD_TO_SOCKET(fd); + if (sockp) + *sockp = sock; + return WSAEnumNetworkEvents(sock, NULL, &ev) == 0; +} + +void +w32_set_winsock_errno(void) +{ + int err = WSAGetLastError(); + WSASetLastError(0); + + /* Map some WSAE* errors to the runtime library's error codes. */ + switch (err) + { + case WSA_INVALID_HANDLE: + errno = EBADF; + break; + case WSA_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + break; + case WSA_INVALID_PARAMETER: + errno = EINVAL; + break; + case WSAEWOULDBLOCK: + errno = EAGAIN; + break; + case WSAENAMETOOLONG: + errno = ENAMETOOLONG; + break; + case WSAENOTEMPTY: + errno = ENOTEMPTY; + break; + default: + errno = (err > 10000 && err < 10025) ? err - 10000 : err; + break; + } +} /* * Get user name in the WIN32 environment @@ -50,12 +90,12 @@ w32_getpw(void) { static char unamebuf[128]; static struct passwd pwd; - long unamesize; + DWORD unamesize; unamesize = sizeof(unamebuf); if (GetUserName(unamebuf, &unamesize)) { pwd.pw_name = unamebuf; - if ((unamesize <= 0 ) || (strlen(unamebuf) <= 0)) + if (unamesize == 0 || strlen(unamebuf) == 0) pwd.pw_name = "nobody"; } else pwd.pw_name = "nobody"; @@ -67,7 +107,7 @@ w32_getpw(void) * set up stdout to work around bugs */ void -sysdep_init(void) +w32_sysdep_init(void) { int err; WSADATA WsaData; @@ -92,16 +132,20 @@ sysdep_init(void) */ #undef socket int -w32_socket(int family, int sock_type, int protocol) +w32_socket(int domain, int type, int protocol) { - SOCKET result; + SOCKET sock; - result = socket(family, sock_type, protocol); - if (result == INVALID_SOCKET) { - errno = WSAGetLastError(); + /* + * We have to use WSASocket() to create non-overlapped IO sockets. + * Overlapped IO sockets cannot be used with read/write. + */ + sock = WSASocket(domain, type, protocol, NULL, 0, 0); + if (sock == INVALID_SOCKET) { + w32_set_winsock_errno(); return -1; } - return (int)result; + return W32_SOCKET_TO_FD(sock); } /* @@ -109,13 +153,15 @@ w32_socket(int family, int sock_type, int protocol) */ #undef connect int -w32_connect(int sock, struct sockaddr *addr, int addrlen) +w32_connect(int sockfd, const struct sockaddr *addr, int addrlen) { + SOCKET sock = W32_FD_TO_SOCKET(sockfd); int result; - result = connect(sock, addr, addrlen); + result = connect(sock, addr, addrlen); if (result == SOCKET_ERROR) { - errno = WSAGetLastError(); + /* FIXME map WSAEWOULDBLOCK to EINPROGRESS */ + w32_set_winsock_errno(); return -1; } return result; @@ -126,13 +172,14 @@ w32_connect(int sock, struct sockaddr *addr, int addrlen) */ #undef recv int -w32_recv(int socket, char *buffer, size_t buf_size, int flags) +w32_recv(int sockfd, void *buffer, size_t buf_size, int flags) { + SOCKET socket = W32_FD_TO_SOCKET(sockfd); int result; result = recv(socket, buffer, buf_size, flags); if (result == SOCKET_ERROR) { - errno = WSAGetLastError(); + w32_set_winsock_errno(); return -1; } return result; @@ -143,10 +190,11 @@ w32_recv(int socket, char *buffer, size_t buf_size, int flags) * Modelled after the GNU's libc/sysdeps/posix/writev.c */ ssize_t -w32_writev_socket(int fd, const struct iovec *iov, int iovcnt) +w32_writev_socket(int sockfd, const struct iovec *iov, int iovcnt) { + SOCKET sock = W32_FD_TO_SOCKET(sockfd); int i; - unsigned char *buffer, *buffer_location; + char *buffer, *buffer_location; size_t total_bytes = 0; int bytes_written; @@ -165,12 +213,10 @@ w32_writev_socket(int fd, const struct iovec *iov, int iovcnt) buffer_location += iov[i].iov_len; } - bytes_written = send(fd, buffer, total_bytes, 0); - + bytes_written = send(sock, buffer, total_bytes, 0); free(buffer); - if (bytes_written == SOCKET_ERROR) { - errno = WSAGetLastError(); + w32_set_winsock_errno(); return -1; } return bytes_written; @@ -180,87 +226,38 @@ w32_writev_socket(int fd, const struct iovec *iov, int iovcnt) * POSIX compatible send() replacement */ int -w32_send(int socket, char *buffer, size_t buf_size, int flags) -{ - int result; - - result = send(socket, buffer, buf_size, flags); - if (result == SOCKET_ERROR) - errno = WSAGetLastError(); - return result; -} - -/* - * POSIX compatible close() replacement specialized to sockets. - */ -int -w32_close_socket(int fd) +w32_send(int sockfd, const void *buffer, size_t buf_size, int flags) { + SOCKET socket = W32_FD_TO_SOCKET(sockfd); int result; - result = closesocket(fd); + result = send(socket, buffer, buf_size, flags); if (result == SOCKET_ERROR) - errno = WSAGetLastError(); + w32_set_winsock_errno(); return result; } /* - * POSIX compatible open() replacement + * POSIX compatible close() replacement */ int -w32_openfd(const char *fname, int oflag, ...) +w32_close(int fd) { - va_list ap; - int pmode = 0; - int fd; - int create_permission = 0; + SOCKET sock; - if (oflag & O_CREAT) { - va_start(ap, oflag); - pmode = va_arg(ap, int); - va_end(ap); - - if (pmode & 0400) - create_permission |= _S_IREAD; - if (pmode & 0200) - create_permission |= _S_IWRITE; - } - - fd = _open(fname, oflag, create_permission); - return fd; -} -/* - * Open a file for reading, return its handle. - * This can be used in place of open() when a handle is desired for - * waiting on it with WaitForMultipleObjects() or similar. - * Ensure the handle is not zero in order to prevent a problem - * input_fd. - */ -int -w32_openhandle(const char *fname, int oflag) -{ - HANDLE handle; - - handle = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (handle == INVALID_HANDLE_VALUE) { - errno = GetLastError(); - return -1; - } - if (handle == 0) { - HANDLE dup_handle; - if (!DuplicateHandle(GetCurrentProcess(), handle, - GetCurrentProcess(), &dup_handle, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - errno = GetLastError(); + if (fd_is_socket(fd, &sock)) { + if (closesocket(sock)) { + w32_set_winsock_errno(); return -1; - } else { - CloseHandle(handle); - handle = dup_handle; } + /* + * This always fails because the underlying handle is already + * gone, but it closes the fd just fine. + */ + _close(fd); + return 0; } - return (int)handle; + return _close(fd); } /* @@ -268,12 +265,12 @@ w32_openhandle(const char *fname, int oflag) * Modelled after the GNU's libc/sysdeps/posix/readv.c */ ssize_t -w32_readv_handle(int fd, const struct iovec *iov, int iovcnt) +w32_readv_fd(int fd, const struct iovec *iov, int iovcnt) { int i; - unsigned char *buffer, *buffer_location; + char *buffer, *buffer_location; size_t total_bytes = 0; - DWORD bytes_read; + int bytes_read; size_t bytes_left; for (i = 0; i < iovcnt; i++) { @@ -286,11 +283,9 @@ w32_readv_handle(int fd, const struct iovec *iov, int iovcnt) return -1; } - if (!ReadFile((HANDLE)fd, buffer, total_bytes, &bytes_read, NULL)) { - free(buffer); - errno = GetLastError(); + bytes_read = read(fd, buffer, total_bytes); + if (bytes_read < 0) return -1; - } bytes_left = bytes_read; buffer_location = buffer; @@ -306,23 +301,7 @@ w32_readv_handle(int fd, const struct iovec *iov, int iovcnt) } free(buffer); - return bytes_read; } -/* - * POSIX compatible close() replacement specialized to files. - * Hack: expects a handle, cannot be used with a file descriptor. - */ -int -w32_close_handle(int fd) -{ - int result; - - result = CloseHandle((HANDLE)fd); - - if (!result) - errno = GetLastError(); - return result; -} #endif /* _WIN32 */ diff --git a/src/client/sysdep_w32.h b/src/client/sysdep_w32.h index 9274af3a..43283602 100644 --- a/src/client/sysdep_w32.h +++ b/src/client/sysdep_w32.h @@ -29,13 +29,13 @@ * * Known contributors to this file: * Ron Koenderink, 2007 + * Markus Armbruster, 2009 */ #ifndef _SYSDEF_W32_H #include #include #include -#include extern int getopt(int, char * const[], const char *); extern char *optarg; @@ -54,35 +54,32 @@ struct iovec { size_t iov_len; }; -struct sigaction { - int sa_flags; - void (*sa_handler)(int sig); -}; +#define W32_FD_TO_SOCKET(fd) ((SOCKET)_get_osfhandle((fd))) +#define W32_SOCKET_TO_FD(fh) (_open_osfhandle((long)(fh), O_RDWR | O_BINARY)) -extern int w32_recv(int socket, char *buffer, - size_t buf_size, int flags); -extern int w32_send(int socket, char *buffer, - size_t buf_size, int flags); -extern int w32_close_socket(int fd); -extern int w32_socket(int family, int sock_type, int protocol); -extern int w32_connect(int sock, struct sockaddr *addr, int addrlen); -extern int w32_close_handle(int fd); -extern ssize_t w32_readv_handle(int fd, const struct iovec *iov, - int iovcnt); -extern ssize_t w32_writev_socket(int fd, const struct iovec *iov, +extern void w32_set_winsock_errno(void); + +extern int w32_recv(int sockfd, void *, size_t, int flags); +extern int w32_send(int sockfd, const void *, size_t, int flags); +extern int w32_close(int fd); +extern int w32_socket(int domain, int type, int protocol); +extern int w32_connect(int sockfd, const struct sockaddr *, int addrlen); +extern ssize_t w32_readv_fd(int fd, const struct iovec *iov, + int iovcnt); +extern ssize_t w32_writev_socket(int sockfd, const struct iovec *iov, int iovcnt); -extern int w32_openfd(const char *fname, int oflag, ...); -extern int w32_openhandle(const char *fname, int oflag); extern struct passwd *w32_getpw(void); -extern void sysdep_init(void); +extern void w32_sysdep_init(void); -#define recv(sock, buffer, buf_size, flags) \ - w32_recv((sock), (buffer), (buf_size), (flags)) -#define socket(family, sock_type, protocol) \ - w32_socket((family), (sock_type), (protocol)) -#define connect(sock, addr, addrlen) \ - w32_connect((sock), (addr), (addrlen)) +#define recv(sockfd, buffer, buf_size, flags) \ + w32_recv((sockfd), (buffer), (buf_size), (flags)) +#define close(fd) \ + w32_close((fd)) +#define socket(domain, type, protocol) \ + w32_socket((domain), (type), (protocol)) +#define connect(sockfd, addr, addrlen) \ + w32_connect((sockfd), (addr), (addrlen)) #define pclose _pclose #define popen _popen