#pragma once // Shim for on non-Windows targets: the BSD socket API under its Winsock names, with the // Winsock semantics 40250 relies on where the two differ (see the notes on each function). #include "windows.h" #include #include #include #include #include #include #include #include #include #include typedef int SOCKET; typedef struct sockaddr SOCKADDR; typedef struct sockaddr* PSOCKADDR; typedef struct sockaddr_in SOCKADDR_IN; typedef struct in_addr IN_ADDR; typedef struct timeval TIMEVAL; typedef struct hostent HOSTENT; #define INVALID_SOCKET (-1) #define SOCKET_ERROR (-1) #define WSAEWOULDBLOCK EWOULDBLOCK typedef struct WSAData { WORD wVersion; WORD wHighVersion; } WSADATA; // There is no Winsock DLL to start. A send on a socket the peer has closed raises SIGPIPE on POSIX // where Winsock returns an error, so the process ignores it from here on. inline int WSAStartup(WORD version, WSADATA* data) { signal(SIGPIPE, SIG_IGN); if (data) data->wVersion = data->wHighVersion = version; return 0; } inline int WSACleanup() { return 0; } // A non-blocking connect() answers WSAEWOULDBLOCK on Winsock and EINPROGRESS on POSIX. inline int WSAGetLastError() { return errno == EINPROGRESS ? WSAEWOULDBLOCK : errno; } inline int closesocket(SOCKET s) { return close(s); } inline int ioctlsocket(SOCKET s, long cmd, DWORD* argp) { int value = static_cast(*argp); return ioctl(s, static_cast(cmd), &value); } // Winsock ignores nfds, and a socket whose connect failed is reported only in exceptfds; POSIX needs // nfds and marks such a socket writable. Callers pass 0 and treat "writable" as "connected" // (CNetworkStream::Process), so writable sockets without a peer are dropped from the write set. inline int mt_winsock_select(fd_set* readfds, fd_set* writefds, fd_set* exceptfds, TIMEVAL* timeout) { int ret = ::select(FD_SETSIZE, readfds, writefds, exceptfds, timeout); if (ret <= 0 || !writefds) return ret; for (int fd = 0; fd < FD_SETSIZE; ++fd) { if (!FD_ISSET(fd, writefds)) continue; sockaddr_in peer; socklen_t len = sizeof(peer); if (getpeername(fd, reinterpret_cast(&peer), &len) != 0) FD_CLR(fd, writefds); } return ret; } #define select(nfds, readfds, writefds, exceptfds, timeout) mt_winsock_select(readfds, writefds, exceptfds, timeout) inline int mt_winsock_recvfrom(SOCKET s, void* buf, size_t len, int flags, struct sockaddr* from, int* fromlen) { socklen_t slen = fromlen ? static_cast(*fromlen) : 0; ssize_t ret = ::recvfrom(s, buf, len, flags, from, fromlen ? &slen : nullptr); if (fromlen) *fromlen = static_cast(slen); return static_cast(ret); } inline int mt_winsock_recvfrom(SOCKET s, void* buf, size_t len, int flags, struct sockaddr* from, socklen_t* fromlen) { return static_cast(::recvfrom(s, buf, len, flags, from, fromlen)); } #define recvfrom mt_winsock_recvfrom