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
This commit is contained in:
1 parent
a3783b5f55
commit
38c9f229bc
1272 files changed
+968388
-1
No files matched your search
@@ -0,0 +1,99 @@
|
||||
# socket_compat — Cross-platform socket abstraction
|
||||
|
||||
## 1. Назначение
|
||||
Унифицирует работу с UDP-сокетами между POSIX и Windows (MSYS2 UCRT64). Скрывает различия в типах дескрипторов (`int` vs `SOCKET`), инициализации подсистемы (WSAStartup/WSACleanup), кодах ошибок и сигнатурах системных вызовов.
|
||||
|
||||
## 2. Как пользоваться
|
||||
|
||||
### Инициализация (однократно при старте)
|
||||
```c
|
||||
if (socket_platform_init() != 0) { /* фатальная ошибка */ }
|
||||
// ... работа с сокетами ...
|
||||
socket_platform_cleanup(); // при завершении
|
||||
```
|
||||
На Windows WSAStartup/WSACleanup с refcount — можно вызывать init/cleanup вложенно.
|
||||
|
||||
### Создание и настройка сокета
|
||||
```c
|
||||
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
|
||||
```
|
||||
|
||||
### Отправка и приём
|
||||
```c
|
||||
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
|
||||
```
|
||||
|
||||
### Обработка ошибок
|
||||
```c
|
||||
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));
|
||||
}
|
||||
```
|
||||
|
||||
### Закрытие
|
||||
```c
|
||||
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` |
|
||||
Reference in new issue
Block a user