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