1 /*
2 SPDX-FileCopyrightText: 2006 Dan Kennedy.
3 SPDX-FileCopyrightText: 2006 Juliusz Chroboczek.
4
5 SPDX-License-Identifier: MIT
6 */
7
8 #include "win32.h"
9 #include <assert.h>
10 #include <errno.h>
11 #include <malloc.h>
12 // #undef poll
13 // #undef socket
14 // #undef connect
15 // #undef accept
16 // #undef shutdown
17 // #undef getpeername
18 // #undef sleep
19 // #undef inet_aton
20 // #undef gettimeofday
21 // #undef stat
22 /* Windows needs this header file for the implementation of inet_aton() */
23 #include <ctype.h>
24 /*
25 * Check whether "cp" is a valid ascii representation of an Internet address
26 * and convert to a binary address. Returns 1 if the address is valid, 0 if
27 * not. This replaces inet_addr, the return value from which cannot
28 * distinguish between failure and a local broadcast address.
29 *
30 * This implementation of the standard inet_aton() function was copied
31 * (with trivial modifications) from the OpenBSD project.
32 */
33 #if 0
34 int
35 mingw_inet_aton(const char *cp, struct in_addr *addr)
36 {
37 register unsigned int val;
38 register int base, n;
39 register char c;
40 unsigned int parts[4];
41 register unsigned int *pp = parts;
42
43 assert(sizeof(val) == 4);
44
45 c = *cp;
46 while (1) {
47 /*
48 * Collect number up to ``.''.
49 * Values are specified as for C:
50 * 0x=hex, 0=octal, isdigit=decimal.
51 */
52 if (!isdigit(c))
53 return (0);
54 val = 0; base = 10;
55 if (c == '0') {
56 c = *++cp;
57 if (c == 'x' || c == 'X')
58 base = 16, c = *++cp;
59 else
60 base = 8;
61 }
62 while (1) {
63 if (isascii(c) && isdigit(c)) {
64 val = (val * base) + (c - '0');
65 c = *++cp;
66 } else if (base == 16 && isascii(c) && isxdigit(c)) {
67 val = (val << 4) |
68 (c + 10 - (islower(c) ? 'a' : 'A'));
69 c = *++cp;
70 } else
71 break;
72 }
73 if (c == '.') {
74 /*
75 * Internet format:
76 * a.b.c.d
77 * a.b.c (with c treated as 16 bits)
78 * a.b (with b treated as 24 bits)
79 */
80 if (pp >= parts + 3)
81 return (0);
82 *pp++ = val;
83 c = *++cp;
84 } else
85 break;
86 }
87 /*
88 * Check for trailing characters.
89 */
90 if (c != '\0' && (!isascii(c) || !isspace(c)))
91 return (0);
92 /*
93 * Concoct the address according to
94 * the number of parts specified.
95 */
96 n = pp - parts + 1;
97 switch (n) {
98
99 case 0:
100 return (0); /* initial nondigit */
101
102 case 1: /* a -- 32 bits */
103 break;
104
105 case 2: /* a.b -- 8.24 bits */
106 if ((val > 0xffffff) || (parts[0] > 0xff))
107 return (0);
108 val |= parts[0] << 24;
109 break;
110
111 case 3: /* a.b.c -- 8.8.16 bits */
112 if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
113 return (0);
114 val |= (parts[0] << 24) | (parts[1] << 16);
115 break;
116
117 case 4: /* a.b.c.d -- 8.8.8.8 bits */
118 if ((val > 0xff) || (parts[0] > 0xff) ||
119 (parts[1] > 0xff) || (parts[2] > 0xff))
120 return (0);
121 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
122 break;
123 }
124 if (addr)
125 addr->s_addr = htonl(val);
126 return (1);
127 }
128
129 unsigned int
130 mingw_sleep(unsigned int seconds)
131 {
132 Sleep(seconds * 1000);
133 return 0;
134 }
135
136 int
137 mingw_gettimeofday(struct timeval *tv, char *tz)
138 {
139 const long long EPOCHFILETIME = (116444736000000000LL);
140 FILETIME ft;
141 LARGE_INTEGER li;
142 long long t;
143
144 /* This implementation doesn't support the timezone parameter. That's Ok,
145 * as at present polipo always passed NULL as the second arg. We
146 * also need to make sure that we have at least 8 bytes of space to
147 * do the math in - otherwise there will be overflow errors.
148 */
149 assert(tz == NULL);
150 assert(sizeof(t) == 8);
151
152 if (tv) {
153 GetSystemTimeAsFileTime(&ft);
154 li.LowPart = ft.dwLowDateTime;
155 li.HighPart = ft.dwHighDateTime;
156 t = li.QuadPart; /* In 100-nanosecond intervals */
157 t -= EPOCHFILETIME; /* Offset to the Epoch time */
158 t /= 10; /* In microseconds */
159 tv->tv_sec = (long)(t / 1000000);
160 tv->tv_usec = (long)(t % 1000000);
161 }
162 return 0;
163 }
164 #endif
165
mingw_poll(struct pollfd * fds,unsigned int nfds,int timo)166 int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo)
167 {
168 struct timeval timeout, *toptr;
169 fd_set ifds, ofds, efds, *ip, *op;
170 int i, rc;
171
172 /* Set up the file-descriptor sets in ifds, ofds and efds. */
173 FD_ZERO(&ifds);
174 FD_ZERO(&ofds);
175 FD_ZERO(&efds);
176 for (i = 0, op = ip = 0; i < nfds; ++i) {
177 fds[i].revents = 0;
178 if (fds[i].events & (POLLIN | POLLPRI)) {
179 ip = &ifds;
180 FD_SET(fds[i].fd, ip);
181 }
182 if (fds[i].events & POLLOUT) {
183 op = &ofds;
184 FD_SET(fds[i].fd, op);
185 }
186 FD_SET(fds[i].fd, &efds);
187 }
188
189 /* Set up the timeval structure for the timeout parameter */
190 if (timo < 0) {
191 toptr = 0;
192 } else {
193 toptr = &timeout;
194 timeout.tv_sec = timo / 1000;
195 timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000;
196 }
197
198 // kWarning()<<QString("Entering select() sec=%1 usec=%2 ip=%3 op=%4").arg(timeout.tv_sec).arg(timeout.tv_usec).arg((long)ip).arg((long)op);
199
200 rc = select(0, ip, op, &efds, toptr);
201
202 // kWarning()<<"Exiting select rc="<<rc;
203
204 if (rc <= 0)
205 return rc;
206
207 if (rc > 0) {
208 for (i = 0; i < nfds; ++i) {
209 int fd = fds[i].fd;
210 if (fds[i].events & (POLLIN | POLLPRI) && FD_ISSET(fd, &ifds))
211 fds[i].revents |= POLLIN;
212 if (fds[i].events & POLLOUT && FD_ISSET(fd, &ofds))
213 fds[i].revents |= POLLOUT;
214 if (FD_ISSET(fd, &efds))
215 /* Some error was detected ... should be some way to know. */
216 fds[i].revents |= POLLHUP;
217 // kWarning()<<QString("%1 %2 %3 revent = %4").arg(FD_ISSET(fd, &ifds)).arg(FD_ISSET(fd, &ofds)).arg(FD_ISSET(fd, &efds)).arg(fds[i].revents);
218 }
219 }
220 return rc;
221 }
222 #if 0
223 int mingw_close_socket(SOCKET fd)
224 {
225 int rc;
226
227 rc = closesocket(fd);
228 assert(rc == 0);
229 return 0;
230 }
231
232 static void
233 set_errno(int winsock_err)
234 {
235 switch (winsock_err) {
236 case WSAEWOULDBLOCK:
237 errno = EAGAIN;
238 break;
239 default:
240 errno = winsock_err;
241 break;
242 }
243 }
244
245 int mingw_write_socket(SOCKET fd, void *buf, int n)
246 {
247 int rc = send(fd, buf, n, 0);
248 if (rc == SOCKET_ERROR) {
249 set_errno(WSAGetLastError());
250 }
251 return rc;
252 }
253
254 int mingw_read_socket(SOCKET fd, void *buf, int n)
255 {
256 int rc = recv(fd, buf, n, 0);
257 if (rc == SOCKET_ERROR) {
258 set_errno(WSAGetLastError());
259 }
260 return rc;
261 }
262
263
264 /*
265 * Set the "non-blocking" flag on socket fd to the value specified by
266 * the second argument (i.e. if the nonblocking argument is non-zero, the
267 * socket is set to non-blocking mode). Zero is returned if the operation
268 * is successful, other -1.
269 */
270 int
271 mingw_setnonblocking(SOCKET fd, int nonblocking)
272 {
273 int rc;
274
275 unsigned long mode = 1;
276 rc = ioctlsocket(fd, FIONBIO, &mode);
277 if (rc != 0) {
278 set_errno(WSAGetLastError());
279 }
280 return (rc == 0 ? 0 : -1);
281 }
282
283 /*
284 * A wrapper around the socket() function. The purpose of this wrapper
285 * is to ensure that the global errno symbol is set if an error occurs,
286 * even if we are using winsock.
287 */
288 SOCKET
289 mingw_socket(int domain, int type, int protocol)
290 {
291 SOCKET fd = socket(domain, type, protocol);
292 if (fd == INVALID_SOCKET) {
293 set_errno(WSAGetLastError());
294 }
295 return fd;
296 }
297
298 static void
299 set_connect_errno(int winsock_err)
300 {
301 switch (winsock_err) {
302 case WSAEINVAL:
303 case WSAEALREADY:
304 case WSAEWOULDBLOCK:
305 errno = EINPROGRESS;
306 break;
307 default:
308 errno = winsock_err;
309 break;
310 }
311 }
312
313 /*
314 * A wrapper around the connect() function. The purpose of this wrapper
315 * is to ensure that the global errno symbol is set if an error occurs,
316 * even if we are using winsock.
317 */
318 int
319 mingw_connect(SOCKET fd, struct sockaddr *addr, socklen_t addr_len)
320 {
321 int rc = connect(fd, addr, addr_len);
322 assert(rc == 0 || rc == SOCKET_ERROR);
323 if (rc == SOCKET_ERROR) {
324 set_connect_errno(WSAGetLastError());
325 }
326 return rc;
327 }
328
329 /*
330 * A wrapper around the accept() function. The purpose of this wrapper
331 * is to ensure that the global errno symbol is set if an error occurs,
332 * even if we are using winsock.
333 */
334 SOCKET
335 mingw_accept(SOCKET fd, struct sockaddr *addr, socklen_t *addr_len)
336 {
337 SOCKET newfd = accept(fd, addr, addr_len);
338 if (newfd == INVALID_SOCKET) {
339 set_errno(WSAGetLastError());
340 newfd = -1;
341 }
342 return newfd;
343 }
344
345 /*
346 * A wrapper around the shutdown() function. The purpose of this wrapper
347 * is to ensure that the global errno symbol is set if an error occurs,
348 * even if we are using winsock.
349 */
350 int
351 mingw_shutdown(SOCKET fd, int mode)
352 {
353 int rc = shutdown(fd, mode);
354 assert(rc == 0 || rc == SOCKET_ERROR);
355 if (rc == SOCKET_ERROR) {
356 set_errno(WSAGetLastError());
357 }
358 return rc;
359 }
360
361 /*
362 * A wrapper around the getpeername() function. The purpose of this wrapper
363 * is to ensure that the global errno symbol is set if an error occurs,
364 * even if we are using winsock.
365 */
366 int
367 mingw_getpeername(SOCKET fd, struct sockaddr *name, socklen_t *namelen)
368 {
369 int rc = getpeername(fd, name, namelen);
370 assert(rc == 0 || rc == SOCKET_ERROR);
371 if (rc == SOCKET_ERROR) {
372 set_errno(WSAGetLastError());
373 }
374 return rc;
375 }
376
377 /* Stat doesn't work on directories if the name ends in a slash. */
378
379 int
380 mingw_stat(const char *filename, struct stat *ss)
381 {
382 int len, rc, saved_errno;
383 char *noslash;
384
385 len = strlen(filename);
386 if (len <= 1 || filename[len - 1] != '/')
387 return stat(filename, ss);
388
389 noslash = malloc(len);
390 if (noslash == NULL)
391 return -1;
392
393 memcpy(noslash, filename, len - 1);
394 noslash[len - 1] = '\0';
395
396 rc = stat(noslash, ss);
397 saved_errno = errno;
398 free(noslash);
399 errno = saved_errno;
400 return rc;
401 }
402 #endif
mingw_strerror(int error)403 char *mingw_strerror(int error)
404 {
405 #ifdef UNICODE
406 wchar_t message[1024];
407 #else
408 char message[1024];
409 #endif
410 static char cmessage[1024];
411
412 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
413 NULL,
414 error,
415 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
416 message,
417 sizeof(message),
418 NULL);
419 #ifdef UNICODE
420 wcstombs(cmessage, message, 1024);
421 #endif
422 char *p;
423 for (p = cmessage; *p; p++) {
424 if (*p == '\n' || *p == '\r')
425 *p = ' ';
426 }
427
428 return cmessage;
429 }
430
431 #if 0
432 static int init(struct pollfd *pollfds, nfds_t nfds, SOCKET *fds, HANDLE *hEvents)
433 {
434 nfds_t i;
435
436 for (i = 0; i < nfds; i++) {
437 fds[i] = INVALID_SOCKET;
438 hEvents[i] = NULL;
439 }
440
441 for (i = 0; i < nfds; i++) {
442 fds[i] = pollfds[i].fd;
443 hEvents[i] = WSACreateEvent();
444 pollfds[i].revents = 0;
445
446 if (WSAEventSelect(fds[i], hEvents[i], pollfds[i].events) < 0) {
447 errno = WSAGetLastError();
448 return -1;
449 }
450 }
451
452 return 0;
453 }
454
455 static void clean(nfds_t nfds, SOCKET *fds, HANDLE *hEvents)
456 {
457 nfds_t i;
458
459 for (i = 0; i < nfds; i++) {
460 if (fds[i] != INVALID_SOCKET) {
461 WSAEventSelect(fds[i], NULL, 0);
462 }
463
464 if (hEvents[i] != NULL) {
465 WSACloseEvent(hEvents[i]);
466 }
467 }
468 }
469
470 int poll(struct pollfd *pollfds, nfds_t nfds, int timeout)
471 {
472 SOCKET *fds;
473 HANDLE *hEvents;
474 DWORD n;
475
476 fds = (SOCKET *)alloca(sizeof(SOCKET) * nfds);
477 hEvents = (HANDLE *)alloca(sizeof(HANDLE) * nfds);
478 if (init(pollfds, nfds, fds, hEvents) < 0) {
479 clean(nfds, fds, hEvents);
480 return -1;
481 }
482
483 n = WSAWaitForMultipleEvents(nfds, hEvents, FALSE, timeout, FALSE);
484 if (n == WSA_WAIT_FAILED) {
485 clean(nfds, fds, hEvents);
486 return -1;
487 } else if (n == WSA_WAIT_TIMEOUT) {
488 clean(nfds, fds, hEvents);
489 return 0;
490 } else {
491 SOCKET fd;
492 HANDLE hEvent;
493 WSANETWORKEVENTS events;
494
495 n -= WSA_WAIT_EVENT_0;
496 fd = fds[n];
497 hEvent = hEvents[n];
498
499 if (WSAEnumNetworkEvents(fd, hEvent, &events) < 0) {
500 clean(nfds, fds, hEvents);
501 return -1;
502 }
503
504 pollfds[n].revents = (short) events.lNetworkEvents;
505 clean(nfds, fds, hEvents);
506 return n + 1;
507 }
508 }
509 #endif
510