/* * IXNetSystem.cpp * Author: Korchynskyi Dmytro * Copyright (c) 2019 Machine Zone. All rights reserved. */ #include "IXNetSystem.h" namespace ix { bool initNetSystem() { #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; int err; // Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); return err == 0; #else return true; #endif } bool uninitNetSystem() { #ifdef _WIN32 int err = WSACleanup(); return err == 0; #else return true; #endif } // // That function could 'return WSAPoll(pfd, nfds, timeout);' // but WSAPoll is said to have weird behaviors on the internet // (the curl folks have had problems with it). // // So we make it a select wrapper // int poll(struct pollfd* fds, nfds_t nfds, int timeout) { #ifdef _WIN32 socket_t maxfd = 0; fd_set readfds, writefds, errorfds; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); for (nfds_t i = 0; i < nfds; ++i) { struct pollfd* fd = &fds[i]; if (fd->fd > maxfd) { maxfd = fd->fd; } if ((fd->events & POLLIN)) { FD_SET(fd->fd, &readfds); } if ((fd->events & POLLOUT)) { FD_SET(fd->fd, &writefds); } if ((fd->events & POLLERR)) { FD_SET(fd->fd, &errorfds); } } struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ret = select(maxfd + 1, &readfds, &writefds, &errorfds, timeout != -1 ? &tv : NULL); if (ret < 0) { return ret; } for (nfds_t i = 0; i < nfds; ++i) { struct pollfd* fd = &fds[i]; fd->revents = 0; if (FD_ISSET(fd->fd, &readfds)) { fd->revents |= POLLIN; } if (FD_ISSET(fd->fd, &writefds)) { fd->revents |= POLLOUT; } if (FD_ISSET(fd->fd, &errorfds)) { fd->revents |= POLLERR; } } return ret; #else // // It was reported that on Android poll can fail and return -1 with // errno == EINTR, which should be a temp error and should typically // be handled by retrying in a loop. // Maybe we need to put all syscall / C functions in // a new IXSysCalls.cpp and wrap them all. // // The style from libuv is as such. // int ret = -1; do { ret = ::poll(fds, nfds, timeout); } while (ret == -1 && errno == EINTR); return ret; #endif } } // namespace ix // // mingw does not have inet_ntop and inet_pton, which were taken as is from the musl C library. // #if defined(_WIN32) && defined(__GNUC__) const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) { const unsigned char *a = a0; int i, j, max, best; char buf[100]; switch (af) { case AF_INET: if (snprintf(s, l, "%d.%d.%d.%d", a[0],a[1],a[2],a[3]) < l) return s; break; case AF_INET6: if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12)) snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%x:%x", 256*a[0]+a[1],256*a[2]+a[3], 256*a[4]+a[5],256*a[6]+a[7], 256*a[8]+a[9],256*a[10]+a[11], 256*a[12]+a[13],256*a[14]+a[15]); else snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", 256*a[0]+a[1],256*a[2]+a[3], 256*a[4]+a[5],256*a[6]+a[7], 256*a[8]+a[9],256*a[10]+a[11], a[12],a[13],a[14],a[15]); /* Replace longest /(^0|:)[:0]{2,}/ with "::" */ for (i=best=0, max=2; buf[i]; i++) { if (i && buf[i] != ':') continue; j = strspn(buf+i, ":0"); if (j>max) best=i, max=j; } if (max>3) { buf[best] = buf[best+1] = ':'; memmove(buf+best+2, buf+best+max, i-best-max+1); } if (strlen(buf) < l) { strcpy(s, buf); return s; } break; default: errno = EAFNOSUPPORT; return 0; } errno = ENOSPC; return 0; } static int hexval(unsigned c) { if (c-'0'<10) return c-'0'; c |= 32; if (c-'a'<6) return c-'a'+10; return -1; } int inet_pton(int af, const char* src, void* dst) { uint16_t ip[8]; unsigned char *a = a0; int i, j, v, d, brk=-1, need_v4=0; if (af==AF_INET) { for (i=0; i<4; i++) { for (v=j=0; j<3 && isdigit(s[j]); j++) v = 10*v + s[j]-'0'; if (j==0 || (j>1 && s[0]=='0') || v>255) return 0; a[i] = v; if (s[j]==0 && i==3) return 1; if (s[j]!='.') return 0; s += j+1; } return 0; } else if (af!=AF_INET6) { errno = EAFNOSUPPORT; return -1; } if (*s==':' && *++s!=':') return 0; for (i=0; ; i++) { if (s[0]==':' && brk<0) { brk=i; ip[i&7]=0; if (!*++s) break; if (i==7) return 0; continue; } for (v=j=0; j<4 && (d=hexval(s[j]))>=0; j++) v=16*v+d; if (j==0) return 0; ip[i&7] = v; if (!s[j] && (brk>=0 || i==7)) break; if (i==7) return 0; if (s[j]!=':') { if (s[j]!='.' || (i<6 && brk<0)) return 0; need_v4=1; i++; break; } s += j+1; } if (brk>=0) { memmove(ip+brk+7-i, ip+brk, 2*(i+1-brk)); for (j=0; j<7-i; j++) ip[brk+j] = 0; } for (j=0; j<8; j++) { *a++ = ip[j]>>8; *a++ = ip[j]; } if (need_v4 && inet_pton(AF_INET, (void *)s, a-4) <= 0) return 0; return 1; } #endif // defined(_WIN32) && defined(__GNUC__)