You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
6.2 KiB
219 lines
6.2 KiB
/** |
|
* Socket compatibility layer implementation |
|
*/ |
|
|
|
#include "socket_compat.h" |
|
#include "debug_config.h" |
|
|
|
#ifdef _WIN32 |
|
// ==================== Windows Implementation ==================== |
|
|
|
int socket_platform_init(void) { |
|
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"); |
|
return 0; |
|
} |
|
|
|
void socket_platform_cleanup(void) { |
|
WSACleanup(); |
|
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "Winsock cleanup completed"); |
|
} |
|
|
|
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 |
|
}
|
|
|