/** * Socket compatibility layer implementation */ #include "socket_compat.h" #include "debug_config.h" #ifdef _WIN32 // ==================== Windows Implementation ==================== static int wsa_init_count = 0; int socket_platform_init(void) { if (wsa_init_count == 0) { WSADATA wsaData; int result = WSAStartup(MAKEWORD(2, 2), &wsaData); if (result != 0) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "WSAStartup failed: %d", result); return -1; } DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "Winsock 2.2 initialized"); } wsa_init_count++; DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "Winsock init count: %d", wsa_init_count); return 0; } void socket_platform_cleanup(void) { if (wsa_init_count > 0) { wsa_init_count--; if (wsa_init_count == 0) { WSACleanup(); DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "Winsock cleanup completed"); } else { DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "Winsock init count after cleanup: %d", wsa_init_count); } } } int socket_set_nonblocking(socket_t sock) { u_long mode = 1; if (ioctlsocket(sock, FIONBIO, &mode) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "ioctlsocket(FIONBIO) failed: %d", socket_get_error()); return -1; } return 0; } int socket_close_wrapper(socket_t sock) { return closesocket(sock); } const char* socket_strerror(int err) { static char buf[256]; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof(buf), NULL); return buf; } #else // ==================== POSIX Implementation ==================== int socket_platform_init(void) { // No initialization needed on POSIX DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "POSIX socket subsystem ready"); return 0; } void socket_platform_cleanup(void) { // No cleanup needed on POSIX DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "POSIX socket cleanup completed"); } int socket_set_nonblocking(socket_t sock) { int flags = fcntl(sock, F_GETFL, 0); if (flags < 0) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "fcntl(F_GETFL) failed: %s", strerror(errno)); return -1; } if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "fcntl(F_SETFL) failed: %s", strerror(errno)); return -1; } return 0; } int socket_close_wrapper(socket_t sock) { return close(sock); } const char* socket_strerror(int err) { return strerror(err); } #endif // ==================== Universal Implementations ==================== socket_t socket_create_udp(int family) { socket_t sock = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socket(SOCK_DGRAM) failed: %s", socket_strerror(socket_get_error())); return SOCKET_INVALID; } DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "Created UDP socket: %ld", (long)sock); return sock; } int socket_set_buffers(socket_t sock, int sndbuf, int rcvbuf) { int err = 0; #ifdef _WIN32 // Windows uses char* for optval if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char*)&sndbuf, sizeof(sndbuf)) != 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_SNDBUF failed: %s", socket_strerror(socket_get_error())); err = -1; } if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char*)&rcvbuf, sizeof(rcvbuf)) != 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_RCVBUF failed: %s", socket_strerror(socket_get_error())); err = -1; } #else if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_SNDBUF failed: %s", strerror(errno)); err = -1; } if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_RCVBUF failed: %s", strerror(errno)); err = -1; } #endif return err; } int socket_set_reuseaddr(socket_t sock, int reuse) { #ifdef _WIN32 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) != 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_REUSEADDR failed: %s", socket_strerror(socket_get_error())); return -1; } #else if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_REUSEADDR failed: %s", strerror(errno)); return -1; } #endif return 0; } int socket_bind_to_device(socket_t sock, const char* ifname) { #ifndef _WIN32 #ifdef SO_BINDTODEVICE if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_BINDTODEVICE failed: %s", strerror(errno)); return -1; } return 0; #else (void)sock; (void)ifname; DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SO_BINDTODEVICE not available"); return -1; #endif #else // Windows doesn't support SO_BINDTODEVICE (void)sock; (void)ifname; DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SO_BINDTODEVICE not available on Windows"); return -1; #endif } int socket_set_mark(socket_t sock, int mark) { #ifndef _WIN32 #ifdef SO_MARK if (setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) { DEBUG_WARN(DEBUG_CATEGORY_SOCKET, "SO_MARK failed: %s", strerror(errno)); return -1; } return 0; #else (void)sock; (void)mark; DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SO_MARK not available"); return -1; #endif #else // Windows doesn't support SO_MARK (void)sock; (void)mark; DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SO_MARK not available on Windows"); return -1; #endif } ssize_t socket_sendto(socket_t sock, const void* buf, size_t len, struct sockaddr* dest, socklen_t dest_len) { #ifdef _WIN32 return sendto(sock, (const char*)buf, (int)len, 0, dest, dest_len); #else return sendto(sock, buf, len, 0, dest, dest_len); #endif } ssize_t socket_recvfrom(socket_t sock, void* buf, size_t len, struct sockaddr* src, socklen_t* src_len) { #ifdef _WIN32 int fromlen = src_len ? (int)*src_len : 0; ssize_t ret = recvfrom(sock, (char*)buf, (int)len, 0, src, src_len ? &fromlen : NULL); if (src_len) *src_len = (socklen_t)fromlen; return ret; #else return recvfrom(sock, buf, len, 0, src, src_len); #endif }