Browse Source

etcp tcp: статус-флоу как в UDP + упрощение STCP API

- etcp_link_enter_ready_tcp: убраны прямые записи got_initial_pkt/initialized/
  links_up/tx_state и fire UP/INIT; переход через etcp_conn_ready +
  loadbalancer_link_ready (как в UDP INIT-обработчиках)
- tcp_server_on_link: убран дублирующий gop/session-блок (проверка в
  etcp_link_enter_ready_tcp единообразно), sc_init_ctx перед
  sc_set_peer_public_key (фикс ctx not initialized)
- stcp_link_connect(etcp_link, addr, port) вместо config-структуры;
  stcp_conn.etcp_conn для live-чтения gop/session_id при handshake
topo_upd
evgeny 2 months ago
parent
commit
7a40a1b0a8
  1. 2
      src/transport_layer/auto_socket.c
  2. 74
      src/transport_layer/etcp_connections.c
  3. 4
      src/transport_layer/etcp_keepalive.c
  4. 2
      src/transport_layer/stcp.h
  5. 11
      src/transport_layer/stcp_client.c
  6. 1
      src/transport_layer/stcp_client.h
  7. 99
      src/transport_layer/stcp_link.c
  8. 14
      src/transport_layer/stcp_link.h
  9. 2
      tests/test_etcp_link_stress.c
  10. 16
      tests/test_stcp.c
  11. 83
      tests/test_stcp_link.c

2
src/transport_layer/auto_socket.c

@ -373,8 +373,6 @@ static struct stcp_server* create_iface_tcp_socket(struct AUTO_SOCKET* as, uint3
struct stcp_link_config scfg;
memset(&scfg, 0, sizeof(scfg));
scfg.ua = inst->ua;
scfg.my_keys = &inst->my_keys;
scfg.inst = inst;
scfg.listen_family = family;

74
src/transport_layer/etcp_connections.c

@ -56,32 +56,18 @@ void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: %s conn=%p peer=0x%016llx pubkey=%016llx",
conn ? "existing" : "NEW", (void*)conn, (unsigned long long)node_id, *(const uint64_t*)pubkey);
/* Синхронизация got_initial_pkt и session_id: если грязный/другой → сбросить */
{
uint8_t client_gop = stcp_link_get_peer_got_initial_pkt(link);
uint32_t client_sid = stcp_link_get_peer_session_id(link);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: server_gop=%d server_sid=%08x client_gop=%d client_sid=%08x conn=%p",
conn ? conn->got_initial_pkt : 0, conn ? conn->session_id : 0,
client_gop, client_sid, (void*)conn);
if (conn) {
if (conn->got_initial_pkt == 1 && client_gop == 0) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: server dirty (gop=1) client clean (gop=0) → reinit");
etcp_conn_reinit(conn, "stcp client clean");
}
if (conn->session_id != client_sid) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: session_id changed my=%08x client=%08x → reinit",
conn->session_id, client_sid);
etcp_conn_reinit(conn, "stcp session changed");
}
conn->session_id = client_sid;
}
}
if (!conn) {
conn = etcp_connection_create(inst, NULL);
if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: etcp_connection_create failed"); return; }
conn->peer_node_id = node_id;
sc_set_peer_public_key(&conn->crypto_ctx, pubkey, SC_PEER_PUBKEY_BIN);
if (sc_init_ctx(&conn->crypto_ctx, &inst->my_keys) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: sc_init_ctx failed");
etcp_connection_close(conn); return;
}
if (sc_set_peer_public_key(&conn->crypto_ctx, pubkey, SC_PEER_PUBKEY_BIN) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: sc_set_peer_public_key failed");
etcp_connection_close(conn); return;
}
etcp_update_log_name(conn);
{ struct conn_queue_entry* ce = (struct conn_queue_entry*)conn->conn_queue_entry->data; ce->peer_node_id = node_id; queue_remove_data(conn->conn_queue, conn->conn_queue_entry); queue_data_put_with_index(conn->conn_queue, conn->conn_queue_entry); }
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: new ETCP_CONN peer=0x%016llx", (unsigned long long)node_id);
@ -1062,11 +1048,9 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
link->recv_keepalive = 1;
link->last_recv_local_time = get_time_tb();
if (!link->mtu_remote) link->mtu_remote = link->mtu;
etcp->got_initial_pkt = 1;
etcp->reset_done = 1;
etcp->initialized = 1; etcp->links_up = 1; etcp->tcp_link_count++;
if (etcp->tx_state == 0) etcp->tx_state = ETCP_TX_STATE_DATA_WAIT;
etcp->tcp_link_count++;
if (link->tcp_link) { const uint8_t* ed = stcp_link_get_peer_ed25519_pubkey(link->tcp_link); if (ed) memcpy(etcp->peer_ed25519_pubkey, ed, SC_PUBKEY_SIZE); }
if (etcp->initialized == 0) etcp_conn_ready(etcp);
etcp_link_send_keepalive(link);
start_keepalive_timer(link);
loadbalancer_link_ready(link);
@ -1074,8 +1058,6 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP link %d UP (mtu=%d init=%d up=%d tcp_links=%d)",
etcp->log_name, link->local_link_id, link->mtu,
etcp->initialized, etcp->links_up, etcp->tcp_link_count);
etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_UP);
etcp_cbk_fire(etcp, ETCP_CBK_EVENT_INIT);
}
static void tcp_link_reconnect_cb(void *arg) {
@ -1085,19 +1067,10 @@ static void tcp_link_reconnect_cb(void *arg) {
if (link->tcp_reconnect_delay_ms == 0) link->tcp_reconnect_delay_ms = 1000;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP link %d reconnect attempt (delay=%ums)", link->etcp->log_name, link->local_link_id, link->tcp_reconnect_delay_ms);
uint16_t port = ntohs(((struct sockaddr_in *)&link->remote_addr)->sin_port);
struct sockaddr_storage bind_addr; const struct sockaddr_storage *laddr = NULL;
if (link->conn && link->conn->interface_addr.ss_family) {
memcpy(&bind_addr, &link->conn->interface_addr, sizeof(bind_addr));
if (bind_addr.ss_family == AF_INET6) ((struct sockaddr_in6*)&bind_addr)->sin6_port = 0;
else ((struct sockaddr_in*)&bind_addr)->sin_port = 0;
laddr = &bind_addr;
}
struct stcp_link_config tcp_cfg = {.ua = link->etcp->instance->ua, .my_keys = &link->etcp->instance->my_keys, .inst = link->etcp->instance, .peer_pubkey = link->etcp->crypto_ctx.peer_public_key,
.peer_pubkey_mode = 0, .remote_addr = &link->remote_addr, .remote_port = port, .local_addr = laddr, .got_initial_pkt = link->etcp->got_initial_pkt, .session_id = link->etcp->session_id};
struct stcp_link *sl = stcp_link_connect(&tcp_cfg);
struct stcp_link *sl = stcp_link_connect(link, &link->remote_addr, port);
if (!sl) { link->tcp_reconnect_delay_ms *= 2; if (link->tcp_reconnect_delay_ms > 30000) link->tcp_reconnect_delay_ms = 30000;
link->tcp_reconnect_timer = uasync_set_timeout(link->etcp->instance->ua, (int)(link->tcp_reconnect_delay_ms * 10), link, tcp_link_reconnect_cb, "tcp_rct"); return; }
link->tcp_link = sl; stcp_link_set_etcp_conn(sl, link->etcp); stcp_link_set_etcp_link(sl, link);
link->tcp_link = sl;
stcp_link_set_on_close(sl, tcp_link_close_cb, link);
}
@ -1106,25 +1079,9 @@ void etcp_tcp_link_start_connect(struct ETCP_LINK *link, struct sockaddr_storage
if (!link->conn) { for (struct ETCP_SOCKET *s = link->etcp->instance->etcp_sockets; s; s = s->next) { if (s->is_tcp) { link->conn = s; break; } }
if (!link->conn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] no TCP socket in instance, cannot start TCP link %d", link->etcp->log_name, link->local_link_id); return; } }
memcpy(&link->remote_addr, addr, sizeof(*addr));
struct sockaddr_storage bind_addr; const struct sockaddr_storage *laddr = NULL;
if (link->conn->interface_addr.ss_family) {
memcpy(&bind_addr, &link->conn->interface_addr, sizeof(bind_addr));
if (bind_addr.ss_family == AF_INET6) ((struct sockaddr_in6*)&bind_addr)->sin6_port = 0;
else ((struct sockaddr_in*)&bind_addr)->sin_port = 0;
laddr = &bind_addr;
}
struct stcp_link_config tcp_cfg = {
.ua = link->etcp->instance->ua,
.my_keys = &link->etcp->instance->my_keys,
.inst = link->etcp->instance,
.peer_pubkey = link->etcp->crypto_ctx.peer_public_key,
.peer_pubkey_mode = 0, .remote_addr = &link->remote_addr, .remote_port = port,
.local_addr = laddr,
.got_initial_pkt = link->etcp->got_initial_pkt,
.session_id = link->etcp->session_id};
struct stcp_link *sl = stcp_link_connect(&tcp_cfg);
struct stcp_link *sl = stcp_link_connect(link, &link->remote_addr, port);
if (!sl) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_tcp_link_start_connect: stcp_link_connect failed"); return; }
link->tcp_link = sl; stcp_link_set_etcp_conn(sl, link->etcp); stcp_link_set_etcp_link(sl, link);
link->tcp_link = sl;
if (link->is_server == 0) stcp_link_set_on_close(sl, tcp_link_close_cb, link);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP link %d → stcp_link_connect %s:%u rc=%p",
link->etcp->log_name, link->local_link_id, addr, port, (void*)sl);
@ -2380,8 +2337,7 @@ int init_sockets(struct UTUN_INSTANCE* instance) {
struct ETCP_SOCKET* ts = tcp_socket_add(instance, server);
if (!ts) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_socket_add failed for %s", server->name); fail_count++; server = server->next; continue; }
struct stcp_link_config scfg = {.ua = instance->ua, .my_keys = &instance->my_keys, .inst = instance,
.listen_family = server->ip.ss_family};
struct stcp_link_config scfg = {.inst = instance, .listen_family = server->ip.ss_family};
struct stcp_server *tsrv = stcp_server_listen(&scfg, port, tcp_server_on_link, ts);
if (!tsrv) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create TCP server for %s", server->name);

4
src/transport_layer/etcp_keepalive.c

@ -181,6 +181,10 @@ static void apply_link_ka_mode(struct ETCP_LINK* link, uint8_t mode) {
static void etcp_keepalive_send_mode_pkt(struct ETCP_LINK* link, uint8_t code, uint8_t mode) {
if (!link || !link->etcp || !link->etcp->instance) return;
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] keepalive %s send: mode=%s",
link->etcp->log_name,
code == ETCP_KEEPALIVE_REQ ? "REQ" : "RESP",
mode == KA_MODE_STANDBY ? "standby" : "normal");
struct ETCP_DGRAM* dgram = u_malloc(sizeof(struct ETCP_DGRAM) + 4);
if (!dgram) {

2
src/transport_layer/stcp.h

@ -16,6 +16,7 @@ extern "C" {
#include <stdint.h>
struct UTUN_INSTANCE;
struct ETCP_CONN;
#define STCP_MAX_MSG_SIZE 65535
#define STCP_RECV_BUF_INIT 8192
@ -55,6 +56,7 @@ struct stcp_conn {
void *socket_id;
struct UTUN_INSTANCE *inst; // для lookup ETCP_CONN при хендшейке (сервер)
struct ETCP_CONN *etcp_conn; // клиент: родительский conn для live-чтения gop/session_id при handshake
enum stcp_state state;
uint8_t is_server;

11
src/transport_layer/stcp_client.c

@ -2,6 +2,7 @@
#include "stcp_client.h"
#include "secure_channel.h"
#include "crc32.h"
#include "etcp.h"
#include "../lib/u_async.h"
#include "../lib/socket_compat.h"
#include "../lib/ll_queue.h"
@ -54,9 +55,11 @@ static void client_send_handshake(struct stcp_conn *c, const uint8_t *server_pub
memcpy(hs, salt, SC_PUBKEY_ENC_SALT_SIZE);
sc_obfuscate_pubkey(salt, server_pubkey, c->my_keys.public_key, hs + SC_PUBKEY_ENC_SALT_SIZE);
uint8_t gop = c->etcp_conn ? c->etcp_conn->got_initial_pkt : c->got_initial_pkt;
uint32_t sid = c->etcp_conn ? c->etcp_conn->session_id : c->session_id;
uint8_t plain[42]; memcpy(plain, my_ed25519, 32);
plain[32] = c->got_initial_pkt;
memcpy(plain + 33, &c->session_id, 4);
plain[32] = gop;
memcpy(plain + 33, &sid, 4);
plain[37] = (uint8_t)padding; plain[38] = (uint8_t)(padding >> 8);
plain[39] = c->device_type;
*(uint16_t*)(plain + 40) = htobe16(c->keepalive_interval);
@ -68,7 +71,7 @@ static void client_send_handshake(struct stcp_conn *c, const uint8_t *server_pub
for (int i = 0; i < padding; i++) hs[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT + i] = (uint8_t)(salt[0] ^ i);
c->state = STCP_STATE_HS_CLIENT_SENT;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: handshake sent (%zu bytes), entering HS_CLIENT_SENT", total);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: handshake sent (%zu bytes) gop=%d sid=%08x, entering HS_CLIENT_SENT", total, gop, sid);
c->send_buf = hs; c->send_len = total; c->send_offset = 0;
uasync_set_socket_write(c->ua, c->socket_id, 1);
}
@ -149,6 +152,7 @@ struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uin
struct SC_MYKEYS *keys, const uint8_t *peer_pubkey,
const uint8_t *my_ed25519_pubkey,
uint8_t got_initial_pkt, uint32_t session_id,
struct ETCP_CONN *etcp_conn,
uint8_t device_type, uint16_t keepalive_interval,
stcp_ready_cb ready_cb, void *arg,
stcp_close_cb close_cb, void *close_arg,
@ -167,6 +171,7 @@ struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uin
c->tx_cb = stcp_tx_queue_cb;
c->got_initial_pkt = got_initial_pkt;
c->session_id = session_id;
c->etcp_conn = etcp_conn;
c->device_type = device_type;
c->keepalive_interval = keepalive_interval;

1
src/transport_layer/stcp_client.h

@ -16,6 +16,7 @@ struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uin
struct SC_MYKEYS *keys, const uint8_t *peer_pubkey,
const uint8_t *my_ed25519_pubkey,
uint8_t got_initial_pkt, uint32_t session_id,
struct ETCP_CONN *etcp_conn,
uint8_t device_type, uint16_t keepalive_interval,
stcp_ready_cb ready_cb, void *arg,
stcp_close_cb close_cb, void *close_arg,

99
src/transport_layer/stcp_link.c

@ -18,16 +18,18 @@
struct stcp_server {
struct stcp_server *next; // linked list in UTUN_INSTANCE
struct stcp_server *srv; // stcp_server from stcp_server.h
struct stcp_link_config cfg;
struct UTUN_INSTANCE *inst;
stcp_server_on_link_cb on_link;
struct ETCP_SOCKET *tcp_sock;
};
struct stcp_link {
struct stcp_link_config cfg;
struct stcp_client *cli;
struct stcp_conn *conn;
struct UTUN_INSTANCE *inst; // для rx-диспатча (из etcp_conn->instance)
struct UASYNC *ua; // event loop (из inst->ua)
struct ETCP_CONN *etcp_conn; // parent ETCP_CONN (for rx dispatch / etcp_send compat)
struct ETCP_LINK *etcp_link; // owning ETCP_LINK (for etcp_conn_input pkt->link)
@ -57,7 +59,7 @@ static void link_rx_cb(struct ll_queue *q, void *arg) {
struct ll_entry *e = queue_data_get(q);
if (!e) { queue_resume_callback(q); return; }
if (link->etcp_conn && link->etcp_link && link->cfg.inst) {
if (link->etcp_conn && link->etcp_link && link->inst) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] stcp_rx: len=%u hdr=%02x%02x%02x sock=%p",
link->etcp_conn->log_name, e->len,
e->dgram && e->len>=3 ? e->dgram[0] : 0,
@ -72,7 +74,7 @@ static void link_rx_cb(struct ll_queue *q, void *arg) {
return;
}
if (e->len < 3) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_link rx too short: %u bytes", e->len); queue_dgram_free(e); queue_entry_free(e); queue_resume_callback(q); return; }
struct ETCP_DGRAM *pkt = memory_pool_alloc(link->cfg.inst->pkt_pool);
struct ETCP_DGRAM *pkt = memory_pool_alloc(link->inst->pkt_pool);
if (!pkt) { queue_dgram_free(e); queue_entry_free(e); queue_resume_callback(q); return; }
pkt->timestamp = ((uint16_t*)e->dgram)[0];
pkt->flag_up = e->dgram[2] & 1;
@ -84,7 +86,7 @@ static void link_rx_cb(struct ll_queue *q, void *arg) {
etcp_packet_decrypted(sock, pkt, link->etcp_link, e->len);
queue_dgram_free(e); queue_entry_free(e);
} else {
struct UTUN_INSTANCE *inst = link->cfg.inst;
struct UTUN_INSTANCE *inst = link->inst;
uint8_t id = (e->dgram && e->len > 0) ? e->dgram[0] : 0;
if (inst && inst->api_bindings.callbacks[id])
inst->api_bindings.callbacks[id](link->etcp_conn ? link->etcp_conn : NULL, e);
@ -112,7 +114,8 @@ static void server_accept_cb(struct stcp_conn *conn, void *arg) {
struct stcp_server *ss = (struct stcp_server *)arg;
struct stcp_link *link = u_calloc(1, sizeof(struct stcp_link));
if (!link) { stcp_conn_free(conn); return; }
link->cfg = ss->cfg;
link->inst = ss->inst;
link->ua = ss->inst->ua;
link->ready = 1;
link->conn = conn;
link->peer_got_initial_pkt = conn->peer_got_initial_pkt;
@ -158,16 +161,12 @@ static void client_ready_cb(struct stcp_conn *conn, void *arg) {
queue_set_waiter_defer(link->tx_queue, 1);
stcp_conn_set_tx_queue(conn, link->tx_queue);
if (link->cfg.remote_addr) {
{
const struct sockaddr_storage *ra = link->etcp_link ? &link->etcp_link->remote_addr : NULL;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: client handshake OK [%s] link=%d addr=%s gop=%d sid=%08x",
link->etcp_conn ? link->etcp_conn->log_name : "?",
link->etcp_link ? link->etcp_link->local_link_id : -1,
sockaddr_storage_to_str(link->cfg.remote_addr).str,
link->peer_got_initial_pkt, link->peer_session_id);
} else {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: client handshake OK [%s] link=%d addr=? gop=%d sid=%08x",
link->etcp_conn ? link->etcp_conn->log_name : "?",
link->etcp_link ? link->etcp_link->local_link_id : -1,
ra ? sockaddr_storage_to_str(ra).str : "?",
link->peer_got_initial_pkt, link->peer_session_id);
}
if (link->etcp_link) etcp_link_enter_ready_tcp(link->etcp_link);
@ -178,13 +177,14 @@ static void client_ready_cb(struct stcp_conn *conn, void *arg) {
struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t port,
stcp_server_on_link_cb on_link, struct ETCP_SOCKET *tcp_sock) {
if (!cfg || !cfg->ua || !cfg->my_keys) return NULL;
if (!cfg || !cfg->inst) return NULL;
struct stcp_server *ss = u_calloc(1, sizeof(struct stcp_server));
if (!ss) return NULL;
ss->cfg = *cfg;
ss->inst = cfg->inst;
ss->on_link = on_link;
ss->tcp_sock = tcp_sock;
ss->srv = stcp_server_create(cfg->ua, port, cfg->my_keys, cfg->inst ? cfg->inst->my_ed25519_pubkey : NULL, cfg->inst, server_accept_cb, ss, NULL, NULL, cfg->listen_family);
ss->srv = stcp_server_create(cfg->inst->ua, port, &cfg->inst->my_keys, cfg->inst->my_ed25519_pubkey,
cfg->inst, server_accept_cb, ss, NULL, NULL, cfg->listen_family);
if (!ss->srv) { u_free(ss); return NULL; }
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "port=%u", port);
return ss;
@ -196,21 +196,24 @@ void stcp_link_server_destroy(struct stcp_server *ss) {
u_free(ss);
}
struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg) {
if (!cfg || !cfg->ua || !cfg->my_keys || !cfg->peer_pubkey || !cfg->remote_addr)
struct stcp_link *stcp_link_connect(struct ETCP_LINK *etcp_link,
struct sockaddr_storage *remote_addr, uint16_t port) {
if (!etcp_link || !etcp_link->etcp || !remote_addr)
return NULL;
struct ETCP_CONN *etcp = etcp_link->etcp;
struct UTUN_INSTANCE *inst = etcp->instance;
int family = cfg->remote_addr->ss_family;
int family = remote_addr->ss_family;
char addr_str[64];
uint16_t port;
uint16_t rport = port;
if (family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *)cfg->remote_addr;
struct sockaddr_in *sa = (struct sockaddr_in *)remote_addr;
inet_ntop(AF_INET, &sa->sin_addr, addr_str, sizeof(addr_str));
port = cfg->remote_port ? cfg->remote_port : ntohs(sa->sin_port);
if (!rport) rport = ntohs(sa->sin_port);
} else if (family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)cfg->remote_addr;
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)remote_addr;
getnameinfo((struct sockaddr*)sa6, sizeof(*sa6), addr_str, sizeof(addr_str), NULL, 0, NI_NUMERICHOST);
port = cfg->remote_port ? cfg->remote_port : ntohs(sa6->sin6_port);
if (!rport) rport = ntohs(sa6->sin6_port);
} else {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_link: unsupported address family %d", family);
return NULL;
@ -218,32 +221,32 @@ struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg) {
struct stcp_link *link = u_calloc(1, sizeof(struct stcp_link));
if (!link) return NULL;
link->cfg = *cfg;
uint8_t pubkey[SC_PUBKEY_SIZE];
if (cfg->peer_pubkey_mode) {
struct secure_channel sc_tmp;
sc_init_ctx(&sc_tmp, cfg->my_keys);
if (sc_set_peer_public_key(&sc_tmp, cfg->peer_pubkey, 1) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "invalid peer pubkey hex");
u_free(link); return NULL;
}
memcpy(pubkey, sc_tmp.peer_public_key, SC_PUBKEY_SIZE);
} else {
memcpy(pubkey, cfg->peer_pubkey, SC_PUBKEY_SIZE);
link->inst = inst;
link->ua = inst->ua;
link->etcp_conn = etcp;
link->etcp_link = etcp_link;
struct sockaddr_storage bind_addr;
const struct sockaddr_storage *local_addr = NULL;
if (etcp_link->conn && etcp_link->conn->interface_addr.ss_family) {
memcpy(&bind_addr, &etcp_link->conn->interface_addr, sizeof(bind_addr));
if (bind_addr.ss_family == AF_INET6) ((struct sockaddr_in6*)&bind_addr)->sin6_port = 0;
else ((struct sockaddr_in*)&bind_addr)->sin_port = 0;
local_addr = &bind_addr;
}
link->cli = stcp_client_connect(cfg->ua, addr_str, port, cfg->my_keys, pubkey,
cfg->inst ? cfg->inst->my_ed25519_pubkey : NULL,
cfg->got_initial_pkt, cfg->session_id,
cfg->inst ? cfg->inst->client_type : 0,
cfg->inst ? cfg->inst->keepalive_interval : 200,
client_ready_cb, link, NULL, NULL, cfg->local_addr);
const uint8_t *pubkey = etcp->crypto_ctx.peer_public_key;
link->cli = stcp_client_connect(inst->ua, addr_str, rport, &inst->my_keys, pubkey,
inst->my_ed25519_pubkey,
etcp->got_initial_pkt, etcp->session_id, etcp,
inst->client_type, inst->keepalive_interval,
client_ready_cb, link, NULL, NULL, local_addr);
if (!link->cli) { u_free(link); return NULL; }
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: connecting to %s:%u pubkey=%016llx bind=%s",
addr_str, port, (unsigned long long)*(const uint64_t*)pubkey,
cfg->local_addr ? sockaddr_storage_to_str(cfg->local_addr).str : "auto");
addr_str, rport, (unsigned long long)*(const uint64_t*)pubkey,
local_addr ? sockaddr_storage_to_str(local_addr).str : "auto");
return link;
}
@ -281,13 +284,13 @@ void stcp_link_close(struct stcp_link *link) {
if (link->cli) {
struct stcp_conn *c = stcp_client_get_conn(link->cli);
if (c) {
if (c->hs_timer) { uasync_cancel_timeout(link->cfg.ua, c->hs_timer); c->hs_timer = NULL; }
if (c->hs_timer) { uasync_cancel_timeout(link->ua, c->hs_timer); c->hs_timer = NULL; }
if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) {
link->saved_rx_queue = c->rx_queue; c->rx_queue = NULL; link->conn_pre_closed = 1;
}
}
}
uasync_call_soon(link->cfg.ua, link, stcp_link_close_impl);
uasync_call_soon(link->ua, link, stcp_link_close_impl);
}
int stcp_link_send(struct stcp_link *link, const uint8_t *data, size_t len) {
@ -321,7 +324,7 @@ void stcp_link_set_etcp_link(struct stcp_link *link, struct ETCP_LINK *elink) {
}
const struct sockaddr_storage *stcp_link_get_remote_addr(struct stcp_link *link) {
return link && link->cfg.remote_addr ? link->cfg.remote_addr : NULL;
return link && link->etcp_link ? &link->etcp_link->remote_addr : NULL;
}
static struct sockaddr_storage g_peer_addr;

14
src/transport_layer/stcp_link.h

@ -22,17 +22,8 @@ struct UTUN_INSTANCE;
// ====== Link config ======
struct stcp_link_config {
struct UASYNC *ua;
struct SC_MYKEYS *my_keys; // ключи этой стороны
struct UTUN_INSTANCE *inst; // для диспатча через api_bindings
const uint8_t *peer_pubkey; // pubkey пира (клиент)
int peer_pubkey_mode; // 0=binary, 1=hex
const struct sockaddr_storage *local_addr; // локальный адрес/интерфейс для bind (клиент, NULL=авто)
const struct sockaddr_storage *remote_addr; // адрес пира (клиент)
uint16_t remote_port; // порт пира (клиент)
struct UTUN_INSTANCE *inst; // rx-диспатч + instance_find_conn; ua/my_keys/ed25519 выводятся отсюда
int listen_family; // AF_INET или AF_INET6 для сервера (0 = v4)
uint8_t got_initial_pkt; // моё значение, отправляется пиру при handshake
uint32_t session_id; // мой ETCP session_id, отправляется пиру при handshake
};
// ====== TCP server ======
@ -51,7 +42,8 @@ int stcp_server_list_count(struct UTUN_INSTANCE *inst);
// ====== TCP client link ======
struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg);
struct stcp_link *stcp_link_connect(struct ETCP_LINK *etcp_link,
struct sockaddr_storage *remote_addr, uint16_t port);
void stcp_link_close(struct stcp_link *link);
int stcp_link_send(struct stcp_link *link, const uint8_t *data, size_t len);
int stcp_link_is_ready(struct stcp_link *link);

2
tests/test_etcp_link_stress.c

@ -296,7 +296,7 @@ static int add_tcp_pair(struct ETCP_CONN* conn) {
struct ETCP_SOCKET* ts = tcp_socket_add(server_instance, &cfg);
if (!ts) { release_tcp_port(port); return -1; }
struct stcp_link_config scfg = {.ua = ua, .my_keys = &server_instance->my_keys, .inst = server_instance, .listen_family = AF_INET};
struct stcp_link_config scfg = {.inst = server_instance, .listen_family = AF_INET};
struct stcp_server* srv = stcp_server_listen(&scfg, port, (stcp_server_on_link_cb)tcp_server_on_link, ts);
if (!srv) { tcp_socket_remove(ts); release_tcp_port(port); return -1; }
stcp_server_list_add(server_instance, srv);

16
tests/test_stcp.c

@ -104,7 +104,7 @@ static int test1_sizes(void) {
uint16_t port = BASE_PORT + 1;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
size_t sizes[] = {0, 1, 16, 17, 255, 256, 1000, 65535};
int n_sizes = 8;
@ -144,7 +144,7 @@ static int test2_many(void) {
uint16_t port = BASE_PORT + 2;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
int sent = 0, ticks = 0;
while (srv.msg_count < 200 && ticks < 200) {
@ -185,7 +185,7 @@ static int test3_wrong_key(void) {
struct SC_MYKEYS rogue;
TASSERT(sc_generate_keypair(&rogue) == SC_OK);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, rogue.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, rogue.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
int ticks = 0;
while (ticks < 200) {
@ -210,7 +210,7 @@ static int test4_close(void) {
uint16_t port = BASE_PORT + 4;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
int closed = 0, ticks = 0;
while (!srv.closed && ticks < 200) {
@ -260,7 +260,7 @@ static int test5_multi(void) {
struct stcp_client *clients[NCLI] = {0};
for (int i = 0; i < NCLI; i++) {
clients[i] = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &clip[i], peer_close_cb, &clip[i], NULL);
clients[i] = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &clip[i], peer_close_cb, &clip[i], NULL);
TASSERT(clients[i]);
}
@ -309,7 +309,7 @@ static int test6_interleaved(void) {
uint16_t port = BASE_PORT + 6;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
int round = 0, ticks = 0;
while (srv.msg_count < 50 || cli.msg_count < 50) {
@ -343,7 +343,7 @@ static int test7_bulk_4mb(void) {
uint16_t port = BASE_PORT + 7;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
#define N_BULK 64
#define SZ_BULK 65535
@ -382,7 +382,7 @@ static int test8_srv_recv_close(void) {
uint16_t port = BASE_PORT + 8;
struct stcp_server *ss = stcp_server_create(ua, port, &s_keys, NULL, NULL, server_connect_cb, &srv, peer_close_cb, &srv, AF_INET); TASSERT(ss);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, 0, NULL, 0, 200, client_ready_cb, &cli, peer_close_cb, &cli, NULL); TASSERT(sc);
int ticks = 0;
while ((!srv.ready || !cli.ready) && ticks < 200) { uasync_poll(ua, 10); ticks++; }

83
tests/test_stcp_link.c

@ -1,8 +1,9 @@
// test_stcp_link.c — integration test for stcp_link API (TCP via STCP)
// test_stcp_link.c — STCP link layer: server listen/accept (slim config) + client connect (raw stcp_client)
#include "stcp_link.h"
#include "stcp_client.h"
#include "secure_channel.h"
#include "utun_instance.h"
#include "../lib/u_async.h"
#include "../lib/ll_queue.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include <stdio.h>
@ -18,88 +19,78 @@ static int test_failed = 0;
if (!(cond)) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, " FAIL: %s", #cond); test_failed = 1; return test_failed; } \
} while(0)
struct recv_ctx { uint8_t *data; size_t len, cap; int count; };
static void recv_cb(struct ll_queue *q, void *arg) {
struct recv_ctx *r = (struct recv_ctx *)arg;
struct ll_entry *e = queue_data_get(q);
if (!e) { queue_resume_callback(q); return; }
r->count++;
size_t need = r->len + e->len;
if (need > r->cap) { r->cap = need + 256; r->data = u_realloc(r->data, r->cap); }
if (e->dgram && e->len) memcpy(r->data + r->len, e->dgram, e->len);
r->len += e->len;
queue_entry_free(e);
queue_resume_callback(q);
}
static struct stcp_link *g_on_srv_link = NULL;
static void on_srv_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) {
(void)tcp_sock; g_on_srv_link = link;
}
static void on_cli_ready(struct stcp_link *link, void *arg) {
static void on_cli_ready(struct stcp_conn *conn, void *arg) {
(void)conn;
int *ready = (int *)arg;
*ready = 1;
(void)link;
}
static struct UTUN_INSTANCE *make_inst(struct UASYNC *ua, struct SC_MYKEYS *keys) {
struct UTUN_INSTANCE *inst = u_calloc(1, sizeof(struct UTUN_INSTANCE));
if (!inst) return NULL;
inst->ua = ua;
inst->my_keys = *keys;
inst->keepalive_interval = 200;
return inst;
}
static int test1_basic(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct UTUN_INSTANCE *inst = make_inst(ua, &s_keys); TASSERT(inst);
struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = NULL};
struct stcp_link_config cfg = {.inst = inst, .listen_family = AF_INET};
g_on_srv_link = NULL;
struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 1, (stcp_server_on_link_cb)on_srv_link, NULL);
struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 1, on_srv_link, NULL);
TASSERT(ss);
struct sockaddr_in raddr; memset(&raddr, 0, sizeof(raddr));
raddr.sin_family = AF_INET; raddr.sin_port = htons(BASE_PORT + 1);
raddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
struct stcp_link_config cli_cfg = {.ua = ua, .my_keys = &c_keys, .inst = NULL,
.peer_pubkey = s_keys.public_key, .remote_addr = (struct sockaddr_storage *)&raddr};
int cli_ready = 0;
struct stcp_link *cli_link = stcp_link_connect(&cli_cfg); TASSERT(cli_link);
stcp_link_set_on_ready(cli_link, on_cli_ready, &cli_ready);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", BASE_PORT + 1, &c_keys,
s_keys.public_key, NULL,
0, 0, NULL,
0, 200, on_cli_ready, &cli_ready, NULL, NULL, NULL);
TASSERT(sc);
int ticks = 0;
while ((!g_on_srv_link || !cli_ready) && ticks < 5000) { uasync_poll(ua, 10); ticks++; }
TASSERT(g_on_srv_link != NULL); TASSERT(cli_ready);
// Verify send works (no crash, data goes through TCP)
const char *msg = "hello link!";
int r = stcp_link_send(cli_link, (const uint8_t *)msg, strlen(msg));
TASSERT(r == 0);
stcp_link_close(cli_link);
stcp_client_destroy(sc);
stcp_link_close(g_on_srv_link);
stcp_link_server_destroy(ss);
u_free(inst);
uasync_destroy(ua, 1);
return 0;
}
static int test2_wrong_key(void) {
struct UASYNC *ua = uasync_create(); TASSERT(ua);
struct UTUN_INSTANCE *inst = make_inst(ua, &s_keys); TASSERT(inst);
struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = NULL};
struct stcp_link_config cfg = {.inst = inst, .listen_family = AF_INET};
g_on_srv_link = NULL;
struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 2, (stcp_server_on_link_cb)on_srv_link, NULL);
struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 2, on_srv_link, NULL);
TASSERT(ss);
struct SC_MYKEYS rogue; TASSERT(sc_generate_keypair(&rogue) == SC_OK);
struct sockaddr_in raddr; memset(&raddr, 0, sizeof(raddr));
raddr.sin_family = AF_INET; raddr.sin_port = htons(BASE_PORT + 2);
raddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
struct stcp_link_config cli_cfg = {.ua = ua, .my_keys = &c_keys, .inst = NULL,
.peer_pubkey = rogue.public_key, .remote_addr = (struct sockaddr_storage *)&raddr};
struct stcp_link *cli_link = stcp_link_connect(&cli_cfg); TASSERT(cli_link);
int cli_ready = 0;
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", BASE_PORT + 2, &c_keys,
rogue.public_key, NULL,
0, 0, NULL,
0, 200, on_cli_ready, &cli_ready, NULL, NULL, NULL);
TASSERT(sc);
int ticks = 0;
while (!g_on_srv_link && ticks < 2000) { uasync_poll(ua, 10); ticks++; }
while (ticks < 2000) { uasync_poll(ua, 10); ticks++; }
TASSERT(!g_on_srv_link); // should NOT connect with wrong key
stcp_link_close(cli_link);
stcp_client_destroy(sc);
stcp_link_server_destroy(ss);
u_free(inst);
uasync_destroy(ua, 1);
return 0;
}

Loading…
Cancel
Save