From: Ron Koenderink Date: Tue, 11 Dec 2007 22:00:25 +0000 (+0000) Subject: (w32_getpw, w32_socket, w32_connect, w32_recv, w32_send, X-Git-Tag: v4.3.11~39 X-Git-Url: http://git.pond.sub.org/?p=empserver;a=commitdiff_plain;h=f082ef9fa629192fdf7ba656fb1c3bc1d7de73cb (w32_getpw, w32_socket, w32_connect, w32_recv, w32_send, w32_writev_socket, w32_close_socket, getpass, w32_openfd, w32_openhandle, w32_readv_handle, w32_close_handle, sysdep_init, sysdep_stdin_init, w32_select, w32_signal_handler, sigaction, stdin_read_thread, w32_ring_from_file_to_bounce_buf) [_WIN32]: New w32 equivalent functions for POSIX functions. (recvline, sendcmd, tcp_connect, hostconnect, getpass, main, intr, play, ring_to_file, ring_from_file, doexecute, doredir) [_WIN32]: Use new WIN32 equivalent functions. (main) [_WIN32]: Add sysdep_init() to support system dependent initialization for equivalence functions. (play) [_WIN32]: Add sysdef_stdin_init() to support system dependent initialization for reading stdin. (recv_input, play) [_WIN32]: Replace the calls to ring_to_file() and select() with WIN32 specific enhanced versions. Makefile.in: update dependencies with new files. Make.mk: Add using of getopt.c and getopt.h from src/lib/w32 directory. Add getopt.c and getopt.h to tar for client. --- diff --git a/Make.mk b/Make.mk index be6130245..9b838683f 100644 --- a/Make.mk +++ b/Make.mk @@ -261,7 +261,7 @@ info.html/%.html: info/%.t $(server): $(filter src/server/% src/lib/as/% src/lib/commands/% src/lib/player/% src/lib/subs/% src/lib/update/%, $(obj)) $(empth_obj) $(libs) $(empth_lib) $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ -$(client): $(filter src/client/%, $(obj)) src/lib/global/version.o +$(client): $(filter src/client/%, $(obj)) src/lib/global/version.o src/lib/w32/getopt.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ $(util): $(libs) @@ -332,6 +332,7 @@ dist-client: $(cli_distgen) $(notdir $(filter src/client/%, $(src)) $(cli_distgen)) \ -C $(srcdir)/include proto.h version.h \ -C $(srcdir)/src/lib/global version.c \ + -C $(srcdir)/src/lib/w32 getopt.h getopt.c \ -C $(srcdir)/man empire.6 \ -C $(srcdir) COPYING INSTALL install-sh diff --git a/src/client/Makefile.in b/src/client/Makefile.in index 6c8b0a053..0d9d2ca4e 100644 --- a/src/client/Makefile.in +++ b/src/client/Makefile.in @@ -79,15 +79,16 @@ uninstall: rm $(mandir)/man6/empire.6 # FIXME generate from .d -expect.$O: misc.h -host.$O: misc.h +expect.$O: misc.h sysdep_w32.h +host.$O: misc.h sysdep_w32.h linebuf.$O: linebuf.h -login.$O: misc.h proto.h -main.$O: misc.h version.h -play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h +login.$O: misc.h proto.h sysdep_w32.h +main.$O: misc.h version.h sysdep_w32.h +play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h sysdep_w32.h ringbuf.$O: ringbuf.h secure.$O: ringbuf.h secure.h -servcmd.$O: misc.h proto.h secure.h -termlib.$O: misc.h +servcmd.$O: misc.h proto.h secure.h sysdep_w32.h +sysdep_w32.$O: misc.h sysdep_w32.h +termlib.$O: misc.h sysdep_w32.h version.$O: version.h $(obj): config.h diff --git a/src/client/expect.c b/src/client/expect.c index 1c7770732..5ea380a05 100644 --- a/src/client/expect.c +++ b/src/client/expect.c @@ -44,6 +44,15 @@ #endif #include "misc.h" +#ifdef _WIN32 +#define recv(sock, buffer, buf_size, flags) \ + w32_recv((sock), (buffer), (buf_size), (flags)) +#define read(sock, buffer, buf_size) \ + w32_recv((sock), (buffer), (buf_size), 0) +#define write(sock, buffer, buf_size) \ + w32_send((sock), (buffer), (buf_size), 0) +#endif + int recvline(int s, char *buf) { @@ -55,15 +64,10 @@ recvline(int s, char *buf) int cc; size = 1024; -#ifndef _WIN32 (void)alarm(30); -#endif ptr = buf; n = recv(s, ptr, size, MSG_PEEK); if (n <= 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); -#endif perror("recv"); return 0; } @@ -71,15 +75,8 @@ recvline(int s, char *buf) buf[n] = '\0'; if ((p = strchr(ptr, '\n')) == NULL) { do { -#ifndef _WIN32 cc = read(s, ptr, n); -#else - cc = recv(s, ptr, n, 0); -#endif if (cc < 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); -#endif perror("expect: read"); return 0; } @@ -89,9 +86,6 @@ recvline(int s, char *buf) } ptr += n; if ((n = recv(s, ptr, size, MSG_PEEK)) <= 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); -#endif perror("recv"); return 0; } @@ -102,15 +96,8 @@ recvline(int s, char *buf) *p = 0; } else newline = 1 + p - ptr; -#ifndef _WIN32 cc = read(s, buf, newline); -#else - cc = recv(s, buf, newline, 0); -#endif if (cc < 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); -#endif perror("expect: read #2"); return 0; } @@ -120,9 +107,7 @@ recvline(int s, char *buf) return 0; } buf[newline] = '\0'; -#ifndef _WIN32 (void)alarm(0); -#endif if (!isxdigit(buf[0]) || buf[1] != ' ') { fprintf(stderr, "Malformed line %s\n", buf); return 0; @@ -146,15 +131,8 @@ sendcmd(int s, char *cmd, char *arg) (void)sprintf(buf, "%s %s\n", cmd, arg != NULL ? arg : ""); len = strlen(buf); -#ifndef _WIN32 cc = write(s, buf, len); -#else - cc = send(s, buf, len, 0); -#endif if (cc < 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); -#endif perror("sendcmd: write"); } if (cc != len) { diff --git a/src/client/host.c b/src/client/host.c index cb309721c..7429f45ab 100644 --- a/src/client/host.c +++ b/src/client/host.c @@ -48,8 +48,7 @@ #include #include #else -#include -#include +#define close(fd) w32_close_socket((fd)) #endif #include "misc.h" @@ -83,11 +82,7 @@ tcp_connect(char *host, char *serv) if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) break; /* success */ -#ifdef _WIN32 - closesocket(sockfd); /* ignore this one */ -#else close(sockfd); /* ignore this one */ -#endif } while ((res = res->ai_next) != NULL); if (res == NULL) { /* errno set from final connect() */ @@ -147,19 +142,11 @@ hostconnect(struct sockaddr_in *addr) s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); -#endif return -1; } addr->sin_family = AF_INET; if (connect(s, (struct sockaddr *)addr, sizeof(*addr)) < 0) { -#ifdef _WIN32 - errno = WSAGetLastError(); - (void)closesocket(s); -#else (void)close(s); -#endif return -1; } return s; diff --git a/src/client/login.c b/src/client/login.c index 7fa41bdce..695ac3860 100644 --- a/src/client/login.c +++ b/src/client/login.c @@ -89,21 +89,9 @@ login(int s, char *uname, char *cname, char *cpass, return 0; } if (cpass == NULL) { -#ifndef _WIN32 cpass = getpass("Your name? "); if (cpass == NULL || *cpass == 0) return 0; -#else - printf("Note: This is echoed to the screen\n"); - printf("Your name? "); - fflush(stdout); - cpass = fgets(tmp, sizeof(tmp), stdin); - if (cpass == NULL || *cpass == 0) - return 0; - len = strlen(cpass); - if (cname[len-1] == '\n') - cname[len-1] = 0; -#endif } (void)printf("\n"); (void)sendcmd(s, "pass", cpass); diff --git a/src/client/main.c b/src/client/main.c index cd0f6fc25..62c667ae5 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -36,12 +36,21 @@ #include +#ifndef _WIN32 #include #include #include +#endif #include "misc.h" #include "version.h" +#ifdef _WIN32 +#define getuid() 0 +#define getpwuid(uid) ((uid), w32_getpw()) +#else +#define sysdep_init() ((void)0) +#endif + static void print_usage(char *program_name) { @@ -68,21 +77,6 @@ main(int argc, char **argv) char *host; char *port; int sock; -#ifdef _WIN32 - char unamebuf[128]; -#endif - -#ifdef _WIN32 - /* - * stdout is unbuffered under Windows if connected to a character - * device, and putchar() screws up when printing multibyte strings - * bytewise to an unbuffered stream. Switch stdout to line- - * buffered mode. Unfortunately, ISO C allows implementations to - * screw that up, and of course Windows does. Manual flushing - * after each prompt is required. - */ - setvbuf(stdout, NULL, _IOLBF, 4096); -#endif while ((opt = getopt(argc, argv, "2:kuhv")) != EOF) { switch (opt) { @@ -124,7 +118,6 @@ main(int argc, char **argv) host = empirehost; uname = getenv("LOGNAME"); if (uname == NULL) { -#ifndef _WIN32 struct passwd *pwd; pwd = getpwuid(getuid()); @@ -133,17 +126,6 @@ main(int argc, char **argv) exit(1); } uname = pwd->pw_name; -#else - DWORD unamesize; - - unamesize = sizeof(unamebuf); - if (GetUserName(unamebuf, &unamesize)) { - uname = unamebuf; - if ((unamesize <= 0 ) || (strlen(uname) <= 0)) - uname = "nobody"; - } else - uname = "nobody"; -#endif } getsose(); @@ -152,13 +134,7 @@ main(int argc, char **argv) exit(1); } -#ifdef _WIN32 - err = WSAStartup(MAKEWORD(2, 0), &WsaData); - if (err != 0) { - printf("WSAStartup Failed, error code %d\n", err); - exit(1); - } -#endif + sysdep_init(); sock = tcp_connect(host, port); diff --git a/src/client/misc.h b/src/client/misc.h index 8cb8acd39..2b6329471 100644 --- a/src/client/misc.h +++ b/src/client/misc.h @@ -36,10 +36,11 @@ #include #ifdef _WIN32 -#include +#include "sysdep_w32.h" #endif #define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) extern char empirehost[]; extern char empireport[]; @@ -50,13 +51,7 @@ extern FILE *auxfp; extern char *SO; extern char *SE; -#ifdef _WIN32 -#define getsose() ((void)0) -#define putso() ((void)0) -#define putse() ((void)0) -#define pclose _pclose -#define popen _popen -#else +#ifndef _WIN32 void getsose(void); void putso(void); void putse(void); diff --git a/src/client/play.c b/src/client/play.c index 7cd4e5b5f..9435f5079 100644 --- a/src/client/play.c +++ b/src/client/play.c @@ -29,6 +29,7 @@ * * Known contributors to this file: * Markus Armbruster, 2007 + * Ron Koenderink, 2007 */ #include @@ -38,15 +39,254 @@ #include #include #include +#ifndef _WIN32 #include #include #include +#else +#include +#endif #include "linebuf.h" #include "misc.h" #include "proto.h" #include "ringbuf.h" #include "secure.h" +#ifdef _WIN32 +static CRITICAL_SECTION signal_critical_section; +static LPCRITICAL_SECTION signal_critical_section_ptr = NULL; + +static unsigned char bounce_buf[RING_SIZE]; +/* + * Set bounce_empty to indicate bounce_buf is available for the stdin thread + * to use. + */ +static HANDLE bounce_empty; +/* + * Set bounce_full to indicate bounce_buf is contains data from the + * stdin thread and is available for recv_input + */ +static HANDLE bounce_full; + /* Ctrl-C (SIGINT) was detected, generate EINTR for the w32_select() */ +static HANDLE ctrl_c_event; +static int bounce_status, bounce_error; + +#define SIGPIPE -1 +static void (*ctrl_handler)(int sig) = { SIG_DFL }; + +/* + * Ctrl-C handler for emulating the SIGINT in WIN32 + */ +static BOOL WINAPI +w32_signal_handler(DWORD ctrl_type) +{ + if (ctrl_type == CTRL_C_EVENT) { + EnterCriticalSection(signal_critical_section_ptr); + if (ctrl_handler != SIG_DFL) { + ctrl_handler(SIGINT); + LeaveCriticalSection(signal_critical_section_ptr); + SetEvent(ctrl_c_event); + return TRUE; + } else + LeaveCriticalSection(signal_critical_section_ptr); + } + return FALSE; +} + +/* + * WIN32 equivalent for sigaction supports the following: + * set handler for SIGINT using WIN32 Ctrl-C handler + * reset handler SIGINT to SIG_DFL + * ignore SIGPIPE + */ +static int +sigaction(int signal, struct sigaction *action, struct sigaction *oaction) +{ + assert(!oaction); + assert(action); + + if (signal == SIGPIPE) + assert(action->sa_handler == SIG_IGN); + else { + assert(signal == SIGINT && action->sa_handler != SIG_IGN); + if (ctrl_handler == action->sa_handler) + return 0; + if (signal_critical_section_ptr == NULL) { + signal_critical_section_ptr = &signal_critical_section; + InitializeCriticalSection(signal_critical_section_ptr); + } + EnterCriticalSection(signal_critical_section_ptr); + if (!SetConsoleCtrlHandler(w32_signal_handler, + action->sa_handler != SIG_DFL)) { + errno = GetLastError(); + LeaveCriticalSection(signal_critical_section_ptr); + return -1; + } + ctrl_handler = action->sa_handler; + LeaveCriticalSection(signal_critical_section_ptr); + } + return 0; +} + +/* + * Read the stdin in WIN32 environment + * WIN32 does not support select type function on console input + * so the client uses a separate thread to read input + */ +static DWORD WINAPI +stdin_read_thread(LPVOID lpParam) +{ + for (;;) { + if (WaitForSingleObject(bounce_empty, INFINITE) != WAIT_OBJECT_0) + break; + bounce_status = _read(0, bounce_buf, sizeof(bounce_buf)); + bounce_error = errno; + if (bounce_status == 0) { + if (_isatty(0)) { + SetEvent(bounce_empty); + continue; + } else + break; + } + SetEvent(bounce_full); + } + SetEvent(bounce_full); + return 0; +} + +/* + * Initialize and start the stdin reading thread for WIN32 + */ +static void +sysdep_stdin_init() +{ + bounce_empty = CreateEvent(NULL, FALSE, TRUE, "bounce_empty"); + bounce_full = CreateEvent(NULL, TRUE, FALSE, "bounce_full"); + ctrl_c_event = CreateEvent(NULL, FALSE, FALSE, "Ctrl_C"); + CreateThread(NULL, 0, stdin_read_thread, NULL, 0, NULL); +} + +/* + * 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 + * 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 + * so an additonal select is also done to determine + * which individual events are active for the sock. + */ +static int +w32_select(int nfds, fd_set *rdfd, fd_set *wrfd, fd_set *errfd, struct timeval* time) +{ + HANDLE handles[3]; + SOCKET sock; + int result, s_result, num_handles = 0; + struct timeval tv_time = {0, 0}; + fd_set rdfd2; + + if (rdfd->fd_count > 1) { + sock = rdfd->fd_array[1]; + if (rdfd->fd_array[0]) + handles[num_handles++] = (HANDLE)rdfd->fd_array[0]; + else { + handles[num_handles++] = ctrl_c_event; + handles[num_handles++] = bounce_full; + } + } else { + assert(rdfd->fd_count == 1); + sock = rdfd->fd_array[0]; + } + assert(wrfd->fd_count == 0 || + (wrfd->fd_count == 1 && wrfd->fd_array[0] == sock)); + /* always wait on the socket */ + handles[num_handles++] = WSACreateEvent(); + + if (wrfd->fd_count > 0) + WSAEventSelect(sock, handles[num_handles - 1], + FD_READ | FD_WRITE | FD_CLOSE); + else + WSAEventSelect(sock, handles[num_handles - 1], + FD_READ | FD_CLOSE); + + result = WaitForMultipleObjects(num_handles, handles, 0, INFINITE); + if (result < 0) { + errno = GetLastError(); + WSACloseEvent(handles[num_handles - 1]); + return -1; + } + WSACloseEvent(handles[num_handles - 1]); + + if (num_handles == 3 && result == WAIT_OBJECT_0) { + errno = EINTR; + return -1; + } + + FD_ZERO(&rdfd2); + FD_SET(sock, &rdfd2); + s_result = select(sock + 1, &rdfd2, wrfd, NULL, &tv_time); + + if (s_result < 0) { + errno = WSAGetLastError(); + return s_result; + } + + *rdfd = rdfd2; + if (num_handles == 3 && result == WAIT_OBJECT_0 + 1) { + FD_SET((SOCKET)0, rdfd); + s_result++; + } + if (num_handles == 2 && result == WAIT_OBJECT_0) { + FD_SET((SOCKET)handles[0], rdfd); + s_result++; + } + return s_result; +} + +/* + * Read input from the user either stdin or from file. + * For stdin, read from bounce_buf which filled by the stdin thread + * otherwise use the regular ring_from_file. + */ +static int +w32_ring_from_file_or_bounce_buf(struct ring *r, int fd) +{ + int i, res; + + if (fd) + return ring_from_file(r, fd); + + if (bounce_status < 0) { + errno = bounce_error; + res = bounce_status; + } else { + for (i = 0; i < bounce_status; i++) { + if (ring_putc(r, bounce_buf[i]) == EOF) { + /* more work to do, hold on to bounce_buf */ + memmove(bounce_buf, bounce_buf + i, bounce_status - i); + bounce_status -= i; + return i; + } + } + res = i; + } + + ResetEvent(bounce_full); + SetEvent(bounce_empty); + 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) \ + w32_select((nfds), (rd), (wr), (error), (time)) +#else +#define sysdep_stdin_init() ((void)0) +#endif + #define EOF_COOKIE "ctld\n" #define INTR_COOKIE "\naborted\n" @@ -197,9 +437,6 @@ static void intr(int sig) { send_intr = 1; -#ifdef _WIN32 - signal(SIGINT, intr); -#endif } /* @@ -231,6 +468,7 @@ play(int sock) ring_init(&inbuf); eof_fd0 = send_eof = send_intr = 0; input_fd = 0; + sysdep_stdin_init(&eof_fd0, &inbuf); for (;;) { FD_ZERO(&rdfd); diff --git a/src/client/ringbuf.c b/src/client/ringbuf.c index f8ef4daf6..95c9c0db1 100644 --- a/src/client/ringbuf.c +++ b/src/client/ringbuf.c @@ -36,8 +36,16 @@ #include #include #include +#ifndef _WIN32 #include #include +#else +#define readv(fd, iov, iovcnt) \ + w32_readv_handle((fd), (iov), (iovcnt)) +#define writev(fd, iov, iovcnt) \ + w32_writev_socket((fd), (iov), (iovcnt)) +#endif +#include "misc.h" #include "ringbuf.h" /* diff --git a/src/client/servcmd.c b/src/client/servcmd.c index 18d095615..526c93450 100644 --- a/src/client/servcmd.c +++ b/src/client/servcmd.c @@ -46,6 +46,13 @@ #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 new file mode 100644 index 000000000..9a3bad92f --- /dev/null +++ b/src/client/sysdep_w32.c @@ -0,0 +1,366 @@ +/* + * Empire - A multi-player, client/server Internet based war game. + * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- + * + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. + * + * --- + * + * sysdep_w32.c: system dependent functions for WIN32 environments + * + * Known contributors to this file: + * Ron Koenderink, 2007 + */ + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include "misc.h" +#include "linebuf.h" +#include "ringbuf.h" +#include "secure.h" + +/* + * Ignore alarm for WIN32 client + */ +int +alarm(int time) +{ + return 0; +} + +/* + * Get user name in the WIN32 environment + */ +struct passwd * +w32_getpw(void) +{ + static char unamebuf[128]; + static struct passwd pwd; + long unamesize; + + unamesize = sizeof(unamebuf); + if (GetUserName(unamebuf, &unamesize)) { + pwd.pw_name = unamebuf; + if ((unamesize <= 0 ) || (strlen(unamebuf) <= 0)) + pwd.pw_name = "nobody"; + } else + pwd.pw_name = "nobody"; + return &pwd; +} + +/* + * Initialize the WIN32 socket library and + * set up stdout to work around bugs + */ +void +sysdep_init(void) +{ + int err; + WSADATA WsaData; + /* + * stdout is unbuffered under Windows if connected to a character + * device, and putchar() screws up when printing multibyte strings + * bytewise to an unbuffered stream. Switch stdout to line- + * buffered mode. Unfortunately, ISO C allows implementations to + * screw that up, and of course Windows does. Manual flushing + * after each prompt is required. + */ + setvbuf(stdout, NULL, _IOLBF, 4096); + err = WSAStartup(MAKEWORD(2, 0), &WsaData); + if (err != 0) { + printf("WSAStartup Failed, error code %d\n", err); + exit(1); + } +} + +/* + * POSIX compatible socket() replacement + */ +#undef socket +int +w32_socket(int family, int sock_type, int protocol) +{ + int result; + + result = socket(family, sock_type, protocol); + if (result == INVALID_SOCKET) { + errno = WSAGetLastError(); + return -1; + } + return result; +} + +/* + * POSIX compatible connect() replacement + */ +#undef connect +int +w32_connect(int sock, struct sockaddr *addr, int addrlen) +{ + int result; + + result = connect(sock, addr, addrlen); + if (result == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return result; +} + +/* + * POSIX compatible recv() replacement + */ +#undef recv +int +w32_recv(int socket, char *buffer, size_t buf_size, int flags) +{ + int result; + + result = recv(socket, buffer, buf_size, flags); + if (result == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return result; +} + +/* + * POSIX compatible writev() replacement specialized to sockets + * Modelled after the GNU's libc/sysdeps/posix/writev.c + */ +ssize_t +w32_writev_socket(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 = send(fd, buffer, total_bytes, 0); + + free(buffer); + + if (bytes_written == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return bytes_written; +} + +/* + * 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) +{ + int result; + + result = closesocket(fd); + if (result == SOCKET_ERROR) + errno = WSAGetLastError(); + return result; +} + +/* + * WIN32 equivalent for getpass + */ +char * +getpass(char *prompt) +{ + static char tmp[128]; + int len; + char *cpass; + DWORD mode; + HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE); + + if (GetConsoleMode(input_handle, &mode)) + SetConsoleMode(input_handle, mode & ~ENABLE_ECHO_INPUT); + else + printf("Note: This is echoed to the screen\n"); + printf("%s", prompt); + fflush(stdout); + cpass = fgets(tmp, sizeof(tmp), stdin); + if (GetConsoleMode(input_handle, &mode)) + SetConsoleMode(input_handle, mode | ENABLE_ECHO_INPUT); + if (cpass == NULL) + return NULL; + len = strlen(cpass); + if (tmp[len - 1] == '\n') + tmp[len - 1] = 0; + return cpass; +} + +/* + * POSIX compatible open() replacement + */ +int +w32_openfd(const char *fname, int oflag, ...) +{ + va_list ap; + int pmode = 0; + int fd; + int create_permission = 0; + + 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(); + return -1; + } else { + CloseHandle(handle); + handle = dup_handle; + } + } + return (int)handle; +} + +/* + * POSIX compatible readv() replacement specialized to files. + * Modelled after the GNU's libc/sysdeps/posix/readv.c + */ +ssize_t +w32_readv_handle(int fd, const struct iovec *iov, int iovcnt) +{ + int i; + unsigned char *buffer, *buffer_location; + size_t total_bytes = 0; + DWORD 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; + } + + if (!ReadFile((HANDLE)fd, buffer, total_bytes, &bytes_read, NULL)) { + free(buffer); + errno = GetLastError(); + 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 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 new file mode 100644 index 000000000..2cb5580eb --- /dev/null +++ b/src/client/sysdep_w32.h @@ -0,0 +1,95 @@ +/* + * Empire - A multi-player, client/server Internet based war game. + * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- + * + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. + * + * --- + * + * sysdep_w32.h: system dependent support for WIN32 environments + * + * Known contributors to this file: + * Ron Koenderink, 2007 + */ + +#ifndef _SYSDEF_W32_H +#include +#include +#include +#include + +extern int getopt(int, char * const[], const char *); +extern char *optarg; +extern int optind, opterr, optopt; + +#ifdef _MSC_VER +typedef int __w64 ssize_t; +#endif + +struct passwd { + char *pw_name; +}; + +struct iovec { + void *iov_base; + size_t iov_len; +}; + +struct sigaction { + int sa_flags; + void (*sa_handler)(int sig); +}; + +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, + int iovcnt); +extern int w32_createfd(const char *fname, int oflag, ...); +extern int w32_openhandle(const char *fname, int oflag); + +extern int alarm(int time); +extern struct passwd *w32_getpw(void); +extern char *getpass(char *prompt); +extern void 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 pclose _pclose +#define popen _popen +#define snprintf _snprintf +#define getsose() ((void)0) +#define putso() ((void)0) +#define putse() ((void)0) +#endif /* sysdef_w32.h */