# STCP Server — приём и рукопожатие соединений ## 1. Назначение STCP Server — серверная сторона протокола STCP. Создаёт слушающий TCP-сокет на указанном порту, принимает входящие соединения, выполняет серверную часть X25519-рукопожатия и поднимает зашифрованный канал AES-CTR для обмена сообщениями. Использует общую структуру `struct stcp_conn` из `stcp.h`. ## 2. Как пользоваться ```c struct stcp_server *srv = stcp_server_create(ua, port, &my_keys, on_connect_cb, conn_arg, // вызывается после успешного рукопожатия on_close_cb, close_arg); // вызывается при закрытии/ошибке // ... use ... stcp_server_destroy(srv); ``` После завершения рукопожатия соединение переходит в `STCP_STATE_DATA`, вызывается `connect_cb`. Вышестоящий код может слать сообщения через `tx_queue` — они будут зашифрованы с CRC32 и отправлены. Входящие расшифрованные сообщения попадают в `rx_queue`. Ключевые нюансы: - Сервер принимает клиентский pubkey+salt (обфусцированный), извлекает pubkey через `sc_obfuscate_pubkey`, выполняет ECDH. - Отправляет ответ: статус OK + padding + CRC32, всё зашифровано AES-CTR. - После рукопожатая трафик шифруется потоковым AES-CTR (XOR), для каждого направления — свой stream. - Рукопожатие обрабатывается в два этапа: `process_client_handshake` (извлечение ключа, дешифровка) → `finish_client_handshake` (отправка ответа, переход в DATA). ## 3. API ### stcp_server — внутренняя структура Слушающий сокет, ключи сервера, коллбэки `connect_cb` / `close_cb`. Не экспортируется, создаётся только через `stcp_server_create`. ### Функции - `stcp_server_create(ua, port, keys, connect_cb, arg, close_cb, close_arg)` — создать сервер: открыть TCP-сокет, bind к порту (IPV4, INADDR_ANY), listen(16), зарегистрировать accept-коллбэк. При приёме соединения создаёт `struct stcp_conn` в состоянии `STCP_STATE_HS_SERVER_WAIT`. - `stcp_server_destroy(srv)` — закрыть слушающий сокет, освободить память. ### Протокол рукопожатия (серверная сторона) 1. Сервер читает `SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT` байт (pubkey+salt + зашифрованные padding_size + CRC32). 2. Деобфусцирует клиентский pubkey (`sc_obfuscate_pubkey`, salt XOR с SHA256(salt||server_pubkey)). 3. Выполняет ECDH (`sc_init_ctx` + `sc_set_peer_public_key`) → получает `session_key`, инициализирует `stream_send`/`stream_recv`. 4. Расшифровывает padding_size, проверяет CRC32, ожидает padding-байты. 5. Формирует ответ: salt2(8) + обфусцированный серверный pubkey(32) + status=OK(1) + padding_size(2) + CRC32(4) + padding(8). Всё кроме salt2 зашифровано `sc_stream_xor`. 6. Переходит в `STCP_STATE_DATA`, вызывает `on_ready` (== `connect_cb`).