- 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
82 lines
4.3 KiB
Markdown
82 lines
4.3 KiB
Markdown
# platform_compat — Cross-platform compatibility layer
|
||
|
||
## 1. Назначение
|
||
Унифицирует различия между POSIX (Linux/FreeBSD) и Windows (MSYS2 UCRT64) на уровне системных вызовов и типов. Предоставляет единый API для байтового порядка, строковых функций, энтропии, работы с сетевыми интерфейсами и времени. Полностью заголовочный (inline) для макросов и тривиальных обёрток, `.c` только для нетривиальных реализаций.
|
||
|
||
## 2. Как пользоваться
|
||
Подключить `"platform_compat.h"` — всё остальное разрешается автоматически в зависимости от `_WIN32`.
|
||
|
||
### Байтовый порядок
|
||
```c
|
||
uint16_t v16 = htobe16(x); // host → big-endian
|
||
uint32_t v32 = be32toh(x); // big-endian → host
|
||
uint64_t v64 = be64toh(x); // big-endian → host
|
||
// На Linux использует <endian.h>, на Windows — _byteswap_*
|
||
```
|
||
|
||
### Криптостойкий random
|
||
```c
|
||
uint8_t salt[8];
|
||
if (random_bytes(salt, sizeof(salt)) != 0) { /* ошибка */ }
|
||
// Linux: /dev/urandom, Windows: BCryptGenRandom
|
||
```
|
||
|
||
### Сетевые интерфейсы
|
||
```c
|
||
// Определить интерфейс маршрута по умолчанию
|
||
uint32_t ifidx = get_default_route_netif_index(AF_INET); // или AF_INET6
|
||
|
||
// Получить IPv4 адрес интерфейса по индексу
|
||
uint32_t ipv4 = get_interface_ip_by_index(ifidx); // network byte order
|
||
|
||
// Получить IPv6 адрес (постоянный или временный)
|
||
uint8_t ipv6[16];
|
||
if (get_interface_ipv6_by_index(ifidx, 1, ipv6) == 0) { // temporary=1
|
||
// ipv6 содержит 16 байт адреса
|
||
}
|
||
```
|
||
**Windows**: `get_interface_ip_by_index`, `get_interface_ipv6_by_index`, `get_default_route_netif_index` — заглушки (возвращают 0/-1).
|
||
|
||
### Время
|
||
```c
|
||
struct timeval tv;
|
||
utun_gettimeofday(&tv, NULL); // макрос: на Linux → gettimeofday, на Windows → inline-реализация
|
||
```
|
||
|
||
### Прочее
|
||
- `strcasecmp`/`strncasecmp` — на Windows `_stricmp`/`_strnicmp`
|
||
- `memmem` — на Windows inline-реализация `compat_memmem`
|
||
- `pipe` — на Windows `_pipe` с `_O_BINARY`
|
||
- `poll` — на Windows `WSAPoll`, флаги `POLLIN`/`POLLOUT` и т.д. определены если отсутствуют
|
||
- `ssize_t` — определён если отсутствует
|
||
- `fcntl` — на Windows упрощённая реализация только для `F_SETFL`/`O_NONBLOCK`
|
||
- `utun_mkdir` — кроссплатформенный `mkdir`
|
||
|
||
### Ограничения
|
||
- Функции сетевых интерфейсов работают только на POSIX, на Windows — заглушки
|
||
- `get_default_route_netif_index` создаёт временный UDP-сокет к `8.8.8.8` (IPv4) или `2001:4860:4860::8888` (IPv6) для определения интерфейса
|
||
- Только IPv4/IPv6; `family` только `AF_INET` или `AF_INET6`
|
||
|
||
## 3. API
|
||
|
||
### Байтовый порядок
|
||
| Макрос | Назначение |
|
||
|--------|------------|
|
||
| `htobe16(x)` / `be16toh(x)` | 16-bit host ↔ big-endian |
|
||
| `htobe32(x)` / `be32toh(x)` | 32-bit host ↔ big-endian |
|
||
| `htobe64(x)` / `be64toh(x)` | 64-bit host ↔ big-endian |
|
||
|
||
### Основные функции
|
||
| Функция | Назначение |
|
||
|---------|------------|
|
||
| `random_bytes(buffer, len)` | Криптостойкие случайные байты. 0 — успех, -1 — ошибка |
|
||
| `get_interface_ip_by_index(ifindex)` | IPv4 адрес интерфейса в network byte order, 0 при ошибке |
|
||
| `get_interface_ipv6_by_index(ifindex, temporary, out)` | IPv6 адрес (temporary=1 — временный privacy-адрес), 0 — успех |
|
||
| `get_default_route_netif_index(family)` | ifindex дефолтного маршрута через connect() к внешнему IP |
|
||
|
||
### Макросы-заменители (условные)
|
||
| Макрос | Назначение |
|
||
|--------|------------|
|
||
| `utun_gettimeofday(tv, tz)` | gettimeofday (inline на Windows) |
|
||
| `utun_mkdir(path, mode)` | mkdir |
|