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