File indexing completed on 2025-01-05 04:37:31
0001 /* 0002 SPDX-FileCopyrightText: 2006 Dan Kennedy. 0003 SPDX-FileCopyrightText: 2006 Juliusz Chroboczek. 0004 0005 SPDX-License-Identifier: MIT 0006 */ 0007 0008 #include "win32.h" 0009 #include <assert.h> 0010 #include <errno.h> 0011 #include <malloc.h> 0012 // #undef poll 0013 // #undef socket 0014 // #undef connect 0015 // #undef accept 0016 // #undef shutdown 0017 // #undef getpeername 0018 // #undef sleep 0019 // #undef inet_aton 0020 // #undef gettimeofday 0021 // #undef stat 0022 /* Windows needs this header file for the implementation of inet_aton() */ 0023 #include <ctype.h> 0024 /* 0025 * Check whether "cp" is a valid ascii representation of an Internet address 0026 * and convert to a binary address. Returns 1 if the address is valid, 0 if 0027 * not. This replaces inet_addr, the return value from which cannot 0028 * distinguish between failure and a local broadcast address. 0029 * 0030 * This implementation of the standard inet_aton() function was copied 0031 * (with trivial modifications) from the OpenBSD project. 0032 */ 0033 #if 0 0034 int 0035 mingw_inet_aton(const char *cp, struct in_addr *addr) 0036 { 0037 register unsigned int val; 0038 register int base, n; 0039 register char c; 0040 unsigned int parts[4]; 0041 register unsigned int *pp = parts; 0042 0043 assert(sizeof(val) == 4); 0044 0045 c = *cp; 0046 while (1) { 0047 /* 0048 * Collect number up to ``.''. 0049 * Values are specified as for C: 0050 * 0x=hex, 0=octal, isdigit=decimal. 0051 */ 0052 if (!isdigit(c)) 0053 return (0); 0054 val = 0; base = 10; 0055 if (c == '0') { 0056 c = *++cp; 0057 if (c == 'x' || c == 'X') 0058 base = 16, c = *++cp; 0059 else 0060 base = 8; 0061 } 0062 while (1) { 0063 if (isascii(c) && isdigit(c)) { 0064 val = (val * base) + (c - '0'); 0065 c = *++cp; 0066 } else if (base == 16 && isascii(c) && isxdigit(c)) { 0067 val = (val << 4) | 0068 (c + 10 - (islower(c) ? 'a' : 'A')); 0069 c = *++cp; 0070 } else 0071 break; 0072 } 0073 if (c == '.') { 0074 /* 0075 * Internet format: 0076 * a.b.c.d 0077 * a.b.c (with c treated as 16 bits) 0078 * a.b (with b treated as 24 bits) 0079 */ 0080 if (pp >= parts + 3) 0081 return (0); 0082 *pp++ = val; 0083 c = *++cp; 0084 } else 0085 break; 0086 } 0087 /* 0088 * Check for trailing characters. 0089 */ 0090 if (c != '\0' && (!isascii(c) || !isspace(c))) 0091 return (0); 0092 /* 0093 * Concoct the address according to 0094 * the number of parts specified. 0095 */ 0096 n = pp - parts + 1; 0097 switch (n) { 0098 0099 case 0: 0100 return (0); /* initial nondigit */ 0101 0102 case 1: /* a -- 32 bits */ 0103 break; 0104 0105 case 2: /* a.b -- 8.24 bits */ 0106 if ((val > 0xffffff) || (parts[0] > 0xff)) 0107 return (0); 0108 val |= parts[0] << 24; 0109 break; 0110 0111 case 3: /* a.b.c -- 8.8.16 bits */ 0112 if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) 0113 return (0); 0114 val |= (parts[0] << 24) | (parts[1] << 16); 0115 break; 0116 0117 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 0118 if ((val > 0xff) || (parts[0] > 0xff) || 0119 (parts[1] > 0xff) || (parts[2] > 0xff)) 0120 return (0); 0121 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 0122 break; 0123 } 0124 if (addr) 0125 addr->s_addr = htonl(val); 0126 return (1); 0127 } 0128 0129 unsigned int 0130 mingw_sleep(unsigned int seconds) 0131 { 0132 Sleep(seconds * 1000); 0133 return 0; 0134 } 0135 0136 int 0137 mingw_gettimeofday(struct timeval *tv, char *tz) 0138 { 0139 const long long EPOCHFILETIME = (116444736000000000LL); 0140 FILETIME ft; 0141 LARGE_INTEGER li; 0142 long long t; 0143 0144 /* This implementation doesn't support the timezone parameter. That's Ok, 0145 * as at present polipo always passed NULL as the second arg. We 0146 * also need to make sure that we have at least 8 bytes of space to 0147 * do the math in - otherwise there will be overflow errors. 0148 */ 0149 assert(tz == NULL); 0150 assert(sizeof(t) == 8); 0151 0152 if (tv) { 0153 GetSystemTimeAsFileTime(&ft); 0154 li.LowPart = ft.dwLowDateTime; 0155 li.HighPart = ft.dwHighDateTime; 0156 t = li.QuadPart; /* In 100-nanosecond intervals */ 0157 t -= EPOCHFILETIME; /* Offset to the Epoch time */ 0158 t /= 10; /* In microseconds */ 0159 tv->tv_sec = (long)(t / 1000000); 0160 tv->tv_usec = (long)(t % 1000000); 0161 } 0162 return 0; 0163 } 0164 #endif 0165 0166 int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo) 0167 { 0168 struct timeval timeout, *toptr; 0169 fd_set ifds, ofds, efds, *ip, *op; 0170 int i, rc; 0171 0172 /* Set up the file-descriptor sets in ifds, ofds and efds. */ 0173 FD_ZERO(&ifds); 0174 FD_ZERO(&ofds); 0175 FD_ZERO(&efds); 0176 for (i = 0, op = ip = 0; i < nfds; ++i) { 0177 fds[i].revents = 0; 0178 if (fds[i].events & (POLLIN | POLLPRI)) { 0179 ip = &ifds; 0180 FD_SET(fds[i].fd, ip); 0181 } 0182 if (fds[i].events & POLLOUT) { 0183 op = &ofds; 0184 FD_SET(fds[i].fd, op); 0185 } 0186 FD_SET(fds[i].fd, &efds); 0187 } 0188 0189 /* Set up the timeval structure for the timeout parameter */ 0190 if (timo < 0) { 0191 toptr = 0; 0192 } else { 0193 toptr = &timeout; 0194 timeout.tv_sec = timo / 1000; 0195 timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000; 0196 } 0197 0198 // 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); 0199 0200 rc = select(0, ip, op, &efds, toptr); 0201 0202 // kWarning()<<"Exiting select rc="<<rc; 0203 0204 if (rc <= 0) 0205 return rc; 0206 0207 if (rc > 0) { 0208 for (i = 0; i < nfds; ++i) { 0209 int fd = fds[i].fd; 0210 if (fds[i].events & (POLLIN | POLLPRI) && FD_ISSET(fd, &ifds)) 0211 fds[i].revents |= POLLIN; 0212 if (fds[i].events & POLLOUT && FD_ISSET(fd, &ofds)) 0213 fds[i].revents |= POLLOUT; 0214 if (FD_ISSET(fd, &efds)) 0215 /* Some error was detected ... should be some way to know. */ 0216 fds[i].revents |= POLLHUP; 0217 // 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); 0218 } 0219 } 0220 return rc; 0221 } 0222 #if 0 0223 int mingw_close_socket(SOCKET fd) 0224 { 0225 int rc; 0226 0227 rc = closesocket(fd); 0228 assert(rc == 0); 0229 return 0; 0230 } 0231 0232 static void 0233 set_errno(int winsock_err) 0234 { 0235 switch (winsock_err) { 0236 case WSAEWOULDBLOCK: 0237 errno = EAGAIN; 0238 break; 0239 default: 0240 errno = winsock_err; 0241 break; 0242 } 0243 } 0244 0245 int mingw_write_socket(SOCKET fd, void *buf, int n) 0246 { 0247 int rc = send(fd, buf, n, 0); 0248 if (rc == SOCKET_ERROR) { 0249 set_errno(WSAGetLastError()); 0250 } 0251 return rc; 0252 } 0253 0254 int mingw_read_socket(SOCKET fd, void *buf, int n) 0255 { 0256 int rc = recv(fd, buf, n, 0); 0257 if (rc == SOCKET_ERROR) { 0258 set_errno(WSAGetLastError()); 0259 } 0260 return rc; 0261 } 0262 0263 0264 /* 0265 * Set the "non-blocking" flag on socket fd to the value specified by 0266 * the second argument (i.e. if the nonblocking argument is non-zero, the 0267 * socket is set to non-blocking mode). Zero is returned if the operation 0268 * is successful, other -1. 0269 */ 0270 int 0271 mingw_setnonblocking(SOCKET fd, int nonblocking) 0272 { 0273 int rc; 0274 0275 unsigned long mode = 1; 0276 rc = ioctlsocket(fd, FIONBIO, &mode); 0277 if (rc != 0) { 0278 set_errno(WSAGetLastError()); 0279 } 0280 return (rc == 0 ? 0 : -1); 0281 } 0282 0283 /* 0284 * A wrapper around the socket() function. The purpose of this wrapper 0285 * is to ensure that the global errno symbol is set if an error occurs, 0286 * even if we are using winsock. 0287 */ 0288 SOCKET 0289 mingw_socket(int domain, int type, int protocol) 0290 { 0291 SOCKET fd = socket(domain, type, protocol); 0292 if (fd == INVALID_SOCKET) { 0293 set_errno(WSAGetLastError()); 0294 } 0295 return fd; 0296 } 0297 0298 static void 0299 set_connect_errno(int winsock_err) 0300 { 0301 switch (winsock_err) { 0302 case WSAEINVAL: 0303 case WSAEALREADY: 0304 case WSAEWOULDBLOCK: 0305 errno = EINPROGRESS; 0306 break; 0307 default: 0308 errno = winsock_err; 0309 break; 0310 } 0311 } 0312 0313 /* 0314 * A wrapper around the connect() function. The purpose of this wrapper 0315 * is to ensure that the global errno symbol is set if an error occurs, 0316 * even if we are using winsock. 0317 */ 0318 int 0319 mingw_connect(SOCKET fd, struct sockaddr *addr, socklen_t addr_len) 0320 { 0321 int rc = connect(fd, addr, addr_len); 0322 assert(rc == 0 || rc == SOCKET_ERROR); 0323 if (rc == SOCKET_ERROR) { 0324 set_connect_errno(WSAGetLastError()); 0325 } 0326 return rc; 0327 } 0328 0329 /* 0330 * A wrapper around the accept() function. The purpose of this wrapper 0331 * is to ensure that the global errno symbol is set if an error occurs, 0332 * even if we are using winsock. 0333 */ 0334 SOCKET 0335 mingw_accept(SOCKET fd, struct sockaddr *addr, socklen_t *addr_len) 0336 { 0337 SOCKET newfd = accept(fd, addr, addr_len); 0338 if (newfd == INVALID_SOCKET) { 0339 set_errno(WSAGetLastError()); 0340 newfd = -1; 0341 } 0342 return newfd; 0343 } 0344 0345 /* 0346 * A wrapper around the shutdown() function. The purpose of this wrapper 0347 * is to ensure that the global errno symbol is set if an error occurs, 0348 * even if we are using winsock. 0349 */ 0350 int 0351 mingw_shutdown(SOCKET fd, int mode) 0352 { 0353 int rc = shutdown(fd, mode); 0354 assert(rc == 0 || rc == SOCKET_ERROR); 0355 if (rc == SOCKET_ERROR) { 0356 set_errno(WSAGetLastError()); 0357 } 0358 return rc; 0359 } 0360 0361 /* 0362 * A wrapper around the getpeername() function. The purpose of this wrapper 0363 * is to ensure that the global errno symbol is set if an error occurs, 0364 * even if we are using winsock. 0365 */ 0366 int 0367 mingw_getpeername(SOCKET fd, struct sockaddr *name, socklen_t *namelen) 0368 { 0369 int rc = getpeername(fd, name, namelen); 0370 assert(rc == 0 || rc == SOCKET_ERROR); 0371 if (rc == SOCKET_ERROR) { 0372 set_errno(WSAGetLastError()); 0373 } 0374 return rc; 0375 } 0376 0377 /* Stat doesn't work on directories if the name ends in a slash. */ 0378 0379 int 0380 mingw_stat(const char *filename, struct stat *ss) 0381 { 0382 int len, rc, saved_errno; 0383 char *noslash; 0384 0385 len = strlen(filename); 0386 if (len <= 1 || filename[len - 1] != '/') 0387 return stat(filename, ss); 0388 0389 noslash = malloc(len); 0390 if (noslash == NULL) 0391 return -1; 0392 0393 memcpy(noslash, filename, len - 1); 0394 noslash[len - 1] = '\0'; 0395 0396 rc = stat(noslash, ss); 0397 saved_errno = errno; 0398 free(noslash); 0399 errno = saved_errno; 0400 return rc; 0401 } 0402 #endif 0403 char *mingw_strerror(int error) 0404 { 0405 #ifdef UNICODE 0406 wchar_t message[1024]; 0407 #else 0408 char message[1024]; 0409 #endif 0410 static char cmessage[1024]; 0411 0412 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0413 NULL, 0414 error, 0415 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 0416 message, 0417 sizeof(message), 0418 NULL); 0419 #ifdef UNICODE 0420 wcstombs(cmessage, message, 1024); 0421 #endif 0422 char *p; 0423 for (p = cmessage; *p; p++) { 0424 if (*p == '\n' || *p == '\r') 0425 *p = ' '; 0426 } 0427 0428 return cmessage; 0429 } 0430 0431 #if 0 0432 static int init(struct pollfd *pollfds, nfds_t nfds, SOCKET *fds, HANDLE *hEvents) 0433 { 0434 nfds_t i; 0435 0436 for (i = 0; i < nfds; i++) { 0437 fds[i] = INVALID_SOCKET; 0438 hEvents[i] = NULL; 0439 } 0440 0441 for (i = 0; i < nfds; i++) { 0442 fds[i] = pollfds[i].fd; 0443 hEvents[i] = WSACreateEvent(); 0444 pollfds[i].revents = 0; 0445 0446 if (WSAEventSelect(fds[i], hEvents[i], pollfds[i].events) < 0) { 0447 errno = WSAGetLastError(); 0448 return -1; 0449 } 0450 } 0451 0452 return 0; 0453 } 0454 0455 static void clean(nfds_t nfds, SOCKET *fds, HANDLE *hEvents) 0456 { 0457 nfds_t i; 0458 0459 for (i = 0; i < nfds; i++) { 0460 if (fds[i] != INVALID_SOCKET) { 0461 WSAEventSelect(fds[i], NULL, 0); 0462 } 0463 0464 if (hEvents[i] != NULL) { 0465 WSACloseEvent(hEvents[i]); 0466 } 0467 } 0468 } 0469 0470 int poll(struct pollfd *pollfds, nfds_t nfds, int timeout) 0471 { 0472 SOCKET *fds; 0473 HANDLE *hEvents; 0474 DWORD n; 0475 0476 fds = (SOCKET *)alloca(sizeof(SOCKET) * nfds); 0477 hEvents = (HANDLE *)alloca(sizeof(HANDLE) * nfds); 0478 if (init(pollfds, nfds, fds, hEvents) < 0) { 0479 clean(nfds, fds, hEvents); 0480 return -1; 0481 } 0482 0483 n = WSAWaitForMultipleEvents(nfds, hEvents, FALSE, timeout, FALSE); 0484 if (n == WSA_WAIT_FAILED) { 0485 clean(nfds, fds, hEvents); 0486 return -1; 0487 } else if (n == WSA_WAIT_TIMEOUT) { 0488 clean(nfds, fds, hEvents); 0489 return 0; 0490 } else { 0491 SOCKET fd; 0492 HANDLE hEvent; 0493 WSANETWORKEVENTS events; 0494 0495 n -= WSA_WAIT_EVENT_0; 0496 fd = fds[n]; 0497 hEvent = hEvents[n]; 0498 0499 if (WSAEnumNetworkEvents(fd, hEvent, &events) < 0) { 0500 clean(nfds, fds, hEvents); 0501 return -1; 0502 } 0503 0504 pollfds[n].revents = (short) events.lNetworkEvents; 0505 clean(nfds, fds, hEvents); 0506 return n + 1; 0507 } 0508 } 0509 #endif