]> git.pond.sub.org Git - empserver/blob - src/client/sysdep_w32.c
(w32_getpw, w32_socket, w32_connect, w32_recv, w32_send,
[empserver] / src / client / sysdep_w32.c
1 /*
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
5  *
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.
10  *
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.
15  *
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
19  *
20  *  ---
21  *
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.
25  *
26  *  ---
27  *
28  *  sysdep_w32.c: system dependent functions for WIN32 environments
29  * 
30  *  Known contributors to this file:
31  *     Ron Koenderink, 2007
32  */
33
34 #ifdef _WIN32
35 #include <assert.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <io.h>
39 #include <sys/stat.h>
40 #include "misc.h"
41 #include "linebuf.h"
42 #include "ringbuf.h"
43 #include "secure.h"
44
45 /*
46  * Ignore alarm for WIN32 client
47  */
48 int 
49 alarm(int time)
50 {
51     return 0;
52 }
53
54 /*
55  * Get user name in the WIN32 environment
56  */
57 struct passwd *
58 w32_getpw(void)
59 {
60     static char unamebuf[128];
61     static struct passwd pwd;
62     long unamesize;
63
64     unamesize = sizeof(unamebuf);
65     if (GetUserName(unamebuf, &unamesize)) {
66         pwd.pw_name = unamebuf;
67         if ((unamesize <= 0 ) || (strlen(unamebuf) <= 0))
68             pwd.pw_name = "nobody";
69     } else
70         pwd.pw_name = "nobody";
71     return &pwd;
72 }
73
74 /*
75  * Initialize the WIN32 socket library and
76  * set up stdout to work around bugs
77  */
78 void
79 sysdep_init(void)
80 {
81     int err;
82     WSADATA WsaData;
83     /*
84      * stdout is unbuffered under Windows if connected to a character
85      * device, and putchar() screws up when printing multibyte strings
86      * bytewise to an unbuffered stream.  Switch stdout to line-
87      * buffered mode.  Unfortunately, ISO C allows implementations to
88      * screw that up, and of course Windows does.  Manual flushing
89      * after each prompt is required.
90      */
91     setvbuf(stdout, NULL, _IOLBF, 4096);
92     err = WSAStartup(MAKEWORD(2, 0), &WsaData);
93     if (err != 0) {
94         printf("WSAStartup Failed, error code %d\n", err);
95         exit(1);
96     }
97 }
98
99 /*
100  * POSIX compatible socket() replacement
101  */
102 #undef socket
103 int
104 w32_socket(int family, int sock_type, int protocol)
105 {
106     int result;
107     
108     result = socket(family, sock_type, protocol);
109     if (result == INVALID_SOCKET) {
110         errno = WSAGetLastError();
111         return -1;
112     }
113     return result;
114 }
115
116 /*
117  * POSIX compatible connect() replacement
118  */
119 #undef connect
120 int
121 w32_connect(int sock, struct sockaddr *addr, int addrlen)
122 {
123     int result;
124     
125     result = connect(sock,  addr, addrlen);
126     if (result == SOCKET_ERROR) {
127         errno = WSAGetLastError();
128         return -1;
129     }
130     return result;
131 }
132
133 /*
134  * POSIX compatible recv() replacement
135  */
136 #undef recv
137 int
138 w32_recv(int socket, char *buffer, size_t buf_size, int flags)
139 {
140     int result;
141
142     result = recv(socket, buffer, buf_size, flags);
143     if (result == SOCKET_ERROR) {
144         errno = WSAGetLastError();
145         return -1;
146     }
147     return result;
148 }
149
150 /*
151  * POSIX compatible writev() replacement specialized to sockets
152  * Modelled after the GNU's libc/sysdeps/posix/writev.c
153  */
154 ssize_t
155 w32_writev_socket(int fd, const struct iovec *iov, int iovcnt)
156 {
157     int i;
158     unsigned char *buffer, *buffer_location;
159     size_t total_bytes = 0;
160     int bytes_written;
161
162     for (i = 0; i < iovcnt; i++)
163         total_bytes += iov[i].iov_len;
164
165     buffer = malloc(total_bytes);
166     if (buffer == NULL && total_bytes != 0) {
167         errno = ENOMEM;
168         return -1;
169     }
170
171     buffer_location = buffer;
172     for (i = 0; i < iovcnt; i++) {
173         memcpy(buffer_location, iov[i].iov_base, iov[i].iov_len);
174         buffer_location += iov[i].iov_len;
175     }
176
177     bytes_written = send(fd, buffer, total_bytes, 0);
178
179     free(buffer);
180
181     if (bytes_written == SOCKET_ERROR) {
182         errno = WSAGetLastError();
183         return -1;
184     }
185     return bytes_written;
186 }
187
188 /*
189  * POSIX compatible send() replacement
190  */
191 int
192 w32_send(int socket, char *buffer, size_t buf_size, int flags)
193 {
194         int result;
195
196         result = send(socket, buffer, buf_size, flags);
197         if (result == SOCKET_ERROR)
198                 errno = WSAGetLastError();
199         return result;
200 }
201
202 /*
203  * POSIX compatible close() replacement specialized to sockets.
204  */
205 int
206 w32_close_socket(int fd)
207 {
208     int result;
209     
210     result = closesocket(fd);
211     if (result == SOCKET_ERROR)
212         errno = WSAGetLastError();
213     return result;
214 }
215
216 /*
217  * WIN32 equivalent for getpass
218  */
219 char *
220 getpass(char *prompt)
221 {
222     static char tmp[128];
223     int len;
224     char *cpass;
225     DWORD mode;
226     HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE);
227
228     if (GetConsoleMode(input_handle, &mode))
229         SetConsoleMode(input_handle, mode & ~ENABLE_ECHO_INPUT);
230     else
231         printf("Note: This is echoed to the screen\n");
232     printf("%s", prompt);
233     fflush(stdout);
234     cpass = fgets(tmp, sizeof(tmp), stdin);
235     if (GetConsoleMode(input_handle, &mode))
236         SetConsoleMode(input_handle, mode | ENABLE_ECHO_INPUT);
237     if (cpass == NULL)
238         return NULL;
239     len = strlen(cpass);
240     if (tmp[len - 1] == '\n')
241         tmp[len - 1] = 0;
242     return cpass;
243 }
244
245 /*
246  * POSIX compatible open() replacement
247  */
248 int
249 w32_openfd(const char *fname, int oflag, ...)
250 {
251     va_list ap;
252     int pmode = 0;
253     int fd;
254     int create_permission = 0;
255
256     if (oflag & O_CREAT) {
257         va_start(ap, oflag);
258         pmode = va_arg(ap, int);
259         va_end(ap);
260
261         if (pmode & 0400)
262             create_permission |= _S_IREAD;
263         if (pmode & 0200)
264             create_permission |= _S_IWRITE;
265     }
266
267     fd = _open(fname, oflag, create_permission);
268     return fd;
269 }
270 /*
271  * Open a file for reading, return its handle.
272  * This can be used in place of open() when a handle is desired for
273  * waiting on it with WaitForMultipleObjects() or similar.
274  * Ensure the handle is not zero in order to prevent a problem
275  * input_fd.
276  */
277 int
278 w32_openhandle(const char *fname, int oflag)
279 {
280     HANDLE handle;
281
282     handle = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
283         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
284
285     if (handle == INVALID_HANDLE_VALUE) {
286         errno = GetLastError();
287         return -1;
288     }
289     if (handle == 0) {
290         HANDLE dup_handle;
291         if (!DuplicateHandle(GetCurrentProcess(), handle,
292                         GetCurrentProcess(), &dup_handle,
293                         0, FALSE, DUPLICATE_SAME_ACCESS)) {
294             errno = GetLastError();
295             return -1;
296         } else {
297             CloseHandle(handle);
298             handle = dup_handle;
299         }
300     }
301     return (int)handle;
302 }
303
304 /*
305  * POSIX compatible readv() replacement specialized to files.
306  * Modelled after the GNU's libc/sysdeps/posix/readv.c
307  */
308 ssize_t
309 w32_readv_handle(int fd, const struct iovec *iov, int iovcnt)
310 {
311     int i;
312     unsigned char *buffer, *buffer_location;
313     size_t total_bytes = 0;
314     DWORD bytes_read;
315     size_t bytes_left;
316
317     for (i = 0; i < iovcnt; i++) {
318         total_bytes += iov[i].iov_len;
319     }
320
321     buffer = malloc(total_bytes);
322     if (buffer == NULL && total_bytes != 0) {
323         errno = ENOMEM;
324         return -1;
325     }
326
327     if (!ReadFile((HANDLE)fd, buffer, total_bytes, &bytes_read, NULL)) {
328         free(buffer);
329         errno = GetLastError();
330         return -1;
331     }
332
333     bytes_left = bytes_read;
334     buffer_location = buffer;
335     for (i = 0; i < iovcnt; i++) {
336         size_t copy = MIN(iov[i].iov_len, bytes_left);
337
338         memcpy(iov[i].iov_base, buffer_location, copy);
339
340         buffer_location += copy;
341         bytes_left -= copy;
342         if (bytes_left == 0)
343             break;
344     }
345
346     free(buffer);
347
348     return bytes_read;
349 }
350
351 /*
352  * POSIX compatible close() replacement specialized to files.
353  * Hack: expects a handle, cannot be used with a file descriptor.
354  */
355 int
356 w32_close_handle(int fd)
357 {
358     int result;
359
360     result = CloseHandle((HANDLE)fd);
361
362     if (!result)
363         errno = GetLastError();
364     return result;
365 }
366 #endif /* _WIN32 */