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.
 
 
 
 
 
 

232 lines
6.6 KiB

/**
* 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
}