Consolidate socket lifecycle and wrapper documentation in header
This commit is contained in:
1 parent
4f3f6d3e60
commit
a288afd8ce
2 files changed
+15
-105
No files matched your search
+15
-6
@@ -2,6 +2,8 @@
|
||||
* Единые socket_t, коды ошибок и wrappers сокетов POSIX/Windows (включая MSYS2 UCRT64).
|
||||
* platform_init/cleanup обслуживают Winsock; UDP/nonblocking/options/sendto/recvfrom — операции ОС.
|
||||
* Созданные сокеты закрывает владелец через socket_close_wrapper; event loop находится в u_async.h.
|
||||
* Использование: platform_init → create_udp → set_nonblocking/options → sendto/recvfrom → close → cleanup.
|
||||
* До регистрации в uasync вызывающий должен включить nonblocking. Winsock init/cleanup согласовать между потоками.
|
||||
*/
|
||||
|
||||
#ifndef SOCKET_COMPAT_H
|
||||
@@ -45,12 +47,14 @@ extern "C" {
|
||||
#define ERR_INTR EINTR
|
||||
#endif
|
||||
|
||||
// Platform initialization/cleanup
|
||||
// POSIX: 0 без системной инициализации. Windows: WSAStartup при первом init, счётчик вложенности; 0 / -1.
|
||||
int socket_platform_init(void);
|
||||
// Парный cleanup: Windows уменьшает счётчик и вызывает WSACleanup на нуле; POSIX ничего не освобождает.
|
||||
void socket_platform_cleanup(void);
|
||||
|
||||
// Socket operations
|
||||
// UDP-сокет для family (обычно AF_INET/AF_INET6); SOCKET_INVALID при ошибке. Владение передаётся вызывающему.
|
||||
socket_t socket_create_udp(int family);
|
||||
// Включает nonblocking: 0 — успех, -1 — ошибка.
|
||||
int socket_set_nonblocking(socket_t sock);
|
||||
/* Закрыть сокет средствами ОС; на POSIX sock=0 оставляет дескриптор открытым и возвращает 0. */
|
||||
int socket_close_wrapper(socket_t sock);
|
||||
@@ -62,22 +66,27 @@ static inline int socket_get_error(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Socket options
|
||||
// Пробует установить оба буфера SO_SNDBUF/SO_RCVBUF: 0 при успехе обоих, -1 при любой ошибке; отката нет.
|
||||
int socket_set_buffers(socket_t sock, int sndbuf, int rcvbuf);
|
||||
// Устанавливает SO_REUSEADDR в значение reuse; 0 / -1.
|
||||
int socket_set_reuseaddr(socket_t sock, int reuse);
|
||||
// SO_BINDTODEVICE для строки ifname (не NULL); 0 / -1. Без поддержки опции, в том числе Windows, возвращает -1.
|
||||
int socket_bind_to_device(socket_t sock, const char* ifname);
|
||||
// SO_MARK в значение mark; 0 / -1. Без поддержки опции, в том числе Windows, возвращает -1.
|
||||
int socket_set_mark(socket_t sock, int mark);
|
||||
|
||||
// I/O operations
|
||||
// Один sendto/recvfrom с flags=0: число байт или SOCKET_ERROR_CODE; errno/WSA-код читать через socket_get_error.
|
||||
// буферами владеет вызывающий; для Windows len должен помещаться в int. dest_len — размер адреса назначения;
|
||||
// src_len при приёме — входная ёмкость/выходная длина адреса (может быть NULL по правилам recvfrom ОС).
|
||||
ssize_t socket_sendto(socket_t sock, const void* buf, size_t len,
|
||||
const struct sockaddr* dest, socklen_t dest_len);
|
||||
ssize_t socket_recvfrom(socket_t sock, void* buf, size_t len,
|
||||
struct sockaddr* src, socklen_t* src_len);
|
||||
|
||||
// Utility
|
||||
// Заимствованный текст ошибки: Windows — один статический буфер (перезаписывается следующим вызовом), POSIX — strerror.
|
||||
const char* socket_strerror(int err);
|
||||
|
||||
// взять порт из sockaddr_storage
|
||||
// IPv4/IPv6-порт в host byte order; 0 при NULL или другом семействе.
|
||||
uint16_t ss_get_port(const struct sockaddr_storage *addr);
|
||||
// Фактический IPv4/IPv6-порт уже привязанного сокета; 0 при ошибке.
|
||||
uint16_t socket_get_bound_port(socket_t sock);
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
# 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