- CMakeLists в корне: ветвление ESP_PLATFORM (idf_component_register, lwip/esp_timer/esp_hw_support/pthread) / POSIX (статическая библиотека fgl-aircon, C++20, -fno-exceptions -fno-rtti, -Werror). - src/ayla/platform: сокеты/потоки/CSPRNG/время; posix (getrandom, poll, pthread_join) и esp-idf (lwip_select, esp_fill_random, pthread-слой IDF); tcp_shutdown/tcp_local_port/thread_join для управляемой остановки. - src/ayla: log (sink, без printf); мини-httpd/1.1 (keep-alive, Content-Length, лимиты заголовков/тела, ephemeral-порт, жизненный цикл с гарантией завершения потока: shutdown(active)→join→close). - tests/ayla: platform (join, loopback+shutdown) и httpd (404, keep-alive, обработчик/парсинг, oversize-400, stop при живом соединении, стрим заголовков). doctest через FetchContent. - scripts/ci.sh: сборка+ctest. ESP-IDF v5.5.5 esp32: смоук-сборка с ядром как компонентом — Project build complete. Ревью под-агентом: 3 круга, все блокеры (жизненный цикл httpd) закрыты, APPROVED.
58 lines
3.3 KiB
C++
58 lines
3.3 KiB
C++
// Платформенный слой: сокеты, таймеры, CSPRNG, потоки.
|
||
// Одна реализация на платформу: platform/posix (Linux) и platform/esp-idf.
|
||
// Все функции — блокирующие; коды ошибок через возвращаемое значение (-1),
|
||
// без исключений. IP-адреса — uint32_t в host byte order.
|
||
#pragma once
|
||
|
||
#include <cstddef>
|
||
#include <cstdint>
|
||
|
||
namespace fgl::plat {
|
||
|
||
// ---- время ----
|
||
// Монотонные миллисекунды с неопределённой точки отсчёта.
|
||
uint64_t now_ms();
|
||
|
||
// ---- CSPRNG ----
|
||
// Заполняет buf cryptographically-secure случайными байтами.
|
||
bool random(uint8_t* buf, size_t len);
|
||
|
||
// ---- потоки ----
|
||
// Идентификатор потока (непрозрачный). Валиден между thread_create и
|
||
// завершением thread_join.
|
||
using ThreadId = void*;
|
||
// Создаёт поток с именем name (для отладки) и стеком stack_bytes (0 — по
|
||
// умолчанию платформы; для ESP-IDF задавать явно, >= 4096).
|
||
// out_id может быть nullptr (тогда присоединиться нельзя).
|
||
bool thread_create(void (*fn)(void*), void* ctx, const char* name,
|
||
uint32_t stack_bytes, ThreadId* out_id);
|
||
// Блокирующе ждёт завершения потока. Гарантирует, что код потока больше не
|
||
// исполняется (объекты потока можно освобождать после возврата).
|
||
void thread_join(ThreadId id);
|
||
// Мягкая блокирующая задержка текущего потока.
|
||
void sleep_ms(uint32_t ms);
|
||
|
||
// ---- TCP (клиент и сервер) ----
|
||
// Создаёт слушающий сокет; возвращает fd или -1. port==0 — любой свободный
|
||
// (узнать выбранный: tcp_local_port).
|
||
int tcp_listen(uint16_t port);
|
||
// Локальный порт сокета (для ephemeral-слушателем).
|
||
uint16_t tcp_local_port(int fd);
|
||
// Принимает соединение (блокирующе); возвращает fd клиента или -1.
|
||
// peer_ip (host byte order) / peer_port могут быть nullptr.
|
||
int tcp_accept(int listen_fd, uint32_t* peer_ip, uint16_t* peer_port);
|
||
// Подключается к host:port (host — DNS-имя или dotted-quad) с таймаутом.
|
||
int tcp_connect(const char* host, uint16_t port, uint32_t timeout_ms);
|
||
long tcp_send(int fd, const void* buf, size_t len); // >0 / -1
|
||
// Блокирующее чтение; 0 — EOF, -1 — ошибка/таймаут.
|
||
long tcp_recv(int fd, void* buf, size_t len);
|
||
// Таймауты на последующие recv/send (0 — без таймаута).
|
||
bool tcp_set_timeout(int fd, uint32_t rx_ms, uint32_t tx_ms);
|
||
// Ожидание читаемости fd (для выходa из блокирующего accept). Таймаут в мс.
|
||
bool tcp_poll_readable(int fd, uint32_t timeout_ms);
|
||
// Прерывает блокированные recv/send на сокете (для остановки сервера).
|
||
bool tcp_shutdown(int fd);
|
||
void tcp_close(int fd);
|
||
|
||
} // namespace fgl::plat
|