You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
638 lines
23 KiB
638 lines
23 KiB
/* |
|
* 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 "route_bgp.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, "msg_transport_init: 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, "msg_transport_init: 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, "msg_transport_init: 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 ROUTE_BGP* bgp = t->instance->bgp; |
|
if (!bgp) { |
|
send_error(client, MSG_ERR_PEER_NOT_FOUND, "BGP not initialized"); |
|
break; |
|
} |
|
struct NODEINFO_Q* nq = route_bgp_get_node(bgp, 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, "on_etcp_recv: 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, "on_etcp_recv: 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, "on_etcp_recv: 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, "on_etcp_recv: 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); |
|
}
|
|
|