Добавлен group_id в etcp_router и topo_group, удалён msg_transport
- etcp_router: SVC_ROUTE_HDR (+8B), ETCP_ROUTER_CONN/TRANSIT_QUEUE хеши расширены под group_id - Все caller'ы (proxy, routing, conn_mgr, nat, chatgui, tests) обновлены - topo_group: глобальный реестр TOPO_NODE по node_id, ref_count=0 при создании - BGP-обмен активируется для всех групп (а не только дефолтной) - Протокол: group_id добавлен в WITHDRAW/TABLE_REQ/TABLE_COMPLETE/ERR_GROUP_MISMATCH - Per-connection коллбэки заменены на instance-level conn_status - msg_transport полностью удалён из проекта 57/57 тестов
This commit is contained in:
1 parent
5265783164
commit
852ce401e7
37 files changed
+375
-1125
No files matched your search
@@ -40,7 +40,6 @@ utun_CORE_SOURCES = \
|
||||
transport_layer/etcp_api.c \
|
||||
transport_layer/etcp_connect.c \
|
||||
control_server.c \
|
||||
msg_transport.c \
|
||||
firewall.c \
|
||||
eim_nat.c \
|
||||
nat_transport.c \
|
||||
@@ -96,7 +95,6 @@ libutun_a_SOURCES = \
|
||||
transport_layer/etcp_api.c \
|
||||
transport_layer/etcp_connect.c \
|
||||
control_server.c \
|
||||
msg_transport.c \
|
||||
firewall.c \
|
||||
eim_nat.c \
|
||||
nat_transport.c \
|
||||
|
||||
@@ -47,7 +47,6 @@ typedef enum {
|
||||
SECTION_NAT,
|
||||
SECTION_TCP_PROXY_CLIENT,
|
||||
SECTION_TCP_PROXY_SERVER,
|
||||
SECTION_MSG_TRANSPORT,
|
||||
SECTION_NETWORK,
|
||||
SECTION_GUI,
|
||||
SECTION_NTP
|
||||
@@ -459,17 +458,6 @@ static int parse_control(const char *key, const char *value, struct global_confi
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_msg_transport(const char *key, const char *value, struct global_config *global, const char *filename, int line_num) {
|
||||
if (strcmp(key, "port") == 0) {
|
||||
char port_str[16];
|
||||
snprintf(port_str, sizeof(port_str), "%s", value);
|
||||
parse_sockaddr("127.0.0.1", port_str, &global->msg_transport_sock);
|
||||
return 0;
|
||||
}
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown msg_transport option '%s'. Valid: port", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_tcp_proxy_client(const char *key, const char *value, struct global_config *global, const char *filename, int line_num) {
|
||||
if (strcmp(key, "enabled") == 0) {
|
||||
global->tcp_proxy_client_enabled = strcasecmp(value, "yes") == 0 || strcasecmp(value, "1") == 0 || strcasecmp(value, "true") == 0;
|
||||
@@ -764,7 +752,6 @@ static section_type_t parse_section_header(const char *line, char *name, size_t
|
||||
if (strcasecmp(section, "nat") == 0) return SECTION_NAT;
|
||||
if (strcasecmp(section, "tcp_proxy_client") == 0) return SECTION_TCP_PROXY_CLIENT;
|
||||
if (strcasecmp(section, "tcp_proxy_server") == 0) return SECTION_TCP_PROXY_SERVER;
|
||||
if (strcasecmp(section, "msg_transport") == 0) return SECTION_MSG_TRANSPORT;
|
||||
if (strcasecmp(section, "ntp") == 0) return SECTION_NTP;
|
||||
if (strcasecmp(section, "gui") == 0) return SECTION_GUI;
|
||||
|
||||
@@ -970,11 +957,6 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
cfg->global.tcp_recv_buf = atoi(value);
|
||||
}
|
||||
break;
|
||||
case SECTION_MSG_TRANSPORT:
|
||||
if (parse_msg_transport(key, value, &cfg->global, filename, line_num) < 0) {
|
||||
// parse_msg_transport already printed the error
|
||||
}
|
||||
break;
|
||||
case SECTION_NETWORK:
|
||||
if (cur_network && parse_network(key, value, cur_network, filename, line_num) < 0) {
|
||||
// parse_network already printed the error
|
||||
@@ -1122,7 +1104,6 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha
|
||||
case SECTION_NAT: cfg->global.nat_enabled = 1; parse_nat(key, value, &cfg->global, filename, line_num); break;
|
||||
case SECTION_TCP_PROXY_CLIENT: cfg->global.tcp_proxy_client_enabled = 1; parse_tcp_proxy_client(key, value, &cfg->global, filename, line_num); break;
|
||||
case SECTION_TCP_PROXY_SERVER: cfg->global.tcp_proxy_server_enabled = 1; if (strcmp(key, "tcp_recv_buf") == 0) cfg->global.tcp_recv_buf = atoi(value); break;
|
||||
case SECTION_MSG_TRANSPORT: parse_msg_transport(key, value, &cfg->global, filename, line_num); break;
|
||||
case SECTION_NETWORK: if (cur_network) parse_network(key, value, cur_network, filename, line_num); break;
|
||||
case SECTION_NTP: if (strcmp(key, "enabled") == 0) cfg->global.ntp_enabled = strcasecmp(value, "yes") == 0 || strcasecmp(value, "1") == 0 || strcasecmp(value, "true") == 0; else if (strcmp(key, "server") == 0) { struct CFG_NTP_SERVER *ns = u_calloc(1, sizeof(struct CFG_NTP_SERVER)); if (ns) { strncpy(ns->name, value, sizeof(ns->name) - 1); ns->name[sizeof(ns->name) - 1] = '\0'; ns->next = cfg->global.ntp_servers; cfg->global.ntp_servers = ns; cfg->global.ntp_server_count++; } } else if (strcmp(key, "interval") == 0) { cfg->global.ntp_resync_interval = atoi(value); if (cfg->global.ntp_resync_interval < 60) cfg->global.ntp_resync_interval = 60; } else DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown ntp option '%s'", filename, line_num, key); break;
|
||||
case SECTION_GUI: break;
|
||||
|
||||
@@ -115,8 +115,6 @@ struct global_config {
|
||||
int mtu;
|
||||
struct sockaddr_storage control_sock;
|
||||
char control_ip[MAX_ADDR_LEN]; // Control server IP address
|
||||
struct sockaddr_storage msg_transport_sock;
|
||||
|
||||
// Debug and logging configuration
|
||||
char log_file[256]; // Path to log file (empty = stdout)
|
||||
char db_path[256]; // Path to SQLite database (empty = disabled)
|
||||
|
||||
@@ -68,8 +68,6 @@ free_config(cfg);
|
||||
| `[nat]` | `parse_nat()` | `tun_ifname`, `tun_ip`, `nat_via`, `port_start`, `port_end`, `forward` (proto:ip:in_port:ext_port) |
|
||||
| `[tcp_proxy_client]` | `parse_tcp_proxy_client()` | `enabled`, `tun_name`, `tun_ip`, `mtu`, `via_node`, `socks_*`, `http_proxy_*`, `forward` (port -> ip:port) |
|
||||
| `[tcp_proxy_server]` | inline | `tcp_recv_buf` |
|
||||
| `[msg_transport]` | `parse_msg_transport()` | `port` |
|
||||
| `[debug]` | inline | `категория=уровень` (до 16 категорий) |
|
||||
| `[ntp]` | inline | `enabled`, `server`, `interval` |
|
||||
| `[gui]` | игнорируется | (зарезервировано) |
|
||||
|
||||
|
||||
@@ -1,638 +0,0 @@
|
||||
/*
|
||||
* msg_transport.c — TCP-сервер транспорта сообщений (local IPC → ETCP)
|
||||
*
|
||||
* Принимает TCP-соединения от локальных приложений (протокол msg_transport.h),
|
||||
* привязывает к remote peer и пересылает данные через etcp_router.
|
||||
*/
|
||||
|
||||
#include "msg_transport.h"
|
||||
#include "utun_instance.h"
|
||||
#include "etcp_router.h"
|
||||
#include "etcp.h"
|
||||
#include "secure_channel.h"
|
||||
#include "topo_group.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_CATEGORY_MSGTRANSPORT
|
||||
#define DEBUG_CATEGORY_MSGTRANSPORT DEBUG_CATEGORY_GENERAL
|
||||
#endif
|
||||
|
||||
/* ============================================================================
|
||||
* Внутренние структуры
|
||||
* ============================================================================ */
|
||||
|
||||
struct msg_client {
|
||||
struct msg_client* next;
|
||||
struct msg_transport* transport;
|
||||
socket_t fd;
|
||||
void* socket_id;
|
||||
uint8_t recv_buffer[MSG_MAX_MSG_SIZE];
|
||||
uint16_t recv_len;
|
||||
uint64_t bound_peer_id; /* 0 = не забинден */
|
||||
uint8_t is_localhost; /* 1 = подключение с loopback */
|
||||
};
|
||||
|
||||
struct msg_transport {
|
||||
struct UTUN_INSTANCE* instance;
|
||||
struct UASYNC* ua;
|
||||
socket_t listen_fd;
|
||||
void* listen_socket_id;
|
||||
struct sockaddr_storage bind_addr;
|
||||
struct msg_client* clients;
|
||||
uint32_t client_count;
|
||||
uint32_t max_clients;
|
||||
uint8_t svc_id;
|
||||
struct msg_transport_counters counters;
|
||||
};
|
||||
|
||||
/* ============================================================================
|
||||
* Forward declarations
|
||||
* ============================================================================ */
|
||||
|
||||
static void accept_callback(socket_t fd, void* arg);
|
||||
static void client_read_callback(socket_t fd, void* arg);
|
||||
static void client_except_callback(socket_t fd, void* arg);
|
||||
static void close_client(struct msg_transport* t, struct msg_client* client);
|
||||
|
||||
static void handle_client_data(struct msg_transport* t, struct msg_client* client);
|
||||
static void on_etcp_recv(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
static int forward_to_peer(struct msg_transport* t, uint64_t dst_peer_id,
|
||||
const uint8_t* data, size_t data_len, int is_signed);
|
||||
static void send_response(struct msg_client* client, uint8_t type, uint64_t id,
|
||||
const uint8_t* data, size_t data_len);
|
||||
static void send_error(struct msg_client* client, uint8_t error_code, const char* msg);
|
||||
|
||||
/* ============================================================================
|
||||
* Инициализация / завершение
|
||||
* ============================================================================ */
|
||||
|
||||
int msg_transport_init(struct msg_transport** out,
|
||||
struct UTUN_INSTANCE* instance,
|
||||
struct UASYNC* ua,
|
||||
struct sockaddr_storage* bind_addr,
|
||||
uint32_t max_clients,
|
||||
uint8_t svc_id) {
|
||||
if (!out || !instance || !ua || !bind_addr) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "invalid args out=%p inst=%p ua=%p addr=%p",
|
||||
(void*)out, (void*)instance, (void*)ua, (void*)bind_addr);
|
||||
return -1;
|
||||
}
|
||||
if (bind_addr->ss_family == 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "bind_addr has no family, skipping");
|
||||
*out = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msg_transport* t = u_calloc(1, sizeof(*t));
|
||||
if (!t) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "u_calloc failed");
|
||||
return -1;
|
||||
}
|
||||
t->instance = instance;
|
||||
t->ua = ua;
|
||||
t->max_clients = max_clients ? max_clients : 8;
|
||||
t->svc_id = svc_id;
|
||||
memcpy(&t->bind_addr, bind_addr, sizeof(*bind_addr));
|
||||
|
||||
int family = bind_addr->ss_family;
|
||||
t->listen_fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (t->listen_fd == INVALID_SOCKET) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "socket() failed: %d", WSAGetLastError());
|
||||
u_free(t); return -1;
|
||||
}
|
||||
u_long nonblock = 1;
|
||||
ioctlsocket(t->listen_fd, FIONBIO, &nonblock);
|
||||
int reuse = 1;
|
||||
setsockopt(t->listen_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
|
||||
#else
|
||||
if (t->listen_fd < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "socket() failed: %s", strerror(errno));
|
||||
u_free(t); return -1;
|
||||
}
|
||||
int reuse = 1;
|
||||
setsockopt(t->listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
int flags = fcntl(t->listen_fd, F_GETFL, 0);
|
||||
if (flags >= 0) fcntl(t->listen_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
socklen_t addr_len = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (bind(t->listen_fd, (struct sockaddr*)bind_addr, addr_len) == SOCKET_ERROR) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "bind() failed: %d", WSAGetLastError());
|
||||
closesocket(t->listen_fd); u_free(t); return -1;
|
||||
}
|
||||
if (listen(t->listen_fd, 5) == SOCKET_ERROR) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "listen() failed: %d", WSAGetLastError());
|
||||
closesocket(t->listen_fd); u_free(t); return -1;
|
||||
}
|
||||
#else
|
||||
if (bind(t->listen_fd, (struct sockaddr*)bind_addr, addr_len) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "bind() failed: %s", strerror(errno));
|
||||
close(t->listen_fd); u_free(t); return -1;
|
||||
}
|
||||
if (listen(t->listen_fd, 5) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "listen() failed: %s", strerror(errno));
|
||||
close(t->listen_fd); u_free(t); return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
t->listen_socket_id = uasync_add_socket_t(ua, t->listen_fd,
|
||||
accept_callback, NULL, NULL, t);
|
||||
if (!t->listen_socket_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "uasync_add_socket_t failed for listen_fd");
|
||||
#ifdef _WIN32
|
||||
closesocket(t->listen_fd);
|
||||
#else
|
||||
close(t->listen_fd);
|
||||
#endif
|
||||
u_free(t); return -1;
|
||||
}
|
||||
|
||||
if (etcp_router_bind(instance, svc_id, on_etcp_recv) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "etcp_router_bind(svc_id=%u) failed", svc_id);
|
||||
uasync_remove_socket_t(ua, t->listen_fd);
|
||||
#ifdef _WIN32
|
||||
closesocket(t->listen_fd);
|
||||
#else
|
||||
close(t->listen_fd);
|
||||
#endif
|
||||
u_free(t); return -1;
|
||||
}
|
||||
|
||||
if (family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)bind_addr;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "msg_transport listening on %s:%d svc_id=%u",
|
||||
ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port), svc_id);
|
||||
} else {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)bind_addr;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "msg_transport listening on [%s]:%d svc_id=%u",
|
||||
ip_to_str(&sin6->sin6_addr, AF_INET6).str, ntohs(sin6->sin6_port), svc_id);
|
||||
}
|
||||
|
||||
*out = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msg_transport_shutdown(struct msg_transport* t) {
|
||||
if (!t) return;
|
||||
|
||||
while (t->clients) close_client(t, t->clients);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (t->listen_fd != INVALID_SOCKET) {
|
||||
uasync_remove_socket_t(t->ua, t->listen_fd);
|
||||
t->listen_socket_id = NULL;
|
||||
closesocket(t->listen_fd);
|
||||
t->listen_fd = INVALID_SOCKET;
|
||||
}
|
||||
#else
|
||||
if (t->listen_fd >= 0) {
|
||||
uasync_remove_socket_t(t->ua, t->listen_fd);
|
||||
t->listen_socket_id = NULL;
|
||||
close(t->listen_fd);
|
||||
t->listen_fd = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "msg_transport shutdown complete svc_id=%u", t->svc_id);
|
||||
memset(t, 0, sizeof(*t));
|
||||
u_free(t);
|
||||
}
|
||||
|
||||
void msg_transport_get_counters(struct msg_transport* t, struct msg_transport_counters* c) {
|
||||
if (t && c) memcpy(c, &t->counters, sizeof(*c));
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* TCP-клиенты: accept / read / close
|
||||
* ============================================================================ */
|
||||
|
||||
static void accept_callback(socket_t fd, void* arg) {
|
||||
struct msg_transport* t = (struct msg_transport*)arg;
|
||||
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t addr_len = sizeof(client_addr);
|
||||
|
||||
#ifdef _WIN32
|
||||
socket_t client_fd = accept(fd, (struct sockaddr*)&client_addr, &addr_len);
|
||||
if (client_fd == INVALID_SOCKET) {
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK)
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "accept() failed: %d", err);
|
||||
return;
|
||||
}
|
||||
u_long nonblock = 1;
|
||||
ioctlsocket(client_fd, FIONBIO, &nonblock);
|
||||
#else
|
||||
socket_t client_fd = accept(fd, (struct sockaddr*)&client_addr, &addr_len);
|
||||
if (client_fd < 0) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "accept() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
int flags = fcntl(client_fd, F_GETFL, 0);
|
||||
if (flags >= 0) fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
if (t->client_count >= t->max_clients) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "max_clients=%u reached, rejecting", t->max_clients);
|
||||
#ifdef _WIN32
|
||||
closesocket(client_fd);
|
||||
#else
|
||||
close(client_fd);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
struct msg_client* client = u_calloc(1, sizeof(*client));
|
||||
if (!client) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "u_calloc(msg_client) failed");
|
||||
#ifdef _WIN32
|
||||
closesocket(client_fd);
|
||||
#else
|
||||
close(client_fd);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
client->fd = client_fd;
|
||||
client->transport = t;
|
||||
|
||||
/* Определяем loopback */
|
||||
if (client_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&client_addr;
|
||||
client->is_localhost = (ntohl(sin->sin_addr.s_addr) == 0x7F000001u); /* 127.0.0.1 */
|
||||
} else if (client_addr.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&client_addr;
|
||||
static const uint8_t loopback_v6[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
|
||||
client->is_localhost = (memcmp(&sin6->sin6_addr, loopback_v6, 16) == 0);
|
||||
} else {
|
||||
client->is_localhost = 0;
|
||||
}
|
||||
|
||||
client->socket_id = uasync_add_socket_t(t->ua, client_fd,
|
||||
client_read_callback, NULL,
|
||||
client_except_callback, client);
|
||||
if (!client->socket_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "uasync_add_socket_t failed for client");
|
||||
u_free(client);
|
||||
#ifdef _WIN32
|
||||
closesocket(client_fd);
|
||||
#else
|
||||
close(client_fd);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
client->next = t->clients;
|
||||
t->clients = client;
|
||||
t->client_count++;
|
||||
t->counters.accepted++;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "msg_transport client connected (total=%u)", t->client_count);
|
||||
}
|
||||
|
||||
static void client_read_callback(socket_t fd, void* arg) {
|
||||
struct msg_client* client = (struct msg_client*)arg;
|
||||
struct msg_transport* t = client->transport;
|
||||
|
||||
uint8_t* buf = client->recv_buffer + client->recv_len;
|
||||
size_t buf_space = MSG_MAX_MSG_SIZE - client->recv_len;
|
||||
|
||||
#ifdef _WIN32
|
||||
int received = recv(fd, (char*)buf, (int)buf_space, 0);
|
||||
if (received == SOCKET_ERROR) {
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) {
|
||||
if (err == 10054) { close_client(t, client); return; }
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "recv() error: %d", err);
|
||||
close_client(t, client);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#else
|
||||
ssize_t received = recv(fd, buf, buf_space, 0);
|
||||
if (received < 0) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "recv() error: %s", strerror(errno));
|
||||
close_client(t, client);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (received == 0) {
|
||||
close_client(t, client);
|
||||
return;
|
||||
}
|
||||
|
||||
client->recv_len += (uint16_t)received;
|
||||
if (client->recv_len > MSG_MAX_MSG_SIZE) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "recv buffer overflow");
|
||||
close_client(t, client);
|
||||
return;
|
||||
}
|
||||
handle_client_data(t, client);
|
||||
}
|
||||
|
||||
static void client_except_callback(socket_t fd, void* arg) {
|
||||
struct msg_client* client = (struct msg_client*)arg;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "client socket exception");
|
||||
close_client(client->transport, client);
|
||||
(void)fd;
|
||||
}
|
||||
|
||||
static void close_client(struct msg_transport* t, struct msg_client* client) {
|
||||
if (!t || !client) return;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (client->fd != INVALID_SOCKET) {
|
||||
uasync_remove_socket_t(t->ua, client->fd);
|
||||
closesocket(client->fd);
|
||||
}
|
||||
#else
|
||||
if (client->fd >= 0) {
|
||||
uasync_remove_socket_t(t->ua, client->fd);
|
||||
close(client->fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct msg_client** curr = &t->clients;
|
||||
while (*curr) {
|
||||
if (*curr == client) { *curr = client->next; break; }
|
||||
curr = &(*curr)->next;
|
||||
}
|
||||
t->client_count--;
|
||||
t->counters.closed++;
|
||||
u_free(client);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "msg_transport client disconnected (total=%u)", t->client_count);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Обработка входящих сообщений от TCP-клиента
|
||||
* ============================================================================ */
|
||||
|
||||
static void handle_client_data(struct msg_transport* t, struct msg_client* client) {
|
||||
while (client->recv_len >= MSG_HDR_SIZE) {
|
||||
struct msg_header* hdr = (struct msg_header*)client->recv_buffer;
|
||||
|
||||
if (msg_validate_header(hdr) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "invalid header size=%u type=0x%02x", hdr->size, hdr->type);
|
||||
send_error(client, MSG_ERR_INVALID_MSG, "Invalid message header");
|
||||
close_client(t, client);
|
||||
return;
|
||||
}
|
||||
if (client->recv_len < hdr->size) break;
|
||||
|
||||
uint8_t* payload = client->recv_buffer + MSG_HDR_SIZE;
|
||||
uint16_t payload_size = hdr->size - MSG_HDR_SIZE;
|
||||
|
||||
switch (hdr->type) {
|
||||
|
||||
case MSG_CTL_BIND: {
|
||||
uint64_t peer_id = hdr->id;
|
||||
if (peer_id == 0) {
|
||||
send_error(client, MSG_ERR_INVALID_MSG, "BIND with zero peer_id");
|
||||
break;
|
||||
}
|
||||
/* Проверить конфликт: этот peer_id уже занят другим клиентом */
|
||||
struct msg_client* other = t->clients;
|
||||
while (other) {
|
||||
if (other != client && other->bound_peer_id == peer_id) {
|
||||
send_error(client, MSG_ERR_ID_TAKEN, "peer_id already bound by another client");
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "BIND peer=%016llx rejected: already bound",
|
||||
(unsigned long long)peer_id);
|
||||
break;
|
||||
}
|
||||
other = other->next;
|
||||
}
|
||||
if (other) break; /* конфликт */
|
||||
client->bound_peer_id = peer_id;
|
||||
send_response(client, MSG_RSP_BIND_OK, peer_id, NULL, 0);
|
||||
t->counters.bind_count++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "BIND peer=%016llx", (unsigned long long)peer_id);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_CTL_UNBIND:
|
||||
client->bound_peer_id = 0;
|
||||
t->counters.unbind_count++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "UNBIND");
|
||||
break;
|
||||
|
||||
case MSG_CTL_GET_PUBKEY:
|
||||
send_response(client, MSG_RSP_PUBKEY, 0,
|
||||
t->instance->my_keys.public_key, SC_PUBKEY_SIZE);
|
||||
break;
|
||||
|
||||
case MSG_CTL_GET_PRIVKEY:
|
||||
if (!client->is_localhost) {
|
||||
send_error(client, MSG_ERR_ACCESS_DENIED, "private key only available from localhost");
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "GET_PRIVKEY denied: not localhost");
|
||||
break;
|
||||
}
|
||||
send_response(client, MSG_RSP_PRIVKEY, 0,
|
||||
t->instance->my_keys.private_key, SC_PRIVKEY_SIZE);
|
||||
break;
|
||||
|
||||
case MSG_CTL_GET_PEER_INFO: {
|
||||
uint64_t peer_id = hdr->id;
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(t->instance->topo_groups);
|
||||
if (!group) {
|
||||
send_error(client, MSG_ERR_PEER_NOT_FOUND, "BGP not initialized");
|
||||
break;
|
||||
}
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, peer_id);
|
||||
if (!nq) {
|
||||
send_error(client, MSG_ERR_PEER_NOT_FOUND, "peer not found");
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "GET_PEER_INFO: peer=%016llx not found",
|
||||
(unsigned long long)peer_id);
|
||||
break;
|
||||
}
|
||||
uint8_t buf[SC_PUBKEY_SIZE * 2];
|
||||
memcpy(buf, nq->node->public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(buf + SC_PUBKEY_SIZE, nq->node->ed25519_public_key, SC_PUBKEY_SIZE);
|
||||
send_response(client, MSG_RSP_PEER_INFO, peer_id, buf, SC_PUBKEY_SIZE * 2);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MSGTRANSPORT, "GET_PEER_INFO: peer=%016llx sent pubkey+edpub",
|
||||
(unsigned long long)peer_id);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_DATA_SEND: {
|
||||
uint64_t dst = hdr->id ? hdr->id : client->bound_peer_id;
|
||||
if (dst == 0) {
|
||||
send_error(client, MSG_ERR_NOT_BOUND, "Not bound to any peer");
|
||||
break;
|
||||
}
|
||||
if (payload_size == 0) break;
|
||||
int is_signed = (hdr->options & MSG_OPT_SIGNED) ? 1 : 0;
|
||||
if (forward_to_peer(t, dst, payload, payload_size, is_signed) != 0) {
|
||||
send_error(client, MSG_ERR_SEND_FAILED, "Failed to forward message to peer");
|
||||
t->counters.drops_no_route++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "unknown message type 0x%02x from client", hdr->type);
|
||||
send_error(client, MSG_ERR_INVALID_MSG, "Unknown message type");
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t msg_size = hdr->size;
|
||||
if (client->recv_len > msg_size)
|
||||
memmove(client->recv_buffer, client->recv_buffer + msg_size, client->recv_len - msg_size);
|
||||
client->recv_len -= msg_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Отправка пиру через etcp_router
|
||||
* ============================================================================ */
|
||||
|
||||
static int forward_to_peer(struct msg_transport* t, uint64_t dst_peer_id,
|
||||
const uint8_t* data, size_t data_len, int is_signed) {
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(t->instance, dst_peer_id, t->svc_id);
|
||||
if (!rconn) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "forward_to_peer: no route to %016llx", (unsigned long long)dst_peer_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (is_signed) {
|
||||
ret = etcp_router_conn_send_signed(rconn, data, data_len);
|
||||
} else {
|
||||
ret = etcp_router_conn_send(rconn, data, data_len);
|
||||
}
|
||||
if (ret != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "forward_to_peer: send failed to %016llx (signed=%d)",
|
||||
(unsigned long long)dst_peer_id, is_signed);
|
||||
return -1;
|
||||
}
|
||||
t->counters.msg_sent_to_peer++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Приём от пира через etcp_router → доставка TCP-клиенту
|
||||
* ============================================================================ */
|
||||
|
||||
static void on_etcp_recv(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
if (!conn || !entry) return;
|
||||
struct UTUN_INSTANCE* inst = conn->instance;
|
||||
if (!inst) { queue_dgram_free(entry); queue_entry_free(entry); return; }
|
||||
|
||||
struct msg_transport* t = inst->msg_t;
|
||||
if (!t) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "msg_transport not initialized on instance");
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
|
||||
uint8_t* payload = entry->dgram + 1;
|
||||
size_t payload_len = entry->len - 1;
|
||||
uint64_t src_node_id = conn->peer_node_id;
|
||||
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_MSGTRANSPORT, "from %016llx len=%zu",
|
||||
(unsigned long long)src_node_id, payload_len);
|
||||
|
||||
/* Ищем клиента привязанного к этому пиру */
|
||||
struct msg_client* client = t->clients;
|
||||
while (client) {
|
||||
if (client->bound_peer_id == src_node_id) break;
|
||||
client = client->next;
|
||||
}
|
||||
|
||||
if (!client) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MSGTRANSPORT, "no client bound to %016llx, dropping",
|
||||
(unsigned long long)src_node_id);
|
||||
t->counters.drops_no_client++;
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
t->counters.msg_recv_from_peer++;
|
||||
|
||||
/* Формируем MSG_DATA_RECV */
|
||||
size_t total = MSG_HDR_SIZE + payload_len;
|
||||
uint8_t* buf = u_malloc(total);
|
||||
if (!buf) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MSGTRANSPORT, "u_malloc failed");
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
struct msg_header* hdr = (struct msg_header*)buf;
|
||||
msg_build_header(hdr, (uint16_t)payload_len, MSG_DATA_RECV, src_node_id, 0);
|
||||
memcpy(buf + MSG_HDR_SIZE, payload, payload_len);
|
||||
|
||||
#ifdef _WIN32
|
||||
send(client->fd, (const char*)buf, (int)total, 0);
|
||||
#else
|
||||
send(client->fd, buf, total, 0);
|
||||
#endif
|
||||
u_free(buf);
|
||||
t->counters.msg_sent_to_client++;
|
||||
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Помощники отправки ответов TCP-клиенту
|
||||
* ============================================================================ */
|
||||
|
||||
static void send_response(struct msg_client* client, uint8_t type, uint64_t id,
|
||||
const uint8_t* data, size_t data_len) {
|
||||
size_t total = MSG_HDR_SIZE + data_len;
|
||||
uint8_t* buf = u_malloc(total);
|
||||
if (!buf) return;
|
||||
|
||||
struct msg_header* hdr = (struct msg_header*)buf;
|
||||
msg_build_header(hdr, (uint16_t)data_len, type, id, 0);
|
||||
if (data_len > 0) memcpy(buf + MSG_HDR_SIZE, data, data_len);
|
||||
|
||||
#ifdef _WIN32
|
||||
send(client->fd, (const char*)buf, (int)total, 0);
|
||||
#else
|
||||
send(client->fd, buf, total, 0);
|
||||
#endif
|
||||
u_free(buf);
|
||||
}
|
||||
|
||||
static void send_error(struct msg_client* client, uint8_t error_code, const char* msg) {
|
||||
size_t msg_len = strlen(msg);
|
||||
size_t total = MSG_HDR_SIZE + 1 + msg_len;
|
||||
uint8_t* buf = u_malloc(total);
|
||||
if (!buf) return;
|
||||
|
||||
struct msg_header* hdr = (struct msg_header*)buf;
|
||||
msg_build_header(hdr, (uint16_t)(1 + msg_len), MSG_RSP_ERROR, 0, 0);
|
||||
buf[MSG_HDR_SIZE] = error_code;
|
||||
memcpy(buf + MSG_HDR_SIZE + 1, msg, msg_len);
|
||||
|
||||
#ifdef _WIN32
|
||||
send(client->fd, (const char*)buf, (int)total, 0);
|
||||
#else
|
||||
send(client->fd, buf, total, 0);
|
||||
#endif
|
||||
u_free(buf);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* msg_transport.h — TCP-сервер транспорта сообщений (local IPC → ETCP)
|
||||
*
|
||||
* Принимает TCP-соединения от локальных приложений.
|
||||
* Каждое соединение привязывается (BIND) к конкретному remote peer node_id.
|
||||
* Сообщения от локального клиента пересылаются пиру через etcp_router,
|
||||
* сообщения от пира доставляются локальному клиенту.
|
||||
*
|
||||
* Формат фрейма на TCP:
|
||||
* [size:2 (uint16_t, native endian)] [type:1] [id:8 (uint64_t)] [options:1] [data...]
|
||||
* size включает само поле size.
|
||||
*/
|
||||
|
||||
#ifndef MSG_TRANSPORT_H
|
||||
#define MSG_TRANSPORT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../lib/socket_compat.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================
|
||||
* Протокол
|
||||
* ============================================================================ */
|
||||
|
||||
#define MSG_MAX_MSG_SIZE 8192
|
||||
#define MSG_SIGN_SIZE 64 /* Ed25519 */
|
||||
|
||||
/* Options byte bits */
|
||||
#define MSG_OPT_SIGNED 0x01
|
||||
|
||||
/* Типы сообщений */
|
||||
#define MSG_CTL_BIND 0x01 /* GUI→utun: привязать TCP-соединение к пиру id */
|
||||
#define MSG_CTL_UNBIND 0x02 /* GUI→utun: отвязать */
|
||||
#define MSG_CTL_GET_PUBKEY 0x03 /* GUI→utun: запросить публичный ключ */
|
||||
#define MSG_CTL_GET_PRIVKEY 0x04 /* GUI→utun: запросить приватный ключ (только localhost) */
|
||||
#define MSG_CTL_GET_PEER_INFO 0x05 /* GUI→utun: запросить ключи пира id (pubkey + ed25519_pubkey) */
|
||||
#define MSG_DATA_SEND 0x10 /* GUI→utun: отправить сообщение пиру id */
|
||||
#define MSG_DATA_RECV 0x11 /* utun→GUI: получено сообщение от пира id */
|
||||
#define MSG_RSP_BIND_OK 0xE1 /* utun→GUI: BIND успешен */
|
||||
#define MSG_RSP_PUBKEY 0xE2 /* utun→GUI: публичный ключ (32 байта) */
|
||||
#define MSG_RSP_PRIVKEY 0xE3 /* utun→GUI: приватный ключ (32 байта) */
|
||||
#define MSG_RSP_PEER_INFO 0xE4 /* utun→GUI: ключи пира (pubkey+edpub=64 байта) */
|
||||
#define MSG_RSP_ERROR 0xFF /* utun→GUI: ошибка */
|
||||
|
||||
/* Коды ошибок для MSG_RSP_ERROR */
|
||||
#define MSG_ERR_INVALID_MSG 0x01
|
||||
#define MSG_ERR_NOT_BOUND 0x02
|
||||
#define MSG_ERR_NO_ROUTE 0x03
|
||||
#define MSG_ERR_SEND_FAILED 0x04
|
||||
#define MSG_ERR_ACCESS_DENIED 0x07
|
||||
#define MSG_ERR_PEER_NOT_FOUND 0x08
|
||||
#define MSG_ERR_ID_TAKEN 0x06
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct msg_header {
|
||||
uint16_t size; /* полный размер сообщения, включая это поле */
|
||||
uint8_t type; /* тип (MSG_CTL_* / MSG_DATA_* / MSG_RSP_*) */
|
||||
uint64_t id; /* peer node_id */
|
||||
uint8_t options; /* битовые флаги (MSG_OPT_*) */
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#define MSG_HDR_SIZE sizeof(struct msg_header) /* 12 */
|
||||
|
||||
static inline void msg_build_header(struct msg_header* hdr,
|
||||
uint16_t payload_size,
|
||||
uint8_t msg_type,
|
||||
uint64_t id,
|
||||
uint8_t options) {
|
||||
hdr->size = MSG_HDR_SIZE + payload_size;
|
||||
hdr->type = msg_type;
|
||||
hdr->id = id;
|
||||
hdr->options = options;
|
||||
}
|
||||
|
||||
static inline int msg_validate_header(const struct msg_header* hdr) {
|
||||
if (hdr->size < MSG_HDR_SIZE || hdr->size > MSG_MAX_MSG_SIZE) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Счётчики (диагностика)
|
||||
* ============================================================================ */
|
||||
|
||||
struct UTUN_INSTANCE;
|
||||
struct UASYNC;
|
||||
|
||||
struct msg_transport;
|
||||
|
||||
struct msg_transport_counters {
|
||||
uint64_t accepted;
|
||||
uint64_t closed;
|
||||
uint64_t bind_count;
|
||||
uint64_t unbind_count;
|
||||
uint64_t msg_sent_to_peer;
|
||||
uint64_t msg_recv_from_peer;
|
||||
uint64_t msg_sent_to_client;
|
||||
uint64_t errors;
|
||||
uint64_t drops_no_client;
|
||||
uint64_t drops_no_route;
|
||||
};
|
||||
|
||||
/* ============================================================================
|
||||
* API
|
||||
* ============================================================================ */
|
||||
|
||||
int msg_transport_init(struct msg_transport** out,
|
||||
struct UTUN_INSTANCE* instance,
|
||||
struct UASYNC* ua,
|
||||
struct sockaddr_storage* bind_addr,
|
||||
uint32_t max_clients,
|
||||
uint8_t svc_id);
|
||||
|
||||
void msg_transport_shutdown(struct msg_transport* t);
|
||||
|
||||
void msg_transport_get_counters(struct msg_transport* t,
|
||||
struct msg_transport_counters* c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MSG_TRANSPORT_H */
|
||||
@@ -1,69 +0,0 @@
|
||||
# Msg Transport (msg_transport)
|
||||
|
||||
## 1. Назначение
|
||||
TCP-сервер для обмена сообщениями между локальными приложениями (например, chatgui) и удалёнными пирами через ETCP. Принимает TCP-соединения от локальных клиентов, привязывает (BIND) их к конкретному `peer_node_id` и пересылает данные туда-обратно через `etcp_router`. Поддерживает подписанные сообщения (Ed25519).
|
||||
|
||||
## 2. Как пользоваться
|
||||
1. Вызвать `msg_transport_init()` — создаёт слушающий TCP-сокет, регистрирует callback `on_etcp_recv` в `etcp_router_bind()`.
|
||||
2. Локальное приложение (chatgui) подключается по TCP и шлёт фреймы протокола.
|
||||
3. При остановке вызвать `msg_transport_shutdown()`.
|
||||
|
||||
**Протокол фрейма:**
|
||||
```
|
||||
[size:2][type:1][id:8][options:1][data...]
|
||||
```
|
||||
- `size` — полный размер (включая поле size), native endian, до 8192 байт.
|
||||
- `type` — команда (`MSG_CTL_*`, `MSG_DATA_*`, `MSG_RSP_*`).
|
||||
- `id` — `peer_node_id` (uint64_t).
|
||||
- `options` — битовые флаги (`MSG_OPT_SIGNED = 0x01`).
|
||||
|
||||
**Нюансы:**
|
||||
- Приватный ключ (`GET_PRIVKEY`) отдаётся только подключениям с loopback (127.0.0.1 / ::1).
|
||||
- Каждый `peer_id` может быть забинден только одним клиентом одновременно.
|
||||
- Сообщения от пира без привязанного клиента молча дропаются (счётчик `drops_no_client`).
|
||||
|
||||
## 3. API
|
||||
|
||||
### Структуры
|
||||
|
||||
| Структура | Назначение |
|
||||
|-----------|-----------|
|
||||
| `struct msg_transport` | Состояние сервера: `listen_fd`, связный список `clients`, `svc_id`, счётчики. |
|
||||
| `struct msg_client` | Состояние TCP-клиента: `fd`, буфер приёма, `bound_peer_id`, флаг `is_localhost`. |
|
||||
| `struct msg_header` | Заголовок фрейма: `size`, `type`, `id`, `options` (12 байт, packed). |
|
||||
| `struct msg_transport_counters` | Счётчики: accepted, closed, bind/unbind, msg_sent/recv, errors, drops. |
|
||||
|
||||
### Функции
|
||||
|
||||
| Функция | Назначение |
|
||||
|---------|-----------|
|
||||
| `msg_transport_init(out, instance, ua, bind_addr, max_clients, svc_id)` | Создать сервер, привязаться к порту, зарегистрировать `svc_id` в `etcp_router_bind`. |
|
||||
| `msg_transport_shutdown(t)` | Закрыть всех клиентов, освободить сокет. |
|
||||
| `msg_transport_get_counters(t, c)` | Скопировать счётчики в переданную структуру. |
|
||||
| `msg_build_header(hdr, payload_size, msg_type, id, options)` | Заполнить заголовок фрейма (inline). |
|
||||
| `msg_validate_header(hdr)` | Проверить корректность заголовка (inline). |
|
||||
|
||||
### Типы сообщений
|
||||
|
||||
| Тип | Направление | Описание |
|
||||
|-----|-------------|----------|
|
||||
| `MSG_CTL_BIND` (0x01) | GUI→utun | Привязать TCP-соединение к пиру `id`. Ответ: `RSP_BIND_OK`. |
|
||||
| `MSG_CTL_UNBIND` (0x02) | GUI→utun | Отвязать соединение. |
|
||||
| `MSG_CTL_GET_PUBKEY` (0x03) | GUI→utun | Запросить свой публичный ключ. Ответ: `RSP_PUBKEY` (32 байта). |
|
||||
| `MSG_CTL_GET_PRIVKEY` (0x04) | GUI→utun | Запросить приватный ключ (только localhost). Ответ: `RSP_PRIVKEY` (32 байта). |
|
||||
| `MSG_CTL_GET_PEER_INFO` (0x05) | GUI→utun | Запросить ключи пира `id`. Ответ: `RSP_PEER_INFO` (pubkey + ed25519_pubkey = 64 байта). |
|
||||
| `MSG_DATA_SEND` (0x10) | GUI→utun | Отправить данные пиру `id` (через `etcp_router_conn_send` / `send_signed`). |
|
||||
| `MSG_DATA_RECV` (0x11) | utun→GUI | Получены данные от пира `id`. |
|
||||
| `MSG_RSP_ERROR` (0xFF) | utun→GUI | Ошибка (1 байт код + текст). |
|
||||
|
||||
### Коды ошибок
|
||||
|
||||
| Код | Константа | Описание |
|
||||
|-----|-----------|----------|
|
||||
| 0x01 | `MSG_ERR_INVALID_MSG` | Некорректный заголовок или тип. |
|
||||
| 0x02 | `MSG_ERR_NOT_BOUND` | Нет привязки к пиру. |
|
||||
| 0x03 | `MSG_ERR_NO_ROUTE` | Нет маршрута до пира. |
|
||||
| 0x04 | `MSG_ERR_SEND_FAILED` | Ошибка отправки. |
|
||||
| 0x06 | `MSG_ERR_ID_TAKEN` | `peer_id` уже занят другим клиентом. |
|
||||
| 0x07 | `MSG_ERR_ACCESS_DENIED` | Доступ запрещён (например, `GET_PRIVKEY` не с loopback). |
|
||||
| 0x08 | `MSG_ERR_PEER_NOT_FOUND` | Пир не найден в BGP-топологии. |
|
||||
+3
-2
@@ -6,6 +6,7 @@
|
||||
#include "tun_if.h"
|
||||
#include "etcp_api.h"
|
||||
#include "etcp_router.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -47,7 +48,7 @@ static void nat_transport_client_tun_out_cb(struct ll_queue* q, void* arg) {
|
||||
queue_dgram_free(pkt); queue_entry_free(pkt);
|
||||
queue_resume_callback(q);
|
||||
|
||||
int ret = etcp_route_send(inst, tr->nat_via_node_id, new_entry, 0);
|
||||
int ret = etcp_route_send(inst, TOPO_GROUP_UTUN, tr->nat_via_node_id, new_entry, 0);
|
||||
if (ret != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT client: etcp_route_send to provider %016llx failed",
|
||||
(unsigned long long)tr->nat_via_node_id);
|
||||
@@ -90,7 +91,7 @@ static void nat_transport_provider_tun_out_cb(struct ll_queue* q, void* arg) {
|
||||
queue_dgram_free(pkt); queue_entry_free(pkt);
|
||||
queue_resume_callback(q);
|
||||
|
||||
int send_ret = etcp_route_send(inst, entry->src_node_id, new_entry, 0);
|
||||
int send_ret = etcp_route_send(inst, TOPO_GROUP_UTUN, entry->src_node_id, new_entry, 0);
|
||||
if (send_ret != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT provider: etcp_route_send back to node %016llx failed",
|
||||
(unsigned long long)entry->src_node_id);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "etcp_router.h"
|
||||
#include "utun_instance.h"
|
||||
#include "tun_if.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -143,7 +144,7 @@ static void raw_read_cb(socket_t sock, void* arg) {
|
||||
memcpy(e->dgram + 20, &icmp_hdr->icmp_seq, 2);
|
||||
if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len);
|
||||
e->len = ICMP_PROXY_HDR_SIZE + payload_len;
|
||||
int ret = etcp_route_send(g_icmp_ctx->inst, r->client_node_id, e, 0);
|
||||
int ret = etcp_route_send(g_icmp_ctx->inst, TOPO_GROUP_UTUN, r->client_node_id, e, 0);
|
||||
if (ret != 0) DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "icmp_proxy: etcp_route_send reply failed: %d", ret);
|
||||
else DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "icmp_proxy: reply forwarded to client %016llx", (unsigned long long)r->client_node_id);
|
||||
u_free(r);
|
||||
@@ -181,7 +182,7 @@ static void exit_handle_request(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
memcpy(e->dgram + 20, &echo_seq, 2);
|
||||
if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len);
|
||||
e->len = ICMP_PROXY_HDR_SIZE + payload_len;
|
||||
etcp_route_send(inst, client_node_id, e, 0);
|
||||
etcp_route_send(inst, TOPO_GROUP_UTUN, client_node_id, e, 0);
|
||||
} else queue_entry_free(e);
|
||||
}
|
||||
} else {
|
||||
@@ -246,7 +247,7 @@ int icmp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id,
|
||||
memcpy(e->dgram + 20, &echo_seq, 2);
|
||||
if (payload_len > 0) memcpy(e->dgram + ICMP_PROXY_HDR_SIZE, payload, payload_len);
|
||||
e->len = ICMP_PROXY_HDR_SIZE + payload_len;
|
||||
return etcp_route_send(inst, exit_node_id, e, 0);
|
||||
return etcp_route_send(inst, TOPO_GROUP_UTUN, exit_node_id, e, 0);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
+16
-15
@@ -5,6 +5,7 @@
|
||||
#include "etcp_api.h"
|
||||
#include "etcp_router.h"
|
||||
#include "utun_instance.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -29,7 +30,7 @@ static void on_error_cb(struct tcp_conn* tc, int err, void* arg);
|
||||
static void on_closed_cb(struct tcp_conn* tc, void* arg);
|
||||
static void tx_waiter_cb(struct ll_queue* q, void* arg);
|
||||
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd, uint32_t sid, const uint8_t* data, size_t len, int force);
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t subcmd, uint32_t sid, const uint8_t* data, size_t len, int force);
|
||||
|
||||
struct listen_ctx {
|
||||
socket_t listen_sock;
|
||||
@@ -46,7 +47,7 @@ struct listen_ctx {
|
||||
// ====================================================================
|
||||
// Отправка сообщений через ETCP
|
||||
// ====================================================================
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd, uint32_t sid, const uint8_t* data, size_t len, int force) {
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t subcmd, uint32_t sid, const uint8_t* data, size_t len, int force) {
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socks_proxy: queue_entry_new failed subcmd=%02x sid=%08x", subcmd, sid); return -1; }
|
||||
e->dgram = u_malloc(TCP_PROXY_HDR_SIZE + len);
|
||||
@@ -60,7 +61,7 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd, ui
|
||||
queue_dgram_free(e); queue_entry_free(e); return -1;
|
||||
}
|
||||
e->len = (uint16_t)(TCP_PROXY_HDR_SIZE + len);
|
||||
int ret = etcp_route_send(inst, dst, e, force);
|
||||
int ret = etcp_route_send(inst, group_id, dst, e, force);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "SOCKS send_msg subcmd=%02x sid=%08x len=%zu force=%d → ret=%d",
|
||||
subcmd, sid, len, force, ret);
|
||||
return ret;
|
||||
@@ -72,28 +73,28 @@ static int send_connect(struct socks_proxy_conn* c) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "SOCKS proxy: CONNECT sid=%08x to %d.%d.%d.%d:%d via_node=%016llx %s",
|
||||
c->stream_id, c->dest_ip[0], c->dest_ip[1], c->dest_ip[2], c->dest_ip[3],
|
||||
ntohs(c->dest_port), (unsigned long long)c->via_node_id, c->is_http ? "http" : "socks");
|
||||
return send_msg(c->inst, c->via_node_id, TCP_PROXY_SUBCMD_CONNECT, c->stream_id, buf, 6, 1);
|
||||
return send_msg(c->inst, TOPO_GROUP_UTUN, c->via_node_id, TCP_PROXY_SUBCMD_CONNECT, c->stream_id, buf, 6, 1);
|
||||
}
|
||||
|
||||
static int send_data(struct socks_proxy_conn* c, const uint8_t* data, uint16_t len) {
|
||||
return send_msg(c->inst, c->via_node_id, TCP_PROXY_SUBCMD_DATA, c->stream_id, data, len, 0);
|
||||
return send_msg(c->inst, TOPO_GROUP_UTUN, c->via_node_id, TCP_PROXY_SUBCMD_DATA, c->stream_id, data, len, 0);
|
||||
}
|
||||
|
||||
static void send_close(struct socks_proxy_conn* c) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "SOCKS send CLOSE sid=%08x", c->stream_id);
|
||||
if (send_msg(c->inst, c->via_node_id, TCP_PROXY_SUBCMD_CLOSE, c->stream_id, NULL, 0, 1) < 0) c->close_pending = 1;
|
||||
if (send_msg(c->inst, TOPO_GROUP_UTUN, c->via_node_id, TCP_PROXY_SUBCMD_CLOSE, c->stream_id, NULL, 0, 1) < 0) c->close_pending = 1;
|
||||
else { c->close_pending = 0; c->close_sent = 1; }
|
||||
}
|
||||
|
||||
static void send_error(struct socks_proxy_conn* c) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "SOCKS send ERROR sid=%08x", c->stream_id);
|
||||
if (send_msg(c->inst, c->via_node_id, TCP_PROXY_SUBCMD_ERROR, c->stream_id, NULL, 0, 1) < 0) c->close_pending = 1;
|
||||
if (send_msg(c->inst, TOPO_GROUP_UTUN, c->via_node_id, TCP_PROXY_SUBCMD_ERROR, c->stream_id, NULL, 0, 1) < 0) c->close_pending = 1;
|
||||
else { c->close_pending = 0; c->close_sent = 1; }
|
||||
}
|
||||
|
||||
static void send_fin(struct socks_proxy_conn* c) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "SOCKS send FIN sid=%08x", c->stream_id);
|
||||
send_msg(c->inst, c->via_node_id, TCP_PROXY_SUBCMD_FIN, c->stream_id, NULL, 0, 1);
|
||||
send_msg(c->inst, TOPO_GROUP_UTUN, c->via_node_id, TCP_PROXY_SUBCMD_FIN, c->stream_id, NULL, 0, 1);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
@@ -331,7 +332,7 @@ static void process_http_request(struct socks_proxy_conn* c) {
|
||||
u_free(pkt);
|
||||
} else {
|
||||
c->tx_buf = pkt; c->tx_len = total;
|
||||
etcp_router_on_send_ready(c->inst, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter, tx_waiter_cb, c);
|
||||
etcp_router_on_send_ready(c->inst, TOPO_GROUP_UTUN, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter, tx_waiter_cb, c);
|
||||
}
|
||||
|
||||
c->buf_len = 0;
|
||||
@@ -395,7 +396,7 @@ static void on_read_cb(struct ll_queue* q, void* arg) {
|
||||
if (c->tx_buf) { memcpy(c->tx_buf, e->dgram, e->len); c->tx_len = e->len; }
|
||||
else { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socks_proxy: tx_buf malloc=%u failed sid=%08x — drop", e->len, c->stream_id); }
|
||||
memory_pool_free(c->tc->data_pool, e->dgram); queue_entry_free(e);
|
||||
etcp_router_on_send_ready(c->inst, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter, tx_waiter_cb, c);
|
||||
etcp_router_on_send_ready(c->inst, TOPO_GROUP_UTUN, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter, tx_waiter_cb, c);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SOCKS PROXY BP: sid=%08x tx_buf=%u waiter_reg", c->stream_id, c->tx_len);
|
||||
}
|
||||
}
|
||||
@@ -410,7 +411,7 @@ static void tx_waiter_cb(struct ll_queue* q, void* arg) {
|
||||
u_free(c->tx_buf); c->tx_buf = NULL; c->tx_len = 0;
|
||||
queue_resume_callback(c->tc->read_queue);
|
||||
} else {
|
||||
etcp_router_on_send_ready(c->inst, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter, tx_waiter_cb, c);
|
||||
etcp_router_on_send_ready(c->inst, TOPO_GROUP_UTUN, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter, tx_waiter_cb, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +525,7 @@ int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count,
|
||||
if (subcmd == TCP_PROXY_SUBCMD_CLOSE) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "socks_proxy: REM_CLOSED sid=%08x", stream_id);
|
||||
c->rem_closed = 1;
|
||||
etcp_router_cancel_send_ready(c->inst, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter);
|
||||
etcp_router_cancel_send_ready(c->inst, TOPO_GROUP_UTUN, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter);
|
||||
tcp_conn_push_close(c->tc);
|
||||
return 1;
|
||||
}
|
||||
@@ -532,7 +533,7 @@ int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count,
|
||||
if (subcmd == TCP_PROXY_SUBCMD_ERROR) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "socks_proxy: ERROR from exit sid=%08x", stream_id);
|
||||
c->rem_closed = 1;
|
||||
etcp_router_cancel_send_ready(c->inst, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter);
|
||||
etcp_router_cancel_send_ready(c->inst, TOPO_GROUP_UTUN, c->via_node_id, ETCP_RT_ID_TCP_PROXY, &c->tx_waiter);
|
||||
tcp_conn_push_close(c->tc);
|
||||
return 1;
|
||||
}
|
||||
@@ -557,12 +558,12 @@ void socks_proxy_conn_free(struct socks_proxy_conn* c) {
|
||||
if (c->close_pending && c->inst) {
|
||||
c->close_pending = 0;
|
||||
uint8_t subcmd = c->tc && c->tc->error ? TCP_PROXY_SUBCMD_ERROR : TCP_PROXY_SUBCMD_CLOSE;
|
||||
send_msg(c->inst, c->via_node_id, subcmd, c->stream_id, NULL, 0, 1);
|
||||
send_msg(c->inst, TOPO_GROUP_UTUN, c->via_node_id, subcmd, c->stream_id, NULL, 0, 1);
|
||||
}
|
||||
if (head) { struct socks_proxy_conn** prev = head; while (*prev) { if (*prev == c) { *prev = c->next; if (count) (*count)--; break; } prev = &(*prev)->next; } }
|
||||
if (c->tx_buf) { u_free(c->tx_buf); c->tx_buf = NULL; c->tx_len = 0; }
|
||||
if (c->tc) { tcp_conn_destroy(c->tc); c->tc = NULL; }
|
||||
if (c->inst) etcp_router_waiter_cancel(c->inst, c->via_node_id, &c->tx_waiter);
|
||||
if (c->inst) etcp_router_waiter_cancel(c->inst, TOPO_GROUP_UTUN, c->via_node_id, &c->tx_waiter);
|
||||
u_free(c);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "utun_instance.h"
|
||||
#include "etcp.h"
|
||||
#include "etcp_api.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
#include "etcp_router.h"
|
||||
#include "tcp_proxy_server.h"
|
||||
#include "udp_proxy.h"
|
||||
@@ -42,7 +43,7 @@ static err_t tcp_proxy_client_output_cb(void *arg, struct pbuf *p, uint32_t src_
|
||||
static void tcp_proxy_client_feed_from_transport(struct tcp_proxy_client_conn *pc);
|
||||
static struct ll_entry* tcp_proxy_client_entry_from_data(struct memory_pool* pool, const uint8_t* data, uint16_t len);
|
||||
static void tcp_proxy_client_conn_free(struct tcp_proxy_client_conn *pc);
|
||||
static int tcp_proxy_client_send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd, uint32_t sid, const uint8_t* data, size_t len, int force);
|
||||
static int tcp_proxy_client_send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t subcmd, uint32_t sid, const uint8_t* data, size_t len, int force);
|
||||
static int tcp_proxy_client_send_data(struct tcp_proxy_client_conn* pc, const uint8_t* data, uint16_t len);
|
||||
static void tcp_proxy_client_tx_waiter_cb(struct ll_queue* q, void* arg);
|
||||
|
||||
@@ -64,7 +65,7 @@ static struct ll_entry* tcp_proxy_client_entry_from_data(struct memory_pool* poo
|
||||
// ====================================================================
|
||||
// Протокол: сборка и отправка сообщений прокси через ETCP
|
||||
// ====================================================================
|
||||
static int tcp_proxy_client_send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd,
|
||||
static int tcp_proxy_client_send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t subcmd,
|
||||
uint32_t sid, const uint8_t* data, size_t len, int force) {
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "queue_entry_new failed subcmd=%02x sid=%08x", subcmd, sid); return -1; }
|
||||
@@ -75,7 +76,7 @@ static int tcp_proxy_client_send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, u
|
||||
memcpy(e->dgram + 2, &sid, 4);
|
||||
if (len > 0) memcpy(e->dgram + TCP_PROXY_HDR_SIZE, data, len);
|
||||
e->len = TCP_PROXY_HDR_SIZE + len;
|
||||
return etcp_route_send(inst, dst, e, force);
|
||||
return etcp_route_send(inst, group_id, dst, e, force);
|
||||
}
|
||||
|
||||
static int tcp_proxy_client_send_connect(struct tcp_proxy_client_conn* pc) {
|
||||
@@ -84,19 +85,19 @@ static int tcp_proxy_client_send_connect(struct tcp_proxy_client_conn* pc) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "TCP proxy client: CONNECT sid=%08x to %d.%d.%d.%d:%d via node %016llx",
|
||||
pc->stream_id, pc->dest_ip[0], pc->dest_ip[1], pc->dest_ip[2], pc->dest_ip[3],
|
||||
ntohs(pc->dest_port), (unsigned long long)pc->proxy->via_node_id);
|
||||
return tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
|
||||
return tcp_proxy_client_send_msg(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id,
|
||||
TCP_PROXY_SUBCMD_CONNECT, pc->stream_id, buf, 6, 1);
|
||||
}
|
||||
|
||||
static int tcp_proxy_client_send_data(struct tcp_proxy_client_conn* pc, const uint8_t* data, uint16_t len) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "PROXY SEND sid=%08x len=%u", pc->stream_id, len);
|
||||
return tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
|
||||
return tcp_proxy_client_send_msg(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id,
|
||||
TCP_PROXY_SUBCMD_DATA, pc->stream_id, data, len, 0);
|
||||
}
|
||||
|
||||
static int tcp_proxy_client_send_close(struct tcp_proxy_client_conn* pc) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "PROXY SEND sid=%08x", pc->stream_id);
|
||||
int ret = tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
|
||||
int ret = tcp_proxy_client_send_msg(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id,
|
||||
TCP_PROXY_SUBCMD_CLOSE, pc->stream_id, NULL, 0, 1);
|
||||
if (ret < 0) { pc->close_pending = 1; return -1; }
|
||||
pc->close_pending = 0;
|
||||
@@ -105,7 +106,7 @@ static int tcp_proxy_client_send_close(struct tcp_proxy_client_conn* pc) {
|
||||
}
|
||||
|
||||
static int tcp_proxy_client_send_error(struct tcp_proxy_client_conn* pc) {
|
||||
int ret = tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
|
||||
int ret = tcp_proxy_client_send_msg(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id,
|
||||
TCP_PROXY_SUBCMD_ERROR, pc->stream_id, NULL, 0, 1);
|
||||
if (ret < 0) { pc->close_pending = 1; return -1; }
|
||||
pc->close_pending = 0;
|
||||
@@ -115,7 +116,7 @@ static int tcp_proxy_client_send_error(struct tcp_proxy_client_conn* pc) {
|
||||
|
||||
static int tcp_proxy_client_send_fin(struct tcp_proxy_client_conn* pc) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TRAFFIC, "PROXY FIN RELAY sid=%08x", pc->stream_id);
|
||||
return tcp_proxy_client_send_msg(pc->proxy->inst, pc->proxy->via_node_id,
|
||||
return tcp_proxy_client_send_msg(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id,
|
||||
TCP_PROXY_SUBCMD_FIN, pc->stream_id, NULL, 0, 1);
|
||||
}
|
||||
|
||||
@@ -306,7 +307,7 @@ static err_t tcp_proxy_client_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbu
|
||||
if (ret == 0) { tcp_recved(pcb, len); u_free(data); }
|
||||
else {
|
||||
pc->tx_buf = data; pc->tx_len = len;
|
||||
etcp_router_waiter_register(pc->proxy->inst, pc->proxy->via_node_id, &pc->tx_waiter,
|
||||
etcp_router_waiter_register(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id, &pc->tx_waiter,
|
||||
tcp_proxy_client_tx_waiter_cb, pc);
|
||||
}
|
||||
} else DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "PROXY recv malloc(%u) failed sid=%08x", len, pc->stream_id);
|
||||
@@ -418,7 +419,7 @@ static void tcp_proxy_client_conn_free(struct tcp_proxy_client_conn *pc) {
|
||||
if (pc->close_pending && p && p->inst) {
|
||||
pc->close_pending = 0;
|
||||
uint8_t subcmd = pc->error ? TCP_PROXY_SUBCMD_ERROR : TCP_PROXY_SUBCMD_CLOSE;
|
||||
tcp_proxy_client_send_msg(p->inst, p->via_node_id, subcmd, pc->stream_id, NULL, 0, 1);
|
||||
tcp_proxy_client_send_msg(p->inst, TOPO_GROUP_UTUN, p->via_node_id, subcmd, pc->stream_id, NULL, 0, 1);
|
||||
}
|
||||
struct tcp_proxy_client_conn **prev = &p->conns;
|
||||
while (*prev) { if (*prev == pc) { *prev = pc->next; p->conn_count--; break; } prev = &(*prev)->next; }
|
||||
@@ -428,7 +429,7 @@ static void tcp_proxy_client_conn_free(struct tcp_proxy_client_conn *pc) {
|
||||
queue_free(pc->to_lwip); pc->to_lwip = NULL;
|
||||
}
|
||||
if (pc->tx_buf) { u_free(pc->tx_buf); pc->tx_buf = NULL; pc->tx_len = 0; }
|
||||
if (pc->proxy && pc->proxy->inst) etcp_router_waiter_cancel(pc->proxy->inst, pc->proxy->via_node_id, &pc->tx_waiter);
|
||||
if (pc->proxy && pc->proxy->inst) etcp_router_waiter_cancel(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id, &pc->tx_waiter);
|
||||
u_free(pc);
|
||||
}
|
||||
|
||||
@@ -463,7 +464,7 @@ static void tcp_proxy_client_handle_close(struct tcp_proxy_client* p, uint32_t s
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "PROXY REM_CLOSED sid=%08x fin_local=%d pcb_state=%u", stream_id, pc->fin_local, pc->pcb ? pc->pcb->state : 0);
|
||||
pc->rem_closed = 1;
|
||||
if (pc->tx_buf) { u_free(pc->tx_buf); pc->tx_buf = NULL; pc->tx_len = 0; }
|
||||
etcp_router_waiter_cancel(pc->proxy->inst, pc->proxy->via_node_id, &pc->tx_waiter);
|
||||
etcp_router_waiter_cancel(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id, &pc->tx_waiter);
|
||||
if (pc->pcb) {
|
||||
tcp_arg(pc->pcb, NULL);
|
||||
tcp_recv(pc->pcb, NULL);
|
||||
@@ -491,7 +492,7 @@ static void tcp_proxy_client_handle_error(struct tcp_proxy_client* p, uint32_t s
|
||||
}
|
||||
pc->rem_closed = 1;
|
||||
if (pc->tx_buf) { u_free(pc->tx_buf); pc->tx_buf = NULL; pc->tx_len = 0; }
|
||||
etcp_router_waiter_cancel(pc->proxy->inst, pc->proxy->via_node_id, &pc->tx_waiter);
|
||||
etcp_router_waiter_cancel(pc->proxy->inst, TOPO_GROUP_UTUN, pc->proxy->via_node_id, &pc->tx_waiter);
|
||||
tcp_proxy_client_conn_free(pc);
|
||||
}
|
||||
|
||||
@@ -671,7 +672,7 @@ void tcp_proxy_client_destroy(struct tcp_proxy_client* p) {
|
||||
queue_free(pc->to_lwip); pc->to_lwip = NULL;
|
||||
}
|
||||
if (pc->tx_buf) { u_free(pc->tx_buf); pc->tx_buf = NULL; pc->tx_len = 0; }
|
||||
if (p->inst) etcp_router_waiter_cancel(p->inst, p->via_node_id, &pc->tx_waiter);
|
||||
if (p->inst) etcp_router_waiter_cancel(p->inst, TOPO_GROUP_UTUN, p->via_node_id, &pc->tx_waiter);
|
||||
u_free(pc); pc = next;
|
||||
}
|
||||
p->conns = NULL;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "etcp_router.h"
|
||||
#include "utun_instance.h"
|
||||
#include "config_parser.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -34,7 +35,7 @@ static void pause_resume_cb(struct ll_queue* q, void* arg);
|
||||
static void close_retry_cb(void* arg);
|
||||
static void diag_timer_cb(void* arg);
|
||||
static void retry_timer_cb(void* arg);
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd,
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t subcmd,
|
||||
uint32_t sid, const uint8_t* data, size_t len, int force);
|
||||
static void send_close(struct tcp_proxy_server_conn* rc);
|
||||
static void send_error(struct tcp_proxy_server_conn* rc);
|
||||
@@ -48,7 +49,7 @@ static inline int write_pending(struct tcp_conn* tc) {
|
||||
// Отправка сообщений через ETCP
|
||||
// ====================================================================
|
||||
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd,
|
||||
static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t subcmd,
|
||||
uint32_t sid, const uint8_t* data, size_t len, int force) {
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "tcp_proxy_server: queue_entry_new failed subcmd=%02x sid=%08x", subcmd, sid); return -1; }
|
||||
@@ -63,7 +64,7 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd,
|
||||
queue_dgram_free(e); queue_entry_free(e); return -1;
|
||||
}
|
||||
e->len = TCP_PROXY_HDR_SIZE + len;
|
||||
return etcp_route_send(inst, dst, e, force);
|
||||
return etcp_route_send(inst, group_id, dst, e, force);
|
||||
}
|
||||
|
||||
static void close_retry_cb(void* arg) {
|
||||
@@ -74,7 +75,7 @@ static void close_retry_cb(void* arg) {
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (!inst) return;
|
||||
uint8_t subcmd = (rc->tc && rc->tc->error) ? TCP_PROXY_SUBCMD_ERROR : TCP_PROXY_SUBCMD_CLOSE;
|
||||
if (send_msg(inst, rc->peer_node_id, subcmd, rc->stream_id, NULL, 0, 1) < 0) {
|
||||
if (send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, subcmd, rc->stream_id, NULL, 0, 1) < 0) {
|
||||
rc->close_backoff = rc->close_backoff < 5000 ? rc->close_backoff * 2 : 5000;
|
||||
rc->close_timer = uasync_set_timeout(rc->ua, rc->close_backoff, rc, close_retry_cb, "tps_close_retry");
|
||||
return;
|
||||
@@ -85,7 +86,7 @@ static void close_retry_cb(void* arg) {
|
||||
static void send_close(struct tcp_proxy_server_conn* rc) {
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (!inst) return;
|
||||
if (send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_CLOSE, rc->stream_id, NULL, 0, 1) < 0) {
|
||||
if (send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, TCP_PROXY_SUBCMD_CLOSE, rc->stream_id, NULL, 0, 1) < 0) {
|
||||
rc->close_pending = 1;
|
||||
rc->close_backoff = 50;
|
||||
if (!rc->close_timer)
|
||||
@@ -96,7 +97,7 @@ static void send_close(struct tcp_proxy_server_conn* rc) {
|
||||
static void send_error(struct tcp_proxy_server_conn* rc) {
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (!inst) return;
|
||||
if (send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_ERROR, rc->stream_id, NULL, 0, 1) < 0) {
|
||||
if (send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, TCP_PROXY_SUBCMD_ERROR, rc->stream_id, NULL, 0, 1) < 0) {
|
||||
rc->close_pending = 1;
|
||||
rc->close_backoff = 50;
|
||||
if (!rc->close_timer)
|
||||
@@ -107,7 +108,7 @@ static void send_error(struct tcp_proxy_server_conn* rc) {
|
||||
static void send_fin(struct tcp_proxy_server_conn* rc) {
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
if (!inst) return;
|
||||
send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_FIN, rc->stream_id, NULL, 0, 1);
|
||||
send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, TCP_PROXY_SUBCMD_FIN, rc->stream_id, NULL, 0, 1);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
@@ -214,7 +215,7 @@ static void read_queue_drain_cb(struct ll_queue* q, void* arg) {
|
||||
struct ll_entry* e;
|
||||
|
||||
if (rc->tx_buf) {
|
||||
int ret = send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, rc->tx_buf, rc->tx_len, 0);
|
||||
int ret = send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, rc->tx_buf, rc->tx_len, 0);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "TPS TXBUF RETRY: sid=%08x len=%u ret=%d", rc->stream_id, rc->tx_len, ret);
|
||||
if (ret == 0) {
|
||||
u_free(rc->tx_buf); rc->tx_buf = NULL; rc->tx_len = 0;
|
||||
@@ -225,7 +226,7 @@ static void read_queue_drain_cb(struct ll_queue* q, void* arg) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
etcp_router_on_send_ready(inst, rc->peer_node_id, ETCP_RT_ID_TCP_PROXY,
|
||||
etcp_router_on_send_ready(inst, TOPO_GROUP_UTUN, rc->peer_node_id, ETCP_RT_ID_TCP_PROXY,
|
||||
&rc->pause_waiter, pause_resume_cb, rc);
|
||||
if (!rc->retry_timer) rc->retry_timer = uasync_set_timeout(rc->ua, 5000, rc, retry_timer_cb, "tps_retry");
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "TPS TXBUF BP AGAIN: sid=%08x waiter_reg", rc->stream_id);
|
||||
@@ -250,7 +251,7 @@ static void read_queue_drain_cb(struct ll_queue* q, void* arg) {
|
||||
queue_resume_callback(q);
|
||||
return;
|
||||
}
|
||||
int ret = send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, e->dgram, e->len, 0);
|
||||
int ret = send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, e->dgram, e->len, 0);
|
||||
rc->bytes_relayed += e->len; rc->drain_count++;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_TRAFFIC, "TPS DRAIN #%u sid=%08x len=%u → ret=%d rq=%d",
|
||||
rc->drain_count, rc->stream_id, e->len, ret, q->count);
|
||||
@@ -264,7 +265,7 @@ static void read_queue_drain_cb(struct ll_queue* q, void* arg) {
|
||||
memory_pool_free(rc->tc->data_pool, e->dgram); queue_entry_free(e);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SOCK:BACKPRESSURE fd=%d sid=%08x — buffered %u for retry",
|
||||
(int)rc->tc->sock, rc->stream_id, rc->tx_len);
|
||||
etcp_router_on_send_ready(inst, rc->peer_node_id, ETCP_RT_ID_TCP_PROXY,
|
||||
etcp_router_on_send_ready(inst, TOPO_GROUP_UTUN, rc->peer_node_id, ETCP_RT_ID_TCP_PROXY,
|
||||
&rc->pause_waiter, pause_resume_cb, rc);
|
||||
if (!rc->retry_timer) rc->retry_timer = uasync_set_timeout(rc->ua, 5000, rc, retry_timer_cb, "tps_retry");
|
||||
}
|
||||
@@ -285,7 +286,7 @@ static void retry_timer_cb(void* arg) {
|
||||
rc->retry_timer = NULL;
|
||||
if (!rc->tx_buf || !rc->tc || rc->tc->sock == SOCKET_INVALID || rc->cli_closed) return;
|
||||
struct UTUN_INSTANCE* inst = rc->ctx ? rc->ctx->inst : NULL;
|
||||
int ret = send_msg(inst, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, rc->tx_buf, rc->tx_len, 1);
|
||||
int ret = send_msg(inst, TOPO_GROUP_UTUN, rc->peer_node_id, TCP_PROXY_SUBCMD_DATA, rc->stream_id, rc->tx_buf, rc->tx_len, 1);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "TPS RETRY TIMER: sid=%08x len=%u force=1 ret=%d", rc->stream_id, rc->tx_len, ret);
|
||||
if (ret == 0) {
|
||||
u_free(rc->tx_buf); rc->tx_buf = NULL; rc->tx_len = 0;
|
||||
@@ -325,13 +326,13 @@ void tcp_proxy_server_conn_free(struct tcp_proxy_server_conn* rc) {
|
||||
if (rc->close_pending && rc->ctx && rc->ctx->inst) {
|
||||
rc->close_pending = 0;
|
||||
uint8_t subcmd = (rc->tc && rc->tc->error) ? TCP_PROXY_SUBCMD_ERROR : TCP_PROXY_SUBCMD_CLOSE;
|
||||
send_msg(rc->ctx->inst, rc->peer_node_id, subcmd, rc->stream_id, NULL, 0, 1);
|
||||
send_msg(rc->ctx->inst, TOPO_GROUP_UTUN, rc->peer_node_id, subcmd, rc->stream_id, NULL, 0, 1);
|
||||
}
|
||||
if (rc->ctx) {
|
||||
struct tcp_proxy_server_conn** prev = &rc->ctx->conns;
|
||||
while (*prev) { if (*prev == rc) { *prev = rc->next; rc->ctx->conn_count--; break; } prev = &(*prev)->next; }
|
||||
}
|
||||
if (rc->ctx && rc->ctx->inst) etcp_router_cancel_send_ready(rc->ctx->inst, rc->peer_node_id, ETCP_RT_ID_TCP_PROXY, &rc->pause_waiter);
|
||||
if (rc->ctx && rc->ctx->inst) etcp_router_cancel_send_ready(rc->ctx->inst, TOPO_GROUP_UTUN, rc->peer_node_id, ETCP_RT_ID_TCP_PROXY, &rc->pause_waiter);
|
||||
if (rc->tx_buf) { u_free(rc->tx_buf); rc->tx_buf = NULL; rc->tx_len = 0; }
|
||||
if (rc->retry_timer) { uasync_cancel_timeout(rc->ua, rc->retry_timer); rc->retry_timer = NULL; }
|
||||
if (rc->close_timer) { uasync_cancel_timeout(rc->ua, rc->close_timer); rc->close_timer = NULL; }
|
||||
@@ -383,7 +384,7 @@ int tcp_proxy_server_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry*
|
||||
if (ret < 0 && errno != EINPROGRESS) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "TCP proxy server: connect() to %d.%d.%d.%d:%d failed: %s",
|
||||
dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], ntohs(dest_port), strerror(errno));
|
||||
send_msg(inst, src_node_id, TCP_PROXY_SUBCMD_ERROR, stream_id, NULL, 0, 1);
|
||||
send_msg(inst, TOPO_GROUP_UTUN, src_node_id, TCP_PROXY_SUBCMD_ERROR, stream_id, NULL, 0, 1);
|
||||
ctx->conn_count--; tcp_conn_destroy(rc->tc); u_free(rc);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return -1;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "etcp_router.h"
|
||||
#include "utun_instance.h"
|
||||
#include "tun_if.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -64,7 +65,7 @@ static void flow_read_cb(socket_t sock, void* arg) {
|
||||
memcpy(e->dgram + UDP_PROXY_HDR_SIZE, buf, n);
|
||||
e->len = UDP_PROXY_HDR_SIZE + n;
|
||||
|
||||
etcp_route_send(g_udp_ctx->inst, f->client_node_id, e, 0);
|
||||
etcp_route_send(g_udp_ctx->inst, TOPO_GROUP_UTUN, f->client_node_id, e, 0);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
@@ -169,7 +170,7 @@ int udp_proxy_send_to_exit(struct UTUN_INSTANCE* inst, uint64_t exit_node_id,
|
||||
memcpy(e->dgram + 20, &dst_port, 2);
|
||||
if (payload_len > 0) memcpy(e->dgram + UDP_PROXY_HDR_SIZE, payload, payload_len);
|
||||
e->len = UDP_PROXY_HDR_SIZE + payload_len;
|
||||
return etcp_route_send(inst, exit_node_id, e, 0);
|
||||
return etcp_route_send(inst, TOPO_GROUP_UTUN, exit_node_id, e, 0);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
@@ -238,7 +238,7 @@ int conn_mgr_disconnect_node(struct CONN_MGR* mgr, uint64_t node_id) {
|
||||
pkt.subcmd = CONN_MGR_SUBCMD_DISCONNECT;
|
||||
pkt.node_id = node_id;
|
||||
struct ll_entry* qe = queue_entry_new(0);
|
||||
if (qe) { qe->dgram = u_malloc(sizeof(pkt)); memcpy(qe->dgram, &pkt, sizeof(pkt)); qe->len = sizeof(pkt); etcp_route_send(mgr->instance, node_id, qe, 1); }
|
||||
if (qe) { qe->dgram = u_malloc(sizeof(pkt)); memcpy(qe->dgram, &pkt, sizeof(pkt)); qe->len = sizeof(pkt); etcp_route_send(mgr->instance, TOPO_GROUP_UTUN, node_id, qe, 1); }
|
||||
cm_clear_nodeinfo(mgr, node_id);
|
||||
cm_entry_destroy(entry);
|
||||
entry->state = CONN_MGR_STATE_DISCONNECTED;
|
||||
@@ -272,7 +272,7 @@ int conn_mgr_send(struct CONN_MGR* mgr, uint64_t node_id, struct ll_entry* entry
|
||||
struct CONN_MGR_ENTRY* e = cm_find_entry(mgr, node_id);
|
||||
if (!e || e->state != CONN_MGR_STATE_CONNECTED) { queue_entry_free(entry); return -1; }
|
||||
e->last_traffic_tb = get_time_tb();
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(mgr->instance, node_id, ETCP_RT_ID_CONN_MGR);
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(mgr->instance, TOPO_GROUP_UTUN, node_id, ETCP_RT_ID_CONN_MGR);
|
||||
if (!rconn) { queue_entry_free(entry); return -1; }
|
||||
int ret = etcp_router_conn_send(rconn, entry->dgram, entry->len);
|
||||
queue_entry_free(entry);
|
||||
@@ -567,7 +567,7 @@ static void cm_start_phase_reverse(struct CONN_MGR_ENTRY* entry) {
|
||||
if (!qe) { u_free(pkt); cm_deliver_result(entry, CONN_MGR_ERR_INTERNAL); return; }
|
||||
qe->dgram = pkt;
|
||||
qe->len = (uint16_t)pkt_size;
|
||||
etcp_route_send(entry->mgr->instance, entry->node_id, qe, 1);
|
||||
etcp_route_send(entry->mgr->instance, TOPO_GROUP_UTUN, entry->node_id, qe, 1);
|
||||
|
||||
struct cm_reverse_pending* rp = u_calloc(1, sizeof(struct cm_reverse_pending));
|
||||
if (rp) { rp->request_id = req_id; rp->entry = entry; rp->next = entry->mgr->reverse_pending;
|
||||
@@ -625,7 +625,7 @@ static int cm_start_phase_indirect(struct CONN_MGR_ENTRY* entry) {
|
||||
qe->dgram = u_malloc(sizeof(req));
|
||||
memcpy(qe->dgram, &req, sizeof(req));
|
||||
qe->len = (uint16_t)sizeof(req);
|
||||
etcp_route_send(entry->mgr->instance, entry->node_id, qe, 1);
|
||||
etcp_route_send(entry->mgr->instance, TOPO_GROUP_UTUN, entry->node_id, qe, 1);
|
||||
entry->main.timer = uasync_set_timeout(mgr->instance->ua, CONN_MGR_INTERM_EXCHANGE_TIMEOUT_MS * 10,
|
||||
entry, cm_exchange_timeout_cb, "conn_mgr_interm_exch");
|
||||
{
|
||||
@@ -693,7 +693,7 @@ static void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CONN_
|
||||
if (nq) pkt.selected[i].rtt = cm_get_node_min_rtt(nq);
|
||||
}
|
||||
struct ll_entry* qe = queue_entry_new(0);
|
||||
if (qe) { qe->dgram = u_malloc(sizeof(pkt)); memcpy(qe->dgram, &pkt, sizeof(pkt)); qe->len = sizeof(pkt); etcp_route_send(entry->mgr->instance, entry->node_id, qe, 1); }
|
||||
if (qe) { qe->dgram = u_malloc(sizeof(pkt)); memcpy(qe->dgram, &pkt, sizeof(pkt)); qe->len = sizeof(pkt); etcp_route_send(entry->mgr->instance, TOPO_GROUP_UTUN, entry->node_id, qe, 1); }
|
||||
|
||||
entry->conn_type = CONN_TYPE_INDIRECT;
|
||||
entry->state = CONN_MGR_STATE_CONNECTED;
|
||||
@@ -877,7 +877,7 @@ static void cm_handle_interm_exchange_req(struct ETCP_CONN* conn,
|
||||
qe->dgram = u_malloc(resp_size);
|
||||
memcpy(qe->dgram, &resp, resp_size);
|
||||
qe->len = (uint16_t)resp_size;
|
||||
etcp_route_send(mgr->instance, conn->peer_node_id, qe, 1);
|
||||
etcp_route_send(mgr->instance, TOPO_GROUP_UTUN, conn->peer_node_id, qe, 1);
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: sent EXCHANGE_RESP to 0x%016llx my=%u your=%u",
|
||||
(unsigned long long)conn->peer_node_id, resp.my_count, resp.your_count);
|
||||
|
||||
@@ -32,7 +32,7 @@ static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN
|
||||
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, const uint8_t* payload, size_t payload_len);
|
||||
static int router_send_one(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len);
|
||||
static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len, uint8_t flag_bits, int is_signed);
|
||||
static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t svc_id, uint8_t flag_bits);
|
||||
static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t svc_id, uint8_t flag_bits);
|
||||
static void router_drain_send_q(struct ETCP_ROUTER_CONN* rconn);
|
||||
static void router_send_resume_cb(void* arg);
|
||||
static void router_no_route_retry_cb(void* arg);
|
||||
@@ -58,23 +58,26 @@ static void router_update_minrtt(struct ETCP_ROUTER_CONN* rconn);
|
||||
// Транзитные очереди — per (src, dst) pair, backpressure через waiter на send_input_q
|
||||
|
||||
static struct TRANSIT_QUEUE* transit_queue_find(struct ETCP_CONN* conn,
|
||||
uint64_t group_id,
|
||||
uint64_t src_node_id, uint64_t dst_node_id) {
|
||||
if (!conn->transit_queues) return NULL;
|
||||
uint8_t key[16];
|
||||
memcpy(key, &src_node_id, 8);
|
||||
memcpy(key + 8, &dst_node_id, 8);
|
||||
uint8_t key[24];
|
||||
memcpy(key, &group_id, 8);
|
||||
memcpy(key + 8, &src_node_id, 8);
|
||||
memcpy(key + 16, &dst_node_id, 8);
|
||||
return (struct TRANSIT_QUEUE*)queue_find_data_by_index(conn->transit_queues, key);
|
||||
}
|
||||
|
||||
static struct TRANSIT_QUEUE* transit_queue_get_or_create(struct ETCP_CONN* conn,
|
||||
uint64_t group_id,
|
||||
uint64_t src_node_id, uint64_t dst_node_id) {
|
||||
if (!conn->transit_queues) {
|
||||
struct UASYNC* ua = conn->instance ? conn->instance->ua : NULL;
|
||||
if (!ua) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "transit_queue_get_or_create: no ua"); return NULL; }
|
||||
conn->transit_queues = queue_new(ua, TRANSIT_QUEUE_HASH, 0, 16, "transit_q_reg");
|
||||
conn->transit_queues = queue_new(ua, TRANSIT_QUEUE_HASH, 0, 24, "transit_q_reg");
|
||||
if (!conn->transit_queues) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "transit_queue_get_or_create: queue_new failed"); return NULL; }
|
||||
}
|
||||
struct TRANSIT_QUEUE* tq = transit_queue_find(conn, src_node_id, dst_node_id);
|
||||
struct TRANSIT_QUEUE* tq = transit_queue_find(conn, group_id, src_node_id, dst_node_id);
|
||||
if (tq) return tq;
|
||||
size_t data_size = sizeof(struct TRANSIT_QUEUE) - sizeof(struct ll_entry);
|
||||
tq = (struct TRANSIT_QUEUE*)queue_entry_new(data_size);
|
||||
@@ -83,14 +86,18 @@ static struct TRANSIT_QUEUE* transit_queue_get_or_create(struct ETCP_CONN* conn,
|
||||
return NULL;
|
||||
}
|
||||
memset(&tq->waiter, 0, sizeof(tq->waiter));
|
||||
tq->group_id = group_id;
|
||||
tq->src_node_id = src_node_id;
|
||||
tq->dst_node_id = dst_node_id;
|
||||
tq->conn = conn;
|
||||
tq->q = queue_new(conn->instance->ua, 0, 0, 0, "transit_pair_q");
|
||||
if (!tq->q) { queue_entry_free(&tq->ll); return NULL; }
|
||||
memcpy(tq->ll.data, &src_node_id, 8);
|
||||
memcpy(tq->ll.data + 8, &dst_node_id, 8);
|
||||
memcpy(tq->ll.data, &group_id, 8);
|
||||
memcpy(tq->ll.data + 8, &src_node_id, 8);
|
||||
memcpy(tq->ll.data + 16, &dst_node_id, 8);
|
||||
queue_data_put_with_index(conn->transit_queues, &tq->ll);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "transit_q: new src=%016llx dst=%016llx",
|
||||
(unsigned long long)src_node_id, (unsigned long long)dst_node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "transit_q: new group=%016llx src=%016llx dst=%016llx",
|
||||
(unsigned long long)group_id, (unsigned long long)src_node_id, (unsigned long long)dst_node_id);
|
||||
return tq;
|
||||
}
|
||||
|
||||
@@ -136,11 +143,13 @@ void etcp_router_transit_queues_destroy(struct ETCP_CONN* conn) {
|
||||
// ====================================================================
|
||||
|
||||
static struct ETCP_ROUTER_CONN* router_conn_find(struct UTUN_INSTANCE* inst,
|
||||
uint64_t group_id,
|
||||
uint64_t remote_node_id, uint8_t svc_id) {
|
||||
if (!inst || !inst->router_conns) return NULL;
|
||||
uint8_t key[9];
|
||||
memcpy(key, &remote_node_id, 8);
|
||||
key[8] = svc_id;
|
||||
uint8_t key[17];
|
||||
memcpy(key, &group_id, 8);
|
||||
memcpy(key + 8, &remote_node_id, 8);
|
||||
key[16] = svc_id;
|
||||
return (struct ETCP_ROUTER_CONN*)queue_find_data_by_index(inst->router_conns, key);
|
||||
}
|
||||
|
||||
@@ -161,6 +170,7 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
|
||||
if (!dgram) { if (!flag_bits) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; }
|
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram;
|
||||
hdr->cmd = ETCP_RT_ID_SVC_ROUTE;
|
||||
hdr->group_id = rconn->group_id;
|
||||
hdr->dst_node_id = rconn->remote_node_id;
|
||||
hdr->src_node_id = inst->node_id;
|
||||
hdr->seq = seq;
|
||||
@@ -178,7 +188,7 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
|
||||
if (pl_len > 0) memcpy(dgram + SVC_ROUTE_HDR_SIZE, payload, pl_len);
|
||||
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(inst->topo_groups);
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, rconn->group_id);
|
||||
if (group) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, rconn->remote_node_id);
|
||||
if (nq && nq->conn_mgr_type == CONN_TYPE_INDIRECT && nq->conn_mgr_intermediariy_count > 0) {
|
||||
@@ -258,12 +268,13 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
|
||||
}
|
||||
|
||||
// Отправка без conn (RST для неизвестного src)
|
||||
static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t svc_id, uint8_t flag_bits) {
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), dst);
|
||||
static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst, uint8_t svc_id, uint8_t flag_bits) {
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, group_id), dst);
|
||||
if (!conn) return;
|
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)u_malloc(SVC_ROUTE_HDR_SIZE);
|
||||
if (!hdr) return;
|
||||
hdr->cmd = ETCP_RT_ID_SVC_ROUTE;
|
||||
hdr->group_id = group_id;
|
||||
hdr->dst_node_id = dst;
|
||||
hdr->src_node_id = inst->node_id;
|
||||
hdr->seq = 0;
|
||||
@@ -314,7 +325,7 @@ static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn) {
|
||||
rconn->closed = 1;
|
||||
router_send_close_to_service(rconn);
|
||||
// Отправляем CLOSE удалённой стороне
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), rconn->remote_node_id);
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, rconn->group_id), rconn->remote_node_id);
|
||||
if (conn) router_send_one_flags(rconn, NULL, 0, ROUTER_FLAG_CLOSE, 0);
|
||||
// Таймеры
|
||||
if (rconn->ack_timer) { uasync_cancel_timeout(inst->ua, rconn->ack_timer); rconn->ack_timer = NULL; }
|
||||
@@ -349,8 +360,8 @@ static void router_close_and_notify(struct ETCP_ROUTER_CONN* rconn) {
|
||||
}
|
||||
if (inst->router_conns)
|
||||
queue_remove_data(inst->router_conns, &rconn->ll);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: closed remote=%016llx svc_id=%u",
|
||||
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: closed group=%016llx remote=%016llx svc_id=%u",
|
||||
(unsigned long long)rconn->group_id, (unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
||||
uasync_call_soon(inst->ua, rconn, router_close_finalize);
|
||||
}
|
||||
|
||||
@@ -389,7 +400,7 @@ static void router_no_route_retry_cb(void* arg) {
|
||||
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)arg;
|
||||
if (rconn->closed) return;
|
||||
rconn->no_route_timer = NULL;
|
||||
struct ETCP_CONN* c = topo_group_find_conn_for_node(topo_groups_get_default(rconn->inst->topo_groups), rconn->remote_node_id);;
|
||||
struct ETCP_CONN* c = topo_group_find_conn_for_node(topo_groups_find(rconn->inst->topo_groups, rconn->group_id), rconn->remote_node_id);;
|
||||
if (c) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router: route appeared for %016llx svc_id=%u, draining send_q=%d",
|
||||
(unsigned long long)rconn->remote_node_id, rconn->svc_id, queue_entry_count(rconn->send_q));
|
||||
@@ -412,6 +423,7 @@ static void router_retransmit_one(struct ETCP_ROUTER_CONN* rconn, struct ROUTER_
|
||||
if (!dgram) { rconn->c_pkts_send_err++; return; }
|
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram;
|
||||
hdr->cmd = ETCP_RT_ID_SVC_ROUTE;
|
||||
hdr->group_id = rconn->group_id;
|
||||
hdr->dst_node_id = rconn->remote_node_id;
|
||||
hdr->src_node_id = inst->node_id;
|
||||
hdr->seq = inf->seq;
|
||||
@@ -420,7 +432,7 @@ static void router_retransmit_one(struct ETCP_ROUTER_CONN* rconn, struct ROUTER_
|
||||
hdr->timestamp = get_current_timestamp();
|
||||
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(inst->topo_groups);
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, rconn->group_id);
|
||||
if (group) {
|
||||
struct TOPO_NODEQ* nq = topo_node_find_by_id(group, rconn->remote_node_id);
|
||||
if (nq && nq->conn_mgr_type == CONN_TYPE_INDIRECT && nq->conn_mgr_intermediariy_count > 0) {
|
||||
@@ -618,7 +630,7 @@ static void router_ack_do_send(struct ETCP_ROUTER_CONN* rconn) {
|
||||
|
||||
static void router_send_ack(struct ETCP_ROUTER_CONN* rconn) {
|
||||
struct UTUN_INSTANCE* inst = rconn->inst;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), rconn->remote_node_id);
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, rconn->group_id), rconn->remote_node_id);
|
||||
if (!conn) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_ack: no route to %016llx svc_id=%u",
|
||||
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
|
||||
@@ -628,6 +640,7 @@ static void router_send_ack(struct ETCP_ROUTER_CONN* rconn) {
|
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)u_malloc(SVC_ROUTE_HDR_SIZE);
|
||||
if (!hdr) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_ack: u_malloc failed"); return; }
|
||||
hdr->cmd = ETCP_RT_ID_SVC_ROUTE;
|
||||
hdr->group_id = rconn->group_id;
|
||||
hdr->dst_node_id = rconn->remote_node_id;
|
||||
hdr->src_node_id = inst->node_id;
|
||||
hdr->seq = rconn->rx_seq;
|
||||
@@ -768,7 +781,7 @@ static void router_incoming_q_cb(struct ll_queue* q, void* arg) {
|
||||
|
||||
queue_data_put_with_index(rconn->recv_q, rq);
|
||||
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(rconn->inst->topo_groups), rconn->remote_node_id);;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(rconn->inst->topo_groups, rconn->group_id), rconn->remote_node_id);;
|
||||
if (seq == rconn->rx_seq) router_try_assembly(rconn, conn);
|
||||
router_schedule_ack(rconn);
|
||||
queue_resume_callback(q);
|
||||
@@ -788,7 +801,7 @@ static int router_verify_signature(struct UTUN_INSTANCE* inst, struct ll_entry*
|
||||
}
|
||||
size_t actual_payload = *pl_len - SC_SIGN_SIZE;
|
||||
uint8_t* sig = (uint8_t*)entry->dgram + SVC_ROUTE_HDR_SIZE + actual_payload;
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(inst->topo_groups);
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, hdr->group_id);
|
||||
struct TOPO_NODEQ* nq = group ? topo_node_find_by_id(group, hdr->src_node_id) : NULL;
|
||||
if (!nq) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: SIGNED packet from unknown node %016llx — dropping",
|
||||
@@ -818,7 +831,7 @@ static int router_verify_signature(struct UTUN_INSTANCE* inst, struct ll_entry*
|
||||
if (sc_stream_sign_verify(&vfy_state, sig, SC_SIGN_SIZE) != SC_OK) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: signature verification FAILED for node %016llx svc_id=%u — dropping",
|
||||
(unsigned long long)hdr->src_node_id, hdr->svc_id);
|
||||
struct ETCP_ROUTER_CONN* sr = router_conn_find(inst, hdr->src_node_id, hdr->svc_id);
|
||||
struct ETCP_ROUTER_CONN* sr = router_conn_find(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id);
|
||||
if (sr) sr->c_sign_fail++;
|
||||
free_entry(entry); return -1;
|
||||
}
|
||||
@@ -875,13 +888,13 @@ static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CON
|
||||
|
||||
static void router_forward_transit(struct UTUN_INSTANCE* inst, struct ll_entry* entry,
|
||||
struct SVC_ROUTE_HDR* hdr) {
|
||||
struct ETCP_CONN* next = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), hdr->dst_node_id);
|
||||
struct ETCP_CONN* next = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, hdr->group_id), hdr->dst_node_id);
|
||||
if (!next) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: no route to %016llx svc_id=%u, dropping",
|
||||
(unsigned long long)hdr->dst_node_id, hdr->svc_id);
|
||||
free_entry(entry); return;
|
||||
}
|
||||
struct TRANSIT_QUEUE* tq = transit_queue_find(next, hdr->src_node_id, hdr->dst_node_id);
|
||||
struct TRANSIT_QUEUE* tq = transit_queue_find(next, hdr->group_id, hdr->src_node_id, hdr->dst_node_id);
|
||||
|
||||
if (!tq && next->send_input_q && queue_entry_count(next->send_input_q) == 0) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: forwarding svc_id=%u → %016llx via %s",
|
||||
@@ -892,7 +905,7 @@ static void router_forward_transit(struct UTUN_INSTANCE* inst, struct ll_entry*
|
||||
}
|
||||
|
||||
if (!tq) {
|
||||
tq = transit_queue_get_or_create(next, hdr->src_node_id, hdr->dst_node_id);
|
||||
tq = transit_queue_get_or_create(next, hdr->group_id, hdr->src_node_id, hdr->dst_node_id);
|
||||
if (!tq) { free_entry(entry); return; }
|
||||
}
|
||||
int was_empty = (queue_entry_count(tq->q) == 0);
|
||||
@@ -914,8 +927,8 @@ static int router_check_peer_restart(struct UTUN_INSTANCE* inst, struct ETCP_ROU
|
||||
"router: peer restart sess_id=%u→%u svc_id=%u from %016llx",
|
||||
rconn->peer_sess_id, incoming_sess, hdr->svc_id,
|
||||
(unsigned long long)hdr->src_node_id);
|
||||
etcp_router_conn_restart(inst, hdr->src_node_id, hdr->svc_id);
|
||||
*prconn = etcp_router_conn_get(inst, hdr->src_node_id, hdr->svc_id);
|
||||
etcp_router_conn_restart(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id);
|
||||
*prconn = etcp_router_conn_get(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id);
|
||||
if (!*prconn) return -1;
|
||||
(*prconn)->peer_sess_id = incoming_sess;
|
||||
rconn = *prconn;
|
||||
@@ -987,7 +1000,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
|
||||
if (router_verify_signature(inst, entry, hdr, &pl_len) != 0) return;
|
||||
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, hdr->src_node_id, hdr->svc_id);
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id);
|
||||
|
||||
if (pl_len == 0 && (hdr->flags & (ROUTER_FLAG_CLOSE | ROUTER_FLAG_RST))) {
|
||||
if (rconn) router_close_and_notify(rconn);
|
||||
@@ -996,7 +1009,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
||||
if (pl_len == 0) { router_handle_ack(inst, rconn, hdr->seq, hdr->src_node_id, hdr->timestamp); free_entry(entry); return; }
|
||||
|
||||
if (!rconn) {
|
||||
rconn = etcp_router_conn_get(inst, hdr->src_node_id, hdr->svc_id);
|
||||
rconn = etcp_router_conn_get(inst, hdr->group_id, hdr->src_node_id, hdr->svc_id);
|
||||
if (!rconn) { free_entry(entry); return; }
|
||||
rconn->peer_sess_id = (hdr->flags >> ROUTER_SESS_ID_SHIFT) & 0x3;
|
||||
}
|
||||
@@ -1017,7 +1030,7 @@ int etcp_router_init(struct UTUN_INSTANCE* inst) {
|
||||
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "NULL instance"); return -1; }
|
||||
memset(&inst->router_bindings, 0, sizeof(inst->router_bindings));
|
||||
inst->router_conns = queue_new(inst->ua,
|
||||
ROUTER_CONN_HASH_SIZE, 0, 9, "router_conns");
|
||||
ROUTER_CONN_HASH_SIZE, 0, 17, "router_conns");
|
||||
if (!inst->router_conns) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "queue_new(router_conns) failed");
|
||||
return -1;
|
||||
@@ -1069,7 +1082,7 @@ int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_entry* entry, int force) {
|
||||
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force) {
|
||||
if (!inst || !entry) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "NULL inst=%p entry=%p", (void*)inst, (void*)entry);
|
||||
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return -1;
|
||||
@@ -1089,9 +1102,9 @@ int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ETCP_CONN* etcp_conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), dst_node_id);
|
||||
struct ETCP_CONN* etcp_conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, group_id), dst_node_id);
|
||||
if (!etcp_conn) {
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, dst_node_id, svc_id);
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, group_id, dst_node_id, svc_id);
|
||||
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
int eq_ret = router_enqueue_send(rconn, entry->dgram + 1, payload_len, force);
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
@@ -1105,7 +1118,7 @@ int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, dst_node_id, svc_id);
|
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, group_id, dst_node_id, svc_id);
|
||||
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return -1; }
|
||||
|
||||
if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= (int32_t)router_effective_max_inflight(rconn)) {
|
||||
@@ -1119,32 +1132,32 @@ int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_
|
||||
return ret;
|
||||
}
|
||||
|
||||
int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
||||
if (!inst || !topo_groups_get_default(inst->topo_groups)) return -1;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), node_id);
|
||||
int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id) {
|
||||
if (!inst || !topo_groups_find(inst->topo_groups, group_id)) return -1;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, group_id), node_id);
|
||||
if (!conn || !conn->normalizer || !conn->normalizer->input) return -1;
|
||||
return queue_entry_count(conn->normalizer->input);
|
||||
}
|
||||
|
||||
void etcp_router_waiter_register(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
|
||||
void etcp_router_waiter_register(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t peer_node_id,
|
||||
struct queue_waiter_handle* h,
|
||||
queue_threshold_callback_fn callback, void* arg) {
|
||||
if (!inst || !topo_groups_get_default(inst->topo_groups) || !h) return;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), peer_node_id);
|
||||
if (!inst || !topo_groups_find(inst->topo_groups, group_id) || !h) return;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, group_id), peer_node_id);
|
||||
if (!conn || !conn->normalizer || !conn->normalizer->input) return;
|
||||
queue_waiter_wait(conn->normalizer->input, h, callback, arg);
|
||||
}
|
||||
|
||||
void etcp_router_waiter_cancel(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
|
||||
void etcp_router_waiter_cancel(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t peer_node_id,
|
||||
struct queue_waiter_handle* h) {
|
||||
if (!inst || !topo_groups_get_default(inst->topo_groups) || !h) return;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_get_default(inst->topo_groups), peer_node_id);
|
||||
if (!inst || !topo_groups_find(inst->topo_groups, group_id) || !h) return;
|
||||
struct ETCP_CONN* conn = topo_group_find_conn_for_node(topo_groups_find(inst->topo_groups, group_id), peer_node_id);
|
||||
if (!conn || !conn->normalizer || !conn->normalizer->input) return;
|
||||
queue_waiter_cancel(conn->normalizer->input, h);
|
||||
}
|
||||
|
||||
void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t remote_node_id, uint8_t svc_id) {
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, remote_node_id, svc_id);
|
||||
void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id) {
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, group_id, remote_node_id, svc_id);
|
||||
if (!rconn) return;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_restart: svc_id=%u remote=%016llx — resetting local state",
|
||||
@@ -1241,19 +1254,19 @@ void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t remote_node_i
|
||||
rconn->closed = 0;
|
||||
}
|
||||
|
||||
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
|
||||
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h,
|
||||
queue_threshold_callback_fn callback, void* arg) {
|
||||
if (!inst || !h) return;
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, node_id, svc_id);
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, group_id, node_id, svc_id);
|
||||
if (!rconn || !rconn->send_q) return;
|
||||
queue_waiter_wait(rconn->send_q, h, callback, arg);
|
||||
}
|
||||
|
||||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
|
||||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h) {
|
||||
if (!inst || !h) return;
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, node_id, svc_id);
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, group_id, node_id, svc_id);
|
||||
if (!rconn || !rconn->send_q) return;
|
||||
queue_waiter_cancel(rconn->send_q, h);
|
||||
}
|
||||
@@ -1263,16 +1276,21 @@ void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id,
|
||||
// ====================================================================
|
||||
|
||||
struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
||||
uint64_t group_id,
|
||||
uint64_t remote_node_id, uint8_t svc_id) {
|
||||
if (!inst || !inst->router_conns) return NULL;
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, remote_node_id, svc_id);
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, group_id, remote_node_id, svc_id);
|
||||
if (rconn) return rconn;
|
||||
|
||||
size_t data_size = sizeof(struct ETCP_ROUTER_CONN) - sizeof(struct ll_entry);
|
||||
rconn = (struct ETCP_ROUTER_CONN*)queue_entry_new(data_size);
|
||||
if (!rconn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_entry_new failed"); return NULL; }
|
||||
rconn->group_id = group_id;
|
||||
rconn->remote_node_id = remote_node_id;
|
||||
rconn->svc_id = svc_id;
|
||||
memcpy(rconn->ll.data, &group_id, 8);
|
||||
memcpy(rconn->ll.data + 8, &remote_node_id, 8);
|
||||
rconn->ll.data[16] = svc_id;
|
||||
rconn->last_dgram_ts = get_current_timestamp();
|
||||
rconn->rtt = 0;
|
||||
rconn->rtt_jitter = 0;
|
||||
@@ -1333,8 +1351,8 @@ struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
||||
queue_set_threshold(rconn->incoming_q, 0, 0);
|
||||
rconn->incoming_data_ready = 0;
|
||||
queue_set_threshold(rconn->send_q, ROUTER_MAX_SEND_Q_PACKETS - 1, 0);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: new conn remote=%016llx svc_id=%u",
|
||||
(unsigned long long)remote_node_id, svc_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "router_conn: new conn group=%016llx remote=%016llx svc_id=%u",
|
||||
(unsigned long long)group_id, (unsigned long long)remote_node_id, svc_id);
|
||||
queue_data_put_with_index(inst->router_conns, &rconn->ll);
|
||||
return rconn;
|
||||
}
|
||||
@@ -1408,7 +1426,7 @@ void etcp_router_pause_retrans_for_node(struct UTUN_INSTANCE* inst, uint64_t rem
|
||||
}
|
||||
}
|
||||
|
||||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id) {
|
||||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id) {
|
||||
if (!inst || !inst->router_conns) return;
|
||||
// Iterate via hash chains to avoid inf-loop from put-back in FIFO iteration
|
||||
struct ll_entry* to_close[256];
|
||||
@@ -1419,7 +1437,7 @@ void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t re
|
||||
while (entry) {
|
||||
struct ll_entry* next = entry->hash_next;
|
||||
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)entry;
|
||||
if (rconn->remote_node_id == remote_node_id)
|
||||
if (rconn->group_id == group_id && rconn->remote_node_id == remote_node_id)
|
||||
to_close[count++] = entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Упрощённый TCP поверх ETCP: восстановление порядка, дедупликация, без переповторов
|
||||
//
|
||||
// Формат SVC_ROUTE пакета:
|
||||
// [cmd:1] [dst_node_id:8] [src_node_id:8] [seq:4] [svc_id:1] [flags:1] [payload...]
|
||||
// [cmd:1] [group_id:8] [dst_node_id:8] [src_node_id:8] [seq:4] [svc_id:1] [flags:1] [timestamp:2] [payload...]
|
||||
// flags: bit7=START, bit6=RST, bit5-4=sess_id(0-3)
|
||||
// ACK-пакет: тот же заголовок, seq=rx_seq, payload_len=0
|
||||
#ifndef ETCP_ROUTER_H
|
||||
@@ -22,6 +22,7 @@ extern "C" {
|
||||
#pragma pack(push, 1)
|
||||
struct SVC_ROUTE_HDR {
|
||||
uint8_t cmd; // ETCP_ID_SVC_ROUTE (0x03) / ETCP_RT_ID_SVC_ROUTE
|
||||
uint64_t group_id; // идентификатор группы
|
||||
uint64_t dst_node_id;
|
||||
uint64_t src_node_id;
|
||||
uint32_t seq; // data: tx_seq; ACK: rx_seq (ожидаемый seq)
|
||||
@@ -30,7 +31,7 @@ struct SVC_ROUTE_HDR {
|
||||
uint16_t timestamp; // часы отправителя (0.1ms), для RTT; ACK: эхо последнего data-пакета
|
||||
};
|
||||
#pragma pack(pop)
|
||||
#define SVC_ROUTE_HDR_SIZE sizeof(struct SVC_ROUTE_HDR) // 25
|
||||
#define SVC_ROUTE_HDR_SIZE sizeof(struct SVC_ROUTE_HDR) // 33
|
||||
#define SVC_ROUTE_MAX_BINDINGS 256
|
||||
|
||||
// Биты в flags
|
||||
@@ -41,24 +42,26 @@ struct SVC_ROUTE_HDR {
|
||||
#define ROUTER_SESS_ID_SHIFT 4
|
||||
#define ROUTER_SESS_ID_MASK 0x30
|
||||
|
||||
// Очередь транзитных пакетов для пары (src_node_id, dst_node_id)
|
||||
// Очередь транзитных пакетов для пары (group_id, src_node_id, dst_node_id)
|
||||
// Создаётся когда не получается отправить пакет в ETCP напрямую,
|
||||
// удаляется когда очередь становится пустой.
|
||||
// ll.data[0..15] = src:8 + dst:8 — совпадает с полями ниже по памяти
|
||||
// ll.data[0..23] = group_id:8 + src:8 + dst:8 — совпадает с полями ниже по памяти
|
||||
struct TRANSIT_QUEUE {
|
||||
struct ll_entry ll; // data[0..15] = src_node_id:8 + dst_node_id:8 (16-byte hash index)
|
||||
uint64_t src_node_id; // = data[0..7]
|
||||
uint64_t dst_node_id; // = data[8..15]
|
||||
struct ll_entry ll; // data[0..23] = group_id:8 + src_node_id:8 + dst_node_id:8 (24-byte hash index)
|
||||
uint64_t group_id; // = data[0..7]
|
||||
uint64_t src_node_id; // = data[8..15]
|
||||
uint64_t dst_node_id; // = data[16..23]
|
||||
struct ll_queue* q; // FIFO транзитных пакетов (ll_entry с dgram), начиная с data[16]
|
||||
struct queue_waiter_handle waiter; // backpressure waiter на bp-очередь (normalizer->input или tx_queue)
|
||||
struct ETCP_CONN* conn; // next_hop (для etcp_send в drain_cb)
|
||||
};
|
||||
|
||||
// Состояние одного логического подключения (remote_node_id + svc_id)
|
||||
// Состояние одного логического подключения (group_id + remote_node_id + svc_id)
|
||||
struct ETCP_ROUTER_CONN {
|
||||
struct ll_entry ll; // data[0..7]=remote_node_id, data[8]=svc_id — хеш-индекс
|
||||
uint64_t remote_node_id; // = data[0..7]
|
||||
uint8_t svc_id; // = data[8]
|
||||
struct ll_entry ll; // data[0..15]=group_id:8+remote_node_id:8, data[16]=svc_id — хеш-индекс
|
||||
uint64_t group_id; // = data[0..7]
|
||||
uint64_t remote_node_id; // = data[8..15]
|
||||
uint8_t svc_id; // = data[16]
|
||||
uint16_t last_dgram_ts; // последний timestamp датаграммы (rx или tx, timebase 0.1ms)
|
||||
uint16_t rtt; // измеренный RTT (0.1ms)
|
||||
int32_t rtt_jitter; // EMA jitter, fixed-point *65536 (как в ETCP)
|
||||
@@ -170,11 +173,11 @@ int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn c
|
||||
int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id);
|
||||
|
||||
// Отправить сервисный пакет (авто-conn, seq, inflight-контроль через send_q)
|
||||
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_entry* entry, int force);
|
||||
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, struct ll_entry* entry, int force);
|
||||
|
||||
// Найти/создать состояние seq-подключения по (remote_node_id, svc_id)
|
||||
// Найти/создать состояние seq-подключения по (group_id, remote_node_id, svc_id)
|
||||
struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
||||
uint64_t remote_node_id, uint8_t svc_id);
|
||||
uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id);
|
||||
|
||||
// Отправить данные с авто-seq и контролем inflight
|
||||
// data: payload без svc_id, flags: битовые флаги (зарезервировано)
|
||||
@@ -200,30 +203,28 @@ void etcp_router_conn_close_async(struct ETCP_ROUTER_CONN* rconn,
|
||||
// Используется при etcp_conn_reinit чтобы избежать гонки с очисткой ETCP-очередей
|
||||
void etcp_router_pause_retrans_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id);
|
||||
|
||||
// Закрыть все router_conn для указанного remote_node_id (peer умер)
|
||||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id);
|
||||
// Закрыть все router_conn для указанного (group_id, remote_node_id) (peer умер)
|
||||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id);
|
||||
|
||||
// Возвращает количество пакетов в очереди normalizer->input для узла node_id
|
||||
int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t node_id);
|
||||
// Возвращает количество пакетов в очереди normalizer->input для узла node_id в группе group_id
|
||||
int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id);
|
||||
|
||||
// Backpressure: зарегистрировать/отменить waiter на normalizer->input очереди
|
||||
void etcp_router_waiter_register(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
|
||||
void etcp_router_waiter_register(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t peer_node_id,
|
||||
struct queue_waiter_handle* h,
|
||||
queue_threshold_callback_fn callback, void* arg);
|
||||
void etcp_router_waiter_cancel(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
|
||||
void etcp_router_waiter_cancel(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t peer_node_id,
|
||||
struct queue_waiter_handle* h);
|
||||
|
||||
// Backpressure: зарегистрировать/отменить waiter на send_q очереди
|
||||
// h — handle из структуры сервиса, callback вызывается когда send_q.count <= threshold (128)
|
||||
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
|
||||
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h,
|
||||
queue_threshold_callback_fn callback, void* arg);
|
||||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
|
||||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h);
|
||||
|
||||
// Сбросить состояние роутера для конкретного peer+svc (перезапуск удалённой стороны).
|
||||
// Очищает send_q/recv_q, уведомляет сервис через cb(NULL, entry) с remote_node_id.
|
||||
void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t remote_node_id, uint8_t svc_id);
|
||||
// Сбросить состояние роутера для конкретного peer+svc в группе (перезапуск удалённой стороны).
|
||||
void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id, uint8_t svc_id);
|
||||
|
||||
// Удалить все транзитные очереди соединения (вызывается при закрытии ETCP_CONN)
|
||||
void etcp_router_transit_queues_destroy(struct ETCP_CONN* conn);
|
||||
|
||||
@@ -144,7 +144,7 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
|
||||
} else {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to node %016llx dst=%s",
|
||||
ip_len, (unsigned long long)nq->node->node_id, ip_to_str(&addr, AF_INET).str);
|
||||
int send_err = etcp_route_send(instance, nq->node->node_id, entry, 1);
|
||||
int send_err = etcp_route_send(instance, nq->node->group_id, nq->node->node_id, entry, 1);
|
||||
if (send_err != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_route_send failed: dst=%s err=%d",
|
||||
ip_to_str(&addr, AF_INET).str, send_err);
|
||||
|
||||
@@ -38,6 +38,7 @@ static void topo_group_send_table_request(struct TOPO_GROUP* group, struct ETCP_
|
||||
if (!req) return;
|
||||
req->cmd = ETCP_ID_TOPO_ENTRY;
|
||||
req->subcmd = TOPO_SUBCMD_REQUEST_TABLE;
|
||||
req->group_id = group->group_id;
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(req); return; }
|
||||
e->dgram = (uint8_t*)req; e->len = sizeof(struct TOPOMSG_TABLE_REQ);
|
||||
@@ -50,6 +51,7 @@ static void topo_group_send_table_complete(struct TOPO_GROUP* group, struct ETCP
|
||||
if (!req) return;
|
||||
req->cmd = ETCP_ID_TOPO_ENTRY;
|
||||
req->subcmd = TOPO_SUBCMD_TABLE_COMPLETE;
|
||||
req->group_id = group->group_id;
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(req); return; }
|
||||
e->dgram = (uint8_t*)req; e->len = sizeof(struct TOPOMSG_TABLE_REQ);
|
||||
@@ -123,7 +125,7 @@ static void topo_group_broadcast_withdraw(struct TOPO_GROUP* group, uint64_t nod
|
||||
struct TOPOMSG_WITHDRAW_PKT* pkt = u_calloc(1, sizeof(struct TOPOMSG_WITHDRAW_PKT));
|
||||
if (!pkt) return;
|
||||
pkt->cmd = ETCP_ID_TOPO_ENTRY; pkt->subcmd = TOPO_SUBCMD_WITHDRAW;
|
||||
pkt->node_id = node_id; pkt->wd_source = wd_source;
|
||||
pkt->group_id = group->group_id; pkt->node_id = node_id; pkt->wd_source = wd_source;
|
||||
struct ll_entry* e = group->senders_list ? group->senders_list->head : NULL;
|
||||
while (e) {
|
||||
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)e->data;
|
||||
@@ -145,12 +147,29 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
if (!from_conn || !entry || entry->len < 2) { if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; }
|
||||
struct UTUN_INSTANCE* instance = from_conn->instance;
|
||||
if (!instance || !instance->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid instance/topo_groups"); queue_dgram_free(entry); queue_entry_free(entry); return; }
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(instance->topo_groups);
|
||||
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "no default group"); queue_dgram_free(entry); queue_entry_free(entry); return; }
|
||||
uint8_t* data = entry->dgram; uint8_t cmd = data[0]; uint8_t subcmd = data[1];
|
||||
if (cmd != ETCP_ID_TOPO_ENTRY) { queue_dgram_free(entry); queue_entry_free(entry); return; }
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP recv %s from %s len=%zu", group_subcmd_name(subcmd), from_conn->log_name, entry->len);
|
||||
uint64_t pkt_group_id = 0;
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO && entry->len >= 3) {
|
||||
pkt_group_id = ((struct TOPOMSG_NODEINFO_PKT*)data)->node.group_id;
|
||||
} else if (subcmd == TOPO_SUBCMD_WITHDRAW && entry->len >= sizeof(struct TOPOMSG_WITHDRAW_PKT)) {
|
||||
pkt_group_id = ((struct TOPOMSG_WITHDRAW_PKT*)data)->group_id;
|
||||
} else if (subcmd == TOPO_SUBCMD_REQUEST_TABLE && entry->len >= sizeof(struct TOPOMSG_TABLE_REQ)) {
|
||||
pkt_group_id = ((struct TOPOMSG_TABLE_REQ*)data)->group_id;
|
||||
} else if (subcmd == TOPO_SUBCMD_TABLE_COMPLETE && entry->len >= sizeof(struct TOPOMSG_TABLE_REQ)) {
|
||||
pkt_group_id = ((struct TOPOMSG_TABLE_REQ*)data)->group_id;
|
||||
} else if (subcmd == TOPO_SUBCMD_ERR_GROUP_MISMATCH && entry->len >= sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH)) {
|
||||
pkt_group_id = ((struct TOPOMSG_ERR_GROUP_MISMATCH*)data)->group_id;
|
||||
}
|
||||
|
||||
struct TOPO_GROUP* group = topo_groups_find(instance->topo_groups, pkt_group_id);
|
||||
if (!group) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "BGP recv %s from %s: group %016llx not found, dropping", group_subcmd_name(subcmd), from_conn->log_name, (unsigned long long)pkt_group_id);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP recv %s from %s len=%zu group=%016llx", group_subcmd_name(subcmd), from_conn->log_name, entry->len, (unsigned long long)pkt_group_id);
|
||||
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO) { nodeinfo_dump_log(data, entry->len); topo_group_process_nodeinfo(group, from_conn, data, entry->len); }
|
||||
else if (subcmd == TOPO_SUBCMD_WITHDRAW) topo_group_process_withdraw(group, from_conn, data, entry->len);
|
||||
@@ -159,8 +178,8 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
else if (subcmd == TOPO_SUBCMD_ERR_GROUP_MISMATCH) {
|
||||
if (entry->len >= sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH)) {
|
||||
struct TOPOMSG_ERR_GROUP_MISMATCH* err = (struct TOPOMSG_ERR_GROUP_MISMATCH*)data;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Group type mismatch from %s: expected_type=%u received_flags=0x%02x",
|
||||
from_conn->log_name, err->expected_type, err->received_flags);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Group mismatch from %s: expected=%u received=0x%02x group=%016llx",
|
||||
from_conn->log_name, err->expected_type, err->received_flags, (unsigned long long)err->group_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,25 +191,13 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
// Init / Destroy / New / Remove conn
|
||||
// ============================================================================
|
||||
|
||||
static void topo_group_on_conn_up(struct ETCP_CONN* conn, void* arg) {
|
||||
(void)arg;
|
||||
if (conn && conn->instance && conn->instance->topo_groups) {
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(conn->instance->topo_groups);
|
||||
if (group) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP peer UP: %s peer=%016llx", conn->log_name, (unsigned long long)conn->peer_node_id); topo_group_new_conn(group, conn); }
|
||||
}
|
||||
}
|
||||
static void topo_group_on_conn_down(struct ETCP_CONN* conn, void* arg) {
|
||||
(void)arg;
|
||||
if (conn && conn->instance && conn->instance->topo_groups) {
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(conn->instance->topo_groups);
|
||||
if (group) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP peer DOWN: %s peer=%016llx", conn->log_name, (unsigned long long)conn->peer_node_id); topo_group_remove_conn(group, conn); }
|
||||
}
|
||||
}
|
||||
static void topo_group_etcp_conn_cbk(struct ETCP_CONN* conn, void* arg) {
|
||||
(void)arg;
|
||||
if (conn && conn->instance && conn->instance->topo_groups) {
|
||||
struct TOPO_GROUP* group = topo_groups_get_default(conn->instance->topo_groups);
|
||||
if (group) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP set callbacks: %s", conn->log_name); etcp_conn_add_up_cbk(conn, topo_group_on_conn_up, group); etcp_conn_add_down_cbk(conn, topo_group_on_conn_down, group); }
|
||||
static void topo_group_conn_status(struct ETCP_CONN* conn, int status, void* arg) {
|
||||
struct TOPO_GROUPS* groups = (struct TOPO_GROUPS*)arg;
|
||||
if (!conn || !groups) return;
|
||||
struct ll_entry* fe = groups->group_list->head;
|
||||
while (fe) { struct TOPO_GROUP* g = (struct TOPO_GROUP*)fe; fe = fe->next;
|
||||
if (status == ETCP_CONN_STATUS_UP) topo_group_new_conn(g, conn);
|
||||
if (status == ETCP_CONN_STATUS_DOWN) topo_group_remove_conn(g, conn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +253,9 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
|
||||
g->group_list = queue_new(instance->ua, 16, 0, 8, "topo_groups");
|
||||
if (!g->group_list) { u_free(g); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group_list queue creation failed"); return NULL; }
|
||||
|
||||
g->node_registry = queue_new(instance->ua, TOPO_NODE_REGISTRY_HASH_SIZE, 0, 8, "node_registry");
|
||||
if (!g->node_registry) { queue_free(g->group_list); u_free(g); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node_registry queue creation failed"); return NULL; }
|
||||
|
||||
g->v4_sock_meta_pool = memory_pool_init(sizeof(struct TOPO_SOCKMETA4), "to_v4sock");
|
||||
g->v4_addr_pool = memory_pool_init(sizeof(struct TOPO_ADDR4), "to_v4addr");
|
||||
g->v6_sock_meta_pool = memory_pool_init(sizeof(struct TOPO_SOCKMETA6), "to_v6sock");
|
||||
@@ -281,14 +291,14 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
|
||||
memory_pool_destroy(g->v4_sock_meta_pool); memory_pool_destroy(g->v4_addr_pool);
|
||||
memory_pool_destroy(g->v6_sock_meta_pool); memory_pool_destroy(g->v6_addr_pool);
|
||||
memory_pool_destroy(g->v4_subnet_pool); memory_pool_destroy(g->v6_subnet_pool);
|
||||
queue_free(g->group_list); u_free(g);
|
||||
queue_free(g->node_registry); queue_free(g->group_list); u_free(g);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "failed to create default group");
|
||||
return NULL;
|
||||
}
|
||||
queue_data_put_with_index(g->group_list, &default_group->ll);
|
||||
|
||||
etcp_bind(instance, ETCP_ID_TOPO_ENTRY, topo_group_receive_cbk);
|
||||
etcp_add_new_conn_cbk(instance, topo_group_etcp_conn_cbk, NULL);
|
||||
etcp_add_conn_status_cbk(instance, topo_group_conn_status, g);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TOPO groups initialized (with default group)");
|
||||
return g;
|
||||
@@ -300,6 +310,7 @@ void topo_groups_destroy(struct UTUN_INSTANCE* instance) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_id=%016llx", (unsigned long long)instance->node_id);
|
||||
|
||||
etcp_unbind(instance, ETCP_ID_TOPO_ENTRY);
|
||||
etcp_remove_conn_status_cbk(instance, topo_group_conn_status, instance->topo_groups);
|
||||
route_connectivity_cancel_all(instance);
|
||||
|
||||
struct TOPO_GROUPS* g = instance->topo_groups;
|
||||
@@ -307,6 +318,16 @@ void topo_groups_destroy(struct UTUN_INSTANCE* instance) {
|
||||
while ((ge = queue_data_get(g->group_list)) != NULL) { struct TOPO_GROUP* grp = (struct TOPO_GROUP*)ge; topo_group_destroy(grp); queue_entry_free(ge); }
|
||||
queue_free(g->group_list);
|
||||
|
||||
if (g->node_registry) {
|
||||
struct ll_entry* re;
|
||||
while ((re = queue_data_get(g->node_registry)) != NULL) {
|
||||
struct TOPO_NODE_REG_ENTRY* r = (struct TOPO_NODE_REG_ENTRY*)re;
|
||||
topo_node_unref(r->node);
|
||||
queue_entry_free(re);
|
||||
}
|
||||
queue_free(g->node_registry);
|
||||
}
|
||||
|
||||
memory_pool_destroy(g->v4_sock_meta_pool);
|
||||
memory_pool_destroy(g->v4_addr_pool);
|
||||
memory_pool_destroy(g->v6_sock_meta_pool);
|
||||
@@ -336,6 +357,20 @@ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t grou
|
||||
if (!group) return NULL;
|
||||
if (channel_id) { strncpy(group->channel_id, channel_id, sizeof(group->channel_id) - 1); group->channel_id[sizeof(group->channel_id) - 1] = '\0'; }
|
||||
queue_data_put_with_index(g->group_list, &group->ll);
|
||||
|
||||
struct ll_queue* connections = g->instance->connections;
|
||||
if (connections) {
|
||||
for (uint32_t slot = 0; slot < connections->hash_size; slot++) {
|
||||
struct ll_entry* entry = connections->hash_table[slot];
|
||||
while (entry) {
|
||||
struct conn_queue_entry* cqe = (struct conn_queue_entry*)entry;
|
||||
if (cqe->conn && cqe->peer_node_id != 0)
|
||||
topo_group_new_conn(group, cqe->conn);
|
||||
entry = entry->hash_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Group created: group_id=%016llx type=%u ch_id=%s", (unsigned long long)group_id, group_type, group->channel_id);
|
||||
return group;
|
||||
}
|
||||
@@ -390,7 +425,7 @@ void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
struct ll_entry* entry = node_entry;
|
||||
if (entry) { queue_remove_data(group->nodes, entry); queue_entry_free(entry); }
|
||||
nodes_removed++;
|
||||
etcp_router_conn_close_all_for_node(group->instance, key);
|
||||
etcp_router_conn_close_all_for_node(group->instance, group->group_id, key);
|
||||
uint64_t wd_src = (key == conn->peer_node_id) ? conn->instance->node_id : conn->peer_node_id;
|
||||
topo_group_broadcast_withdraw(group, key, wd_src, NULL);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "Removed node %016llx after link down", (unsigned long long)key);
|
||||
@@ -468,6 +503,7 @@ static void topo_group_send_err_group_mismatch(struct TOPO_GROUP* group, struct
|
||||
struct TOPOMSG_ERR_GROUP_MISMATCH* pkt = u_calloc(1, sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH));
|
||||
if (!pkt) return;
|
||||
pkt->cmd = ETCP_ID_TOPO_ENTRY; pkt->subcmd = TOPO_SUBCMD_ERR_GROUP_MISMATCH;
|
||||
pkt->group_id = group->group_id;
|
||||
pkt->expected_type = expected_type; pkt->received_flags = received_flags;
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(pkt); return; }
|
||||
@@ -481,6 +517,12 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
struct TOPOMSG_NODEINFO_PKT* pkt = (struct TOPOMSG_NODEINFO_PKT*)data;
|
||||
struct TOPOMSG_NODE* ni = &pkt->node;
|
||||
|
||||
if (ni->group_id != group->group_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO group_id mismatch from %s: expected=%016llx got=%016llx",
|
||||
from->log_name, (unsigned long long)group->group_id, (unsigned long long)ni->group_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Проверка соответствия типа группы
|
||||
uint8_t expected_flags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS;
|
||||
if ((ni->flags & TOPO_FLAG_SEND_SUBNETS) != expected_flags) {
|
||||
@@ -538,8 +580,8 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
}
|
||||
|
||||
if (nodeinfo1) {
|
||||
nodeinfo1->node = new_ni; topo_node_ref(new_ni);
|
||||
nodeinfo1->hash_node_id = new_ni->node_id;
|
||||
nodeinfo1->node = topo_node_registry_acquire(group->instance->topo_groups, new_ni);
|
||||
nodeinfo1->hash_node_id = nodeinfo1->node ? nodeinfo1->node->node_id : 0;
|
||||
nodeinfo1->subnets = new_subnets;
|
||||
u_free(nodeinfo1->tranzit_data); nodeinfo1->tranzit_data = new_tranzit;
|
||||
nodeinfo1->tranzit_count = new_tranzit_count;
|
||||
@@ -547,11 +589,11 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
nodeinfo1->hop_count = new_hop_count;
|
||||
} else {
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_NODEQ));
|
||||
if (!qe) { topo_node_unref(new_ni); u_free(new_tranzit); u_free(new_hop_list); u_free(new_subnets); return -1; }
|
||||
if (!qe) { topo_node_free_raw(group->instance->topo_groups, new_ni); u_free(new_tranzit); u_free(new_hop_list); u_free(new_subnets); return -1; }
|
||||
nodeinfo1 = (struct TOPO_NODEQ*)qe;
|
||||
memset((uint8_t*)nodeinfo1 + sizeof(struct ll_entry), 0, sizeof(*nodeinfo1) - sizeof(struct ll_entry));
|
||||
nodeinfo1->node = new_ni; topo_node_ref(new_ni);
|
||||
nodeinfo1->hash_node_id = new_ni->node_id;
|
||||
nodeinfo1->node = topo_node_registry_acquire(group->instance->topo_groups, new_ni);
|
||||
nodeinfo1->hash_node_id = nodeinfo1->node ? nodeinfo1->node->node_id : 0;
|
||||
nodeinfo1->subnets = new_subnets;
|
||||
nodeinfo1->tranzit_data = new_tranzit; nodeinfo1->tranzit_count = new_tranzit_count;
|
||||
nodeinfo1->hop_list = new_hop_list; nodeinfo1->hop_count = new_hop_count;
|
||||
|
||||
@@ -76,16 +76,18 @@ struct TOPOMSG_NODEINFO_PKT {
|
||||
struct TOPOMSG_WITHDRAW_PKT {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t group_id; // идентификатор группы
|
||||
uint64_t node_id; // удаляемый узел (который стал недоступен)
|
||||
uint64_t wd_source; // узел который инициировал withdraw (при удалении он должен быть в hoplist или = current node_id)
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief Пакет запроса полной таблицы
|
||||
* @brief Пакет запроса полной таблицы / завершения синхронизации
|
||||
*/
|
||||
struct TOPOMSG_TABLE_REQ {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t group_id; // идентификатор группы
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
@@ -94,6 +96,7 @@ struct TOPOMSG_TABLE_REQ {
|
||||
struct TOPOMSG_ERR_GROUP_MISMATCH {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t group_id; // идентификатор группы
|
||||
uint8_t expected_type;
|
||||
uint8_t received_flags;
|
||||
} __attribute__((packed));
|
||||
@@ -105,6 +108,13 @@ struct TOPO_GROUP_CONN_ITEM {
|
||||
|
||||
struct ETCP_LINK;
|
||||
|
||||
#define TOPO_NODE_REGISTRY_HASH_SIZE 256
|
||||
|
||||
struct TOPO_NODE_REG_ENTRY {
|
||||
struct ll_entry ll; // data[0..7] = node_id (hash key)
|
||||
struct TOPO_NODE* node;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Группа топологии (одна на каждый group_id: utun, чат-группа, …)
|
||||
*/
|
||||
@@ -126,6 +136,7 @@ struct TOPO_GROUP {
|
||||
struct TOPO_GROUPS {
|
||||
struct UTUN_INSTANCE* instance;
|
||||
struct ll_queue* group_list; // ll_queue of TOPO_GROUP entries
|
||||
struct ll_queue* node_registry; // глобальный реестр TOPO_NODE* по node_id (hash=8)
|
||||
struct memory_pool* v4_sock_meta_pool;
|
||||
struct memory_pool* v4_addr_pool;
|
||||
struct memory_pool* v6_sock_meta_pool;
|
||||
|
||||
@@ -48,6 +48,18 @@ static void free_v6_sub_list(struct memory_pool* pool, struct TOPO_SUBNET6* head
|
||||
while (head) { struct TOPO_SUBNET6* next = head->next; memory_pool_free(pool, head); head = next; }
|
||||
}
|
||||
|
||||
void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
if (!ni) return;
|
||||
if (groups) {
|
||||
free_v4_sock_list(groups->v4_sock_meta_pool, ni->v4_sock_meta);
|
||||
free_v4_addr_list(groups->v4_addr_pool, ni->v4_addrs);
|
||||
free_v6_sock_list(groups->v6_sock_meta_pool, ni->v6_sock_meta);
|
||||
free_v6_addr_list(groups->v6_addr_pool, ni->v6_addrs);
|
||||
}
|
||||
u_free(ni->node_name);
|
||||
u_free(ni);
|
||||
}
|
||||
|
||||
void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq) {
|
||||
if (!group || !nq) return;
|
||||
if (nq->node) {
|
||||
@@ -57,7 +69,7 @@ void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq) {
|
||||
free_v6_addr_list(group->instance->topo_groups->v6_addr_pool, nq->node->v6_addrs);
|
||||
nq->node->v4_sock_meta = NULL; nq->node->v4_addrs = NULL;
|
||||
nq->node->v6_sock_meta = NULL; nq->node->v6_addrs = NULL;
|
||||
topo_node_unref(nq->node);
|
||||
topo_node_registry_release(group->instance->topo_groups, nq->node);
|
||||
nq->node = NULL;
|
||||
}
|
||||
if (nq->subnets) {
|
||||
@@ -70,6 +82,46 @@ void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq) {
|
||||
u_free(nq->hop_list); nq->hop_list = NULL; nq->hop_count = 0;
|
||||
}
|
||||
|
||||
// ===== глобальный реестр TOPO_NODE =====
|
||||
|
||||
static struct TOPO_NODE* node_registry_find(struct TOPO_GROUPS* groups, uint64_t node_id) {
|
||||
if (!groups || !groups->node_registry) return NULL;
|
||||
struct ll_entry* e = queue_find_data_by_index(groups->node_registry, &node_id);
|
||||
return e ? ((struct TOPO_NODE_REG_ENTRY*)e)->node : NULL;
|
||||
}
|
||||
|
||||
struct TOPO_NODE* topo_node_registry_acquire(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
if (!groups || !ni) return NULL;
|
||||
struct TOPO_NODE* existing = node_registry_find(groups, ni->node_id);
|
||||
if (existing) {
|
||||
topo_node_ref(existing);
|
||||
topo_node_free_raw(groups, ni);
|
||||
return existing;
|
||||
}
|
||||
struct ll_entry* qe = queue_entry_new(sizeof(struct TOPO_NODE_REG_ENTRY));
|
||||
if (!qe) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "registry_acquire: queue_entry_new failed for node=%016llx", (unsigned long long)ni->node_id);
|
||||
return NULL;
|
||||
}
|
||||
struct TOPO_NODE_REG_ENTRY* re = (struct TOPO_NODE_REG_ENTRY*)qe;
|
||||
re->node = ni;
|
||||
topo_node_ref(ni);
|
||||
memcpy(re->ll.data, &ni->node_id, 8);
|
||||
queue_data_put_with_index(groups->node_registry, &re->ll);
|
||||
return ni;
|
||||
}
|
||||
|
||||
void topo_node_registry_release(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
if (!groups || !ni) return;
|
||||
uint64_t node_id = ni->node_id;
|
||||
uint32_t prev_ref = ni->ref_count;
|
||||
topo_node_unref(ni);
|
||||
if (prev_ref == 1) {
|
||||
struct ll_entry* e = groups->node_registry ? queue_find_data_by_index(groups->node_registry, &node_id) : NULL;
|
||||
if (e) { queue_remove_data(groups->node_registry, e); queue_entry_free(e); }
|
||||
}
|
||||
}
|
||||
|
||||
// ===== serialization =====
|
||||
|
||||
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) {
|
||||
@@ -167,7 +219,7 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc TOPO_NODE failed"); return -1; }
|
||||
ni->ref_count = 1;
|
||||
ni->ref_count = 0;
|
||||
ni->flags = msg->flags;
|
||||
ni->group_id = msg->group_id;
|
||||
ni->node_id = msg->node_id;
|
||||
@@ -186,46 +238,46 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
for (int i = 0; i < msg->local_v4_sockets; i++) {
|
||||
const struct TOPOMSG_SOCKMETA4* w = (const struct TOPOMSG_SOCKMETA4*)dp; dp += sizeof(*w);
|
||||
struct TOPO_SOCKMETA4* e = memory_pool_alloc(group->instance->topo_groups->v4_sock_meta_pool);
|
||||
if (!e) { topo_node_unref(ni); return -1; }
|
||||
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
e->id = w->id; e->config_type = w->config_type; e->nat_type = w->nat_type;
|
||||
e->next = ni->v4_sock_meta; ni->v4_sock_meta = e;
|
||||
}
|
||||
for (int i = 0; i < msg->local_v4_addrs; i++) {
|
||||
const struct TOPOMSG_ADDR4* w = (const struct TOPOMSG_ADDR4*)dp; dp += sizeof(*w);
|
||||
struct TOPO_ADDR4* e = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool);
|
||||
if (!e) { topo_node_unref(ni); return -1; }
|
||||
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
memcpy(e->addr, w->addr, 4); e->port = w->port; e->type = w->type; e->socket_id = w->socket_id; e->protocol = w->protocol;
|
||||
e->next = ni->v4_addrs; ni->v4_addrs = e;
|
||||
}
|
||||
for (int i = 0; i < msg->local_v6_sockets; i++) {
|
||||
const struct TOPOMSG_SOCKMETA6* w = (const struct TOPOMSG_SOCKMETA6*)dp; dp += sizeof(*w);
|
||||
struct TOPO_SOCKMETA6* e = memory_pool_alloc(group->instance->topo_groups->v6_sock_meta_pool);
|
||||
if (!e) { topo_node_unref(ni); return -1; }
|
||||
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
e->id = w->id; e->config_type = w->config_type; e->nat_type = w->nat_type;
|
||||
e->next = ni->v6_sock_meta; ni->v6_sock_meta = e;
|
||||
}
|
||||
for (int i = 0; i < msg->local_v6_addrs; i++) {
|
||||
const struct TOPOMSG_ADDR6* w = (const struct TOPOMSG_ADDR6*)dp; dp += sizeof(*w);
|
||||
struct TOPO_ADDR6* e = memory_pool_alloc(group->instance->topo_groups->v6_addr_pool);
|
||||
if (!e) { topo_node_unref(ni); return -1; }
|
||||
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
memcpy(e->addr, w->addr, 16); e->port = w->port; e->type = w->type; e->socket_id = w->socket_id; e->protocol = w->protocol;
|
||||
e->next = ni->v6_addrs; ni->v6_addrs = e;
|
||||
}
|
||||
|
||||
if (out_subnets && (msg->flags & TOPO_FLAG_SEND_SUBNETS) && (msg->local_v4_subnets || msg->local_v6_subnets)) {
|
||||
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS));
|
||||
if (!r) { topo_node_unref(ni); return -1; }
|
||||
if (!r) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
for (int i = 0; i < msg->local_v4_subnets; i++) {
|
||||
const struct TOPOMSG_SUBNET4* w = (const struct TOPOMSG_SUBNET4*)dp; dp += sizeof(*w);
|
||||
struct TOPO_SUBNET4* e = memory_pool_alloc(group->instance->topo_groups->v4_subnet_pool);
|
||||
if (!e) { u_free(r); topo_node_unref(ni); return -1; }
|
||||
if (!e) { u_free(r); topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
memcpy(e->addr, w->addr, 4); e->prefix_length = w->prefix_length;
|
||||
e->next = r->v4_subnets; r->v4_subnets = e;
|
||||
}
|
||||
for (int i = 0; i < msg->local_v6_subnets; i++) {
|
||||
const struct TOPOMSG_SUBNET6* w = (const struct TOPOMSG_SUBNET6*)dp; dp += sizeof(*w);
|
||||
struct TOPO_SUBNET6* e = memory_pool_alloc(group->instance->topo_groups->v6_subnet_pool);
|
||||
if (!e) { u_free(r); topo_node_unref(ni); return -1; }
|
||||
if (!e) { u_free(r); topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
memcpy(e->addr, w->addr, 16); e->prefix_length = w->prefix_length;
|
||||
e->next = r->v6_subnets; r->v6_subnets = e;
|
||||
}
|
||||
@@ -241,14 +293,14 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
if (out_tranzit && msg->tranzit_nodes > 0) {
|
||||
size_t tsz = msg->tranzit_nodes * sizeof(struct TOPOMSG_TRANZIT);
|
||||
*out_tranzit = u_malloc(tsz);
|
||||
if (!*out_tranzit) { topo_node_unref(ni); return -1; }
|
||||
if (!*out_tranzit) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
memcpy(*out_tranzit, dp, tsz); dp += tsz;
|
||||
*out_tranzit_count = msg->tranzit_nodes;
|
||||
}
|
||||
if (out_hop_list && msg->hop_count > 0) {
|
||||
size_t hsz = msg->hop_count * 8;
|
||||
*out_hop_list = u_malloc(hsz);
|
||||
if (!*out_hop_list) { topo_node_unref(ni); return -1; }
|
||||
if (!*out_hop_list) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
memcpy(*out_hop_list, dp, hsz); dp += hsz;
|
||||
*out_hop_count = msg->hop_count;
|
||||
}
|
||||
@@ -600,7 +652,7 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
||||
if (!ni) { u_free(lq); group->local_node = NULL; return -1; }
|
||||
ni->ref_count = 1;
|
||||
ni->ref_count = 0;
|
||||
ni->flags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS;
|
||||
ni->group_id = group->group_id;
|
||||
ni->node_id = instance->node_id;
|
||||
@@ -609,7 +661,7 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
memcpy(ni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE);
|
||||
if (name_len) { ni->node_name = u_malloc(name_len + 1); if (ni->node_name) { memcpy(ni->node_name, instance->name, name_len); ni->node_name[name_len] = 0; } }
|
||||
|
||||
lq->node = ni;
|
||||
lq->node = topo_node_registry_acquire(instance->topo_groups, ni);
|
||||
lq->hash_node_id = ni->node_id;
|
||||
lq->hop_count = 0;
|
||||
lq->dirty = 1;
|
||||
|
||||
@@ -252,8 +252,20 @@ struct TOPO_NODEQ {
|
||||
|
||||
struct TOPO_NODEQ* topo_node_find_by_id(struct TOPO_GROUP* group, uint64_t node_id);
|
||||
|
||||
// Владение TOPO_NODE: создаётся с ref_count=0. Владелец вызывает topo_node_ref() чтобы завладеть.
|
||||
// При отказе от владения — topo_node_unref(). При ref_count=0 узел удаляется.
|
||||
void topo_node_ref(struct TOPO_NODE* ni);
|
||||
void topo_node_unref(struct TOPO_NODE* ni);
|
||||
|
||||
// Глобальный реестр TOPO_NODE* (по node_id). Каждый узел хранится один раз.
|
||||
// При помещении в реестр и при получении из реестра владение берётся (ref++).
|
||||
// При освобождении из реестра владение возвращается (unref, при ref=0 — удаление).
|
||||
struct TOPO_NODE* topo_node_registry_acquire(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni);
|
||||
void topo_node_registry_release(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni);
|
||||
|
||||
// Освободить узел без учёта ref_count (для ошибок после deserialize, пока ref=0).
|
||||
void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni);
|
||||
|
||||
void topo_node_free_lists(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq);
|
||||
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ extern "C" {
|
||||
#define ETCP_RT_ID_TCP_PROXY 0x04 // TCP proxy (клиент ↔ exit)
|
||||
#define ETCP_RT_ID_UDP_PROXY 0x05 // UDP datagram прокси (client ↔ exit)
|
||||
#define ETCP_RT_ID_ICMP_PROXY 0x06 // ICMP echo прокси (ping через exit)
|
||||
#define ETCP_RT_ID_MSG_TRANSPORT 0x10 // msg_transport — локальный IPC транспорт сообщений
|
||||
|
||||
#define ETCP_RT_ID_CONN_MGR 0x11 // Connection Manager — management connections
|
||||
|
||||
// Connection status events (instance-level callback)
|
||||
|
||||
@@ -63,7 +63,6 @@ etcp_set_new_conn_cbk(instance, on_new_conn, my_data);
|
||||
- `ETCP_RT_ID_TCP_PROXY` (0x04) — TCP-прокси
|
||||
- `ETCP_RT_ID_UDP_PROXY` (0x05) — UDP-прокси
|
||||
- `ETCP_RT_ID_ICMP_PROXY` (0x06) — ICMP-прокси
|
||||
- `ETCP_RT_ID_MSG_TRANSPORT` (0x10) — локальный IPC-транспорт сообщений
|
||||
- `ETCP_RT_ID_CONN_MGR` (0x11) — управление соединениями
|
||||
- `ETCP_ID_NTP_TIME` (0x04) — синхронизация времени (raw ETCP, P2P)
|
||||
|
||||
|
||||
+1
-23
@@ -16,7 +16,7 @@
|
||||
#include "db_sync.h"
|
||||
#include "stcp_server.h"
|
||||
#include "control_server.h"
|
||||
#include "msg_transport.h"
|
||||
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/sha256.h"
|
||||
@@ -399,13 +399,6 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
ntp_time_destroy(instance);
|
||||
ntp_node_time_destroy(instance);
|
||||
|
||||
// Shutdown message transport server
|
||||
if (instance->msg_t) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Shutting down message transport server");
|
||||
msg_transport_shutdown(instance->msg_t);
|
||||
instance->msg_t = NULL;
|
||||
}
|
||||
|
||||
// Shutdown control server first
|
||||
if (instance->control_srv) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Shutting down control server");
|
||||
@@ -635,21 +628,6 @@ int utun_instance_init(struct UTUN_INSTANCE *instance) {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize message transport server if configured
|
||||
if (instance->config->global.msg_transport_sock.ss_family != 0) {
|
||||
int mt_ret = msg_transport_init(&instance->msg_t, instance, instance->ua,
|
||||
&instance->config->global.msg_transport_sock,
|
||||
8, ETCP_RT_ID_MSG_TRANSPORT);
|
||||
if (mt_ret != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "Failed to initialize msg_transport, continuing without IPC transport");
|
||||
instance->msg_t = NULL;
|
||||
} else {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Message transport server initialized");
|
||||
}
|
||||
} else {
|
||||
instance->msg_t = NULL;
|
||||
}
|
||||
|
||||
// Start the main loop
|
||||
instance->running = 1;
|
||||
|
||||
|
||||
+1
-4
@@ -40,7 +40,7 @@ struct ETCP_ROUTER_BINDINGS;
|
||||
struct TOPO_GROUP;
|
||||
struct TOPO_GROUPS;
|
||||
struct control_server;
|
||||
struct msg_transport;
|
||||
|
||||
struct PING_CONTEXT;
|
||||
struct CONN_MGR;
|
||||
struct ETCP_CONNECT;
|
||||
@@ -126,9 +126,6 @@ struct UTUN_INSTANCE {
|
||||
// Control server for monitoring
|
||||
struct control_server* control_srv;
|
||||
|
||||
// Message transport server (local IPC → ETCP)
|
||||
struct msg_transport* msg_t;
|
||||
|
||||
// Firewall
|
||||
struct firewall_ctx fw;
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@ utun_instance_init(inst); // запускает всю цепочку иниц
|
||||
3. `nat_transport_init` — NAT (если включён в конфиге)
|
||||
4. `init_connections` — ETCP-сокеты, клиентские подключения, handshake
|
||||
5. `control_server_init` — сервер мониторинга (etcpmon)
|
||||
6. `msg_transport_init` — IPC-транспорт сообщений (чат, команды)
|
||||
7. `ntp_time_init` + `ntp_node_time_init` — синхронизация времени
|
||||
6. `ntp_time_init` + `ntp_node_time_init` — синхронизация времени
|
||||
|
||||
### Основной цикл
|
||||
```c
|
||||
@@ -44,7 +43,7 @@ while (inst->running) {
|
||||
utun_instance_stop(inst); // running=0, wakeup
|
||||
utun_instance_destroy(inst); // полный cleanup в обратном порядке
|
||||
```
|
||||
`destroy` гарантирует порядок: NTP→msg_transport→control→ETCP sockets→db_sync→connections→pings→TUN→tcp_proxy→routing→NAT→etcp_router→conn_mgr→BGP→fw→stcp→networks→config→pools. **uasync не уничтожается** — вызывающий код должен сам вызвать `uasync_destroy()`.
|
||||
`destroy` гарантирует порядок: NTP→control→ETCP sockets→db_sync→connections→pings→TUN→tcp_proxy→routing→NAT→etcp_router→conn_mgr→BGP→fw→stcp→networks→config→pools. **uasync не уничтожается** — вызывающий код должен сам вызвать `uasync_destroy()`.
|
||||
|
||||
### Reload (SIGHUP)
|
||||
```c
|
||||
@@ -78,7 +77,6 @@ inst = utun_instance_reload(inst, ua, "utun.conf");
|
||||
| `pkt_pool` | `struct memory_pool*` | Пул для `struct ETCP_DGRAM` |
|
||||
| `ack_pool` | `struct memory_pool*` | Пул для `struct ACK_PACKET` |
|
||||
| `control_srv` | `struct control_server*` | Сервер мониторинга (etcpmon backend) |
|
||||
| `msg_t` | `struct msg_transport*` | IPC-транспорт сообщений |
|
||||
| `fw` | `struct firewall_ctx` | Контекст файрвола |
|
||||
| `nat` / `nat_tr` | `struct eim_nat_ctx` / `nat_transport_ctx` | EIM NAT + транспорт |
|
||||
| `tcp_proxy_client` | `struct tcp_proxy_client*` | TCP-прокси клиент (опционально) |
|
||||
|
||||
Reference in new issue
Block a user