// net_compat.h #pragma once #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #define NOGDI #define NOUSER #include #include #pragma comment(lib, "ws2_32.lib") // Map POSIX names to Winsock equivalents #define close(s) closesocket(s) #define MSG_DONTWAIT 0 // no direct equivalent, use non-blocking mode instead static inline int net_errno(void) { return WSAGetLastError(); } #define NET_EAGAIN WSAEWOULDBLOCK #define NET_EINTR WSAEINTR typedef int socklen_t; // err.h doesn't exist on Windows — provide a minimal shim #include #include static inline void err(int code, const char *msg) { fprintf(stderr, "%s: WSA error %d\n", msg, WSAGetLastError()); exit(code); } // Winsock requires explicit init/cleanup static inline void net_init(void) { WSADATA wsa; if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) { fprintf(stderr, "WSAStartup failed\n"); exit(EXIT_FAILURE); } } static inline void net_cleanup(void) { WSACleanup(); } // Non-blocking: Winsock uses ioctlsocket instead of MSG_DONTWAIT #include static inline void set_nonblocking(SOCKET s) { u_long mode = 1; ioctlsocket(s, FIONBIO, &mode); } #include static inline void sleep_us(int microseconds) { Sleep(microseconds / 1000); // Windows uses milliseconds } #else #include #include #include #include #include #include #include static inline void net_init(void) {} // no-op on POSIX static inline void net_cleanup(void) {} // no-op on POSIX static inline void set_nonblocking(int s) { fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); } static inline void sleep_us(int microseconds) { usleep(microseconds); } static inline int net_errno(void) { return errno; } #define NET_EAGAIN EAGAIN #define NET_EINTR EINTR #endif