Files
utun2/lib/socket_compat_doc.md
T
evgeny 38c9f229bc stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll
- stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close
- utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP),
  add deferred drain in both Phase J and L
- stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39,
  exchange ed25519_pubkey in both handshake directions
- etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in
  etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb
- chat_sync.c: fix lk->conn NULL dereference for TCP links
- test_stcp.c: update stcp_server_create/stcp_client_connect callsites
- tools/chat_tcp_test: change transport udp→tcp
2026-08-07 00:48:27 +03:00

5.4 KiB
Raw Blame History

socket_compat — Cross-platform socket abstraction

1. Назначение

Унифицирует работу с UDP-сокетами между POSIX и Windows (MSYS2 UCRT64). Скрывает различия в типах дескрипторов (int vs SOCKET), инициализации подсистемы (WSAStartup/WSACleanup), кодах ошибок и сигнатурах системных вызовов.

2. Как пользоваться

Инициализация (однократно при старте)

if (socket_platform_init() != 0) { /* фатальная ошибка */ }
// ... работа с сокетами ...
socket_platform_cleanup();   // при завершении

На Windows WSAStartup/WSACleanup с refcount — можно вызывать init/cleanup вложенно.

Создание и настройка сокета

socket_t sock = socket_create_udp(AF_INET);     // или AF_INET6
if (sock == SOCKET_INVALID) { /* ошибка */ }

socket_set_nonblocking(sock);                   // обязательно для u_async
socket_set_reuseaddr(sock, 1);
socket_set_buffers(sock, 256*1024, 256*1024);   // SO_SNDBUF/SO_RCVBUF
socket_bind_to_device(sock, "eth0");            // только Linux, SO_BINDTODEVICE
socket_set_mark(sock, 42);                      // только Linux, SO_MARK

Отправка и приём

ssize_t sent = socket_sendto(sock, buf, len, (struct sockaddr*)&addr, addr_len);
ssize_t recv = socket_recvfrom(sock, buf, sizeof(buf), (struct sockaddr*)&src, &src_len);

uint16_t port = ss_get_port(&src);              // порт из sockaddr_storage

Обработка ошибок

if (sent == SOCKET_ERROR_CODE) {
    int err = socket_get_error();
    if (err == ERR_WOULDBLOCK) { /* нормально для неблокирующего */ }
    // на POSIX ERR_WOULDBLOCK == EWOULDBLOCK (может совпадать с EAGAIN)
    DEBUG_ERROR(..., "%s", socket_strerror(err));
}

Закрытие

socket_close_wrapper(sock);   // на POSIX: close() с защитой от fd 0

Ключевые нюансы

  • Всегда вызывать socket_platform_init() перед работой — иначе на Windows сокеты не будут работать
  • Всегда socket_set_nonblocking() — u_async требует неблокирующих сокетов
  • socket_t — на POSIX int, на Windows SOCKET (unsigned)
  • SOCKET_INVALID — константа для невалидного сокета (-1 на POSIX, INVALID_SOCKET на Windows)
  • SOCKET_ERROR_CODE — код ошибки сокетных вызовов (-1 на POSIX, SOCKET_ERROR на Windows)
  • socket_strerror() на Windows использует статический буфер — не thread-safe для параллельного использования
  • socket_bind_to_device и socket_set_mark — только Linux, на остальных платформах возвращают -1 с DEBUG-сообщением
  • socket_close_wrapper на POSIX не закроет fd 0 (защита)

3. API

Типы и константы

Имя Назначение
socket_t Кроссплатформенный тип дескриптора сокета (int / SOCKET)
SOCKET_INVALID Невалидный сокет (-1 / INVALID_SOCKET)
SOCKET_ERROR_CODE Код ошибки сокетного вызова (-1 / SOCKET_ERROR)
ERR_WOULDBLOCK / ERR_AGAIN / ERR_INTR Кроссплатформенные коды ошибок

Инициализация

Функция Назначение
socket_platform_init() Инициализация сокетной подсистемы (WSAStartup на Windows). 0 — успех
socket_platform_cleanup() Деинициализация (WSACleanup на Windows), refcount

Создание и настройка

Функция Назначение
socket_create_udp(family) Создать UDP-сокет (AF_INET или AF_INET6)
socket_set_nonblocking(sock) Перевести в неблокирующий режим
socket_set_buffers(sock, snd, rcv) Установить SO_SNDBUF и SO_RCVBUF
socket_set_reuseaddr(sock, reuse) Установить SO_REUSEADDR
socket_bind_to_device(sock, ifname) Привязать к интерфейсу (Linux SO_BINDTODEVICE)
socket_set_mark(sock, mark) Установить SO_MARK (Linux)

I/O

Функция Назначение
socket_sendto(sock, buf, len, dest, dest_len) Отправить UDP-датаграмму
socket_recvfrom(sock, buf, len, src, src_len) Принять UDP-датаграмму

Утилиты

Функция Назначение
socket_get_error() Текущий код ошибки (inline: WSAGetLastError() / errno)
socket_strerror(err) Текстовое описание ошибки (Windows: статический буфер, не thread-safe)
socket_close_wrapper(sock) Закрыть сокет (POSIX: защита от закрытия fd 0)
ss_get_port(addr) Извлечь порт в host byte order из sockaddr_storage