Files
utun2/src/proxy/tcp_proxy_server.h
T

100 lines
7.4 KiB
C

/* Exit TCP-прокси: принимает CONNECT/DATA через UTUN-router и открывает обычный TCP к назначению.
* Поток определяется парой peer_node_id/stream_id; proxy_flow согласует окна и half-close.
* init учитывает tcp_proxy_server_enabled в конфиге; destroy закрывает потоки и общий UDP/ICMP-прокси.
* Сначала init, затем приём через router callback, в конце destroy; повторный init живого сервера недопустим.
* Состояние принадлежит UTUN_INSTANCE, операции и callbacks выполняются в его uasync-потоке.
* CLOSE дренирует запись и прекращает чтение; ERROR немедленно уничтожает поток, FIN — half-close. */
#ifndef TCP_PROXY_SERVER_H
#define TCP_PROXY_SERVER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "../lib/socket_compat.h"
#include "../lib/ll_queue.h"
#include "../lib/tcp_io.h"
#include "../routing_layer/etcp_router.h"
struct UTUN_INSTANCE;
struct UASYNC;
struct ll_entry;
struct ETCP_CONN;
#include "proxy_protocol.h"
struct tcp_proxy_server_conn {
struct tcp_proxy_server_conn* next; // следующий поток exit
struct tcp_proxy_server* ctx; // заимствованный владелец в inst
struct tcp_conn* tc; // собственный OS TCP к назначению
struct proxy_flow flow; // окно, FIN и control retry
uint32_t stream_id; // ID клиента; уникален в паре с peer_node_id
uint64_t peer_node_id; // конечный ingress-узел, не транспортный сосед
uint8_t dest_ip[4]; // IPv4 назначения в сетевом порядке
uint16_t dest_port; // порт назначения в сетевом порядке
uint8_t close_queued; // close-маркер уже поставлен в write_queue TCP
uint8_t cli_closed; // client sent CLOSE
void* diag_timer; // 1-секундный таймер диагностики
uint8_t freed; // логически удалён; сама структура освобождается через call_soon
struct queue_waiter_handle pause_waiter; // ожидание свободного места в router send_q
void* retry_timer; // fallback 500 мс: возобновить read_queue, DATA отправляется с force=0
uint32_t bytes_sent; // сумма входящих DATA, учитывается до проверки/записи в TCP
uint32_t bytes_relayed; // байт принято router для клиента
uint32_t drain_count; // число успешно отправленных DATA из read_queue
uint32_t data_count; // счётчик входящих DATA от клиента
struct UASYNC* ua; // заимствованный loop для таймеров и отложенного free
};
struct tcp_proxy_server {
int enabled; // exit обслуживает CONNECT/UDP/ICMP REQUEST
int conn_count; // число потоков в conns
struct tcp_proxy_server_conn* conns; // собственные потоки всех пиров
struct UTUN_INSTANCE* inst; // заимствованный instance, содержащий сервер
};
// Обнулить состояние и учесть config->global.tcp_proxy_server_enabled; NULL inst → -1, иначе 0.
// Без конфига/при отключении не bind-ит сервис. При включении bind SERVER и вызывает UDP/ICMP init.
// 0 не гарантирует успешный bind/UDP/ICMP: их ошибки не пробрасываются вызывающему коду.
int tcp_proxy_server_init(struct UTUN_INSTANCE* inst);
// Удалить потоки, выключить сервер, снять binding и уничтожить общие UDP/ICMP; NULL inst допустим.
// Перед этим остановить tcp_proxy_client того же inst; дать ua обработать отложенные освобождения.
void tcp_proxy_server_destroy(struct UTUN_INSTANCE* inst);
// Линейный поиск в ненулевом ctx по паре peer/sid; заимствованный указатель или NULL.
struct tcp_proxy_server_conn* tcp_proxy_server_find_conn(struct tcp_proxy_server* ctx, uint64_t peer, uint32_t stream_id);
// Немедленно удалить rc из списка, закрыть TCP и отменить таймеры/waiter; NULL допустим.
// Память rc освобождается отложенно в ua; сама функция не отправляет CLOSE/ERROR пиру.
void tcp_proxy_server_conn_free(struct tcp_proxy_server_conn* rc);
// Router callback: conn->instance — владелец, peer берётся из ROUTER_SVC_SRC_OFF entry.
// Принимает владение entry/dgram при любом исходе. Пустой payload router удаляет потоки этого peer.
void tcp_proxy_server_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry);
// entry — полный приёмный пакет CONNECT с IPv4/портом; принимает владение entry/dgram.
// inst должен быть включён, sid/src — уже разобранные поля. 0 = connect запущен/готов, -1 = ошибка.
// CONNECTED отправляется только после реального connect; таймаут — из connect_timeout_ms (0 = отключён).
int tcp_proxy_server_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry* entry,
uint32_t stream_id, uint64_t src_node_id);
// Полный entry DATA не короче RECV_HDR_SIZE; принимает владение entry/dgram. conn сейчас не используется.
// Peer берётся из entry; проверяет окно и ставит данные в OS write_queue. 0 = обработано, -1 = отклонено.
// Ошибка выделения в write_queue может закрыть поток и при возврате 0: это не подтверждение OS send.
int tcp_proxy_server_handle_data(struct UTUN_INSTANCE* inst, struct ETCP_CONN* conn, struct ll_entry* entry, uint32_t stream_id);
// CLOSE: прекратить чтение, отбросить read_queue и закрыть TCP после записи уже принятой write_queue.
void tcp_proxy_server_handle_close(struct UTUN_INSTANCE* inst, uint64_t peer, uint32_t stream_id);
// ERROR: немедленно удалить поток вместе с непрочитанными/незаписанными данными.
void tcp_proxy_server_handle_error(struct UTUN_INSTANCE* inst, uint64_t peer, uint32_t stream_id);
// FIN: поставить shutdown(SHUT_WR) после уже принятых DATA; обратное направление продолжает работать.
// handle_close/error/fin допускают NULL inst и отсутствующую пару peer/sid.
void tcp_proxy_server_handle_fin(struct UTUN_INSTANCE* inst, uint64_t peer, uint32_t stream_id);
#ifdef __cplusplus
}
#endif
#endif