Browse Source

etcp: убрать session_id из INIT/STCP handshake, симметричная эпоха reset_id

v2
evgeny 1 month ago
parent
commit
f36ad8903a
  1. 4
      src/chat/chat_status.c
  2. 30
      src/transport_layer/etcp.c
  3. 1
      src/transport_layer/etcp.h
  4. 88
      src/transport_layer/etcp_connections.c
  5. 54
      src/transport_layer/etcp_connections.h
  6. 4
      src/transport_layer/etcp_dump.c
  7. 21
      src/transport_layer/stcp.h
  8. 36
      src/transport_layer/stcp_client.c
  9. 2
      src/transport_layer/stcp_client.h
  10. 13
      src/transport_layer/stcp_link.c
  11. 1
      src/transport_layer/stcp_link.h
  12. 36
      src/transport_layer/stcp_server.c
  13. 16
      tests/test_stcp.c
  14. 12
      tests/test_stcp_link.c

4
src/chat/chat_status.c

@ -216,7 +216,7 @@ static void collect_conn_metrics(uint64_t peer_node_id) {
off += snprintf(buf + off, sizeof(buf) - off,
"=== PEER: %04llX\u2192%04llX [%s] ===\n"
"Role: %s\n"
"Status: %s Links: %d/%d Initialized: %s Session: 0x%X MTU: %d\n"
"Status: %s Links: %d/%d Initialized: %s MTU: %d\n"
"Reinit: %u Reset: %u Tx_state: %d Routing_exchange: %d\n"
"\n--- ETCP ---\n"
"RTT last/avg10: %.1f/%.1f ms Jitter: %.1f ms\n"
@ -228,7 +228,7 @@ static void collect_conn_metrics(uint64_t peer_node_id) {
(unsigned long long)(my_id & 0xFFFF), (unsigned long long)(peer_node_id & 0xFFFF), peername,
role_str,
conn->links_up ? "UP" : "DOWN", links_up_count, link_count,
conn->initialized ? "yes" : "no", conn->session_id, conn->mtu,
conn->initialized ? "yes" : "no", conn->mtu,
conn->reinit_count, conn->reset_count, conn->tx_state, conn->routing_exchange_active,
conn->rtt_last / 10.0f, conn->rtt_avg_10 / 10.0f, conn->jitter / 10.0f,
conn->bytes_sent_total, conn->retransmissions_count, conn->ack_packets_count,

30
src/transport_layer/etcp.c

@ -637,30 +637,20 @@ void etcp_conn_reinit_id(struct ETCP_CONN* etcp, const char* reason, uint64_t re
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "end");
}
// Применение чужого reset_id (эпохи ресета пира).
// Если id отличается от уже виденного — пир сделал новый ресет.
// slave (больший node_id) принимает эпоху пира и ресетится; master сохраняет свою.
// Применение чужого reset_id (эпохи ресета пира). Симметрично:
// если uid пира изменился — сбрасываем своё состояние (свой uid сохраняем).
void etcp_conn_apply_peer_reset_id(struct ETCP_CONN* conn, uint64_t peer_id, uint64_t peer_reset_id) {
if (!conn) return;
int first_time = (conn->peer_reset_id == 0);
if (peer_reset_id == conn->peer_reset_id) return; // ретрансмиссия известного ресета
if (peer_reset_id == conn->peer_reset_id) return; // uid пира не изменился
conn->peer_reset_id = peer_reset_id;
if (peer_reset_id == conn->reset_id) return; // уже в одной эпохе
int i_am_master = conn->instance && conn->instance->node_id < peer_id;
if (first_time) {
// первый обмен: принимаем id как есть БЕЗ ресета (мы уже свежие при init)
if (!i_am_master) conn->reset_id = peer_reset_id; // slave принимает id мастера
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] first peer reset id=%016llx (no reset)", conn->log_name, (unsigned long long)peer_reset_id);
return;
}
if (i_am_master) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] peer reset id=%016llx != mine=%016llx — I'm master, keeping my id",
conn->log_name, (unsigned long long)peer_reset_id, (unsigned long long)conn->reset_id);
return;
if (conn->got_initial_pkt) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] peer reset id changed to %016llx — resetting self",
conn->log_name, (unsigned long long)peer_reset_id);
etcp_conn_reinit(conn, "peer reset epoch");
} else {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] peer reset id=%016llx (clean, no reset)",
conn->log_name, (unsigned long long)peer_reset_id);
}
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] peer reset id=%016llx != mine=%016llx — slave adopts and re-resets",
conn->log_name, (unsigned long long)peer_reset_id, (unsigned long long)conn->reset_id);
etcp_conn_reinit_id(conn, "peer reset epoch", peer_reset_id);
}
// внутренняя функция. Вызывается один раз когда первый линк готов.

1
src/transport_layer/etcp.h

@ -192,7 +192,6 @@ struct ETCP_CONN {
uint8_t routing_exchange_active; // 0-не активен, 1-надо инициировать (клиент), 2-обмен идёт, 3-завершён, 4-пропущен (нет BGP)
uint8_t got_initial_pkt; //
uint8_t initialized; // 0 - только созданный ETCP, 1 - хотя бы один линк проинициалзирован (обмен ключами произведен)
uint32_t session_id; // случайный ID сессии (генерируется клиентом) для защиты от ложного reinit
uint64_t reset_id; // метка эпохи ресета (генерируется при локальном ресете, master авторитет)
uint64_t peer_reset_id; // последняя увиденная эпоха ресета пира
uint8_t tx_state; // 0 - n/a, 1 - data_wait (queues empty), 2 - link_wait (link busy)

88
src/transport_layer/etcp_connections.c

@ -160,7 +160,6 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
struct ETCP_INIT_REQUEST_PKT* req = (struct ETCP_INIT_REQUEST_PKT*)dgram->data;
req->code = reset ? ETCP_INIT_REQUEST : ETCP_INIT_REQUEST_NOINIT;
*(uint64_t*)req->node_id = htobe64(link->etcp->instance->node_id);
*(uint32_t*)req->session_id = htobe32(link->etcp->session_id);
*(uint64_t*)req->reset_id = htobe64(link->etcp->reset_id);
*(uint16_t*)req->mtu = htobe16(link->mtu_local);
*(uint16_t*)req->keepalive = htobe16(link->etcp->instance->keepalive_interval);
@ -423,6 +422,19 @@ static void etcp_link_update_remote_addr(struct ETCP_LINK* link, struct ETCP_SOC
link->etcp->log_name, sockaddr_storage_to_str(new_addr).str);
}
/* Выбор линка для отправки collision INIT: outbound-линк (is_server==0), чей remote_addr
* совпадает с адресом пришедшего INIT (симметричный сокет). NULL — симметричного сокета
* нет (асимметрия/NAT) → коллизия не срабатывает, inbound принимается как есть. */
struct ETCP_LINK* etcp_select_collision_link(struct ETCP_CONN* conn, const struct sockaddr_storage* addr) {
if (!conn || !addr) return NULL;
struct ETCP_LINK* l = conn->links;
while (l) {
if (l->is_server == 0 && sockaddr_equal(&l->remote_addr, addr)) return l;
l = l->next;
}
return NULL;
}
struct ETCP_LINK* etcp_link_find_by_remote_id(struct ETCP_CONN* conn, uint8_t remote_link_id) {
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "");
if (!conn || remote_link_id == 0) return NULL;
@ -1059,19 +1071,12 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
/* Синхронизация got_initial_pkt: если я грязный (1) а пир чистый (0) → сбросить */
if (link->tcp_link) {
uint8_t peer_gop = stcp_link_get_peer_got_initial_pkt(link->tcp_link);
uint32_t peer_sid = stcp_link_get_peer_session_id(link->tcp_link);
uint64_t peer_rid = stcp_link_get_peer_reset_id(link->tcp_link);
if (etcp->got_initial_pkt == 1 && peer_gop == 0 && peer_rid != etcp->reset_id) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP ready: I'm dirty (gop=1) but peer clean (gop=0) → reinit",
etcp->log_name);
etcp_conn_reinit(etcp, "tcp peer clean");
}
if (etcp->session_id != peer_sid) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP ready: session_id mismatch my=%08x peer=%08x → reinit",
etcp->log_name, etcp->session_id, peer_sid);
etcp_conn_reinit(etcp, "tcp session changed");
}
etcp->session_id = peer_sid;
etcp_conn_apply_peer_reset_id(etcp, etcp->peer_node_id, peer_rid);
link->peer_device_type = stcp_link_get_peer_device_type(link->tcp_link);
@ -1612,7 +1617,6 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
resp->code = ETCP_INIT_RESPONSE_NOINIT; // 0x05 - without reset
}
*(uint64_t*)resp->node_id = htobe64(e_sock->instance->node_id);
*(uint32_t*)resp->session_id = htobe32(conn->session_id);
*(uint64_t*)resp->reset_id = htobe64(conn->reset_id);
resp->mtu[0]=link->mtu_local>>8;
@ -1747,16 +1751,8 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
// ETCP_INIT_RESPONSE_NOINIT (0x05) - no reset
struct ETCP_INIT_RESPONSE_PKT* resp = (struct ETCP_INIT_RESPONSE_PKT*)pkt->data;
uint64_t server_node_id = be64toh(*(uint64_t*)resp->node_id);
uint32_t resp_session_id = be32toh(*(uint32_t*)resp->session_id);
uint64_t resp_reset_id = be64toh(*(uint64_t*)resp->reset_id);
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "INIT_RESPONSE session_id=%08x rid=%016llx", resp_session_id, (unsigned long long)resp_reset_id);
// Check session_id: ignore response if it doesn't match our session
if (resp_session_id != link->etcp->session_id) {
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] INIT_RESPONSE session_id mismatch: got %08x, expected %08x, ignoring",
link->etcp->log_name, resp_session_id, link->etcp->session_id);
memory_pool_free(e_sock->instance->pkt_pool, pkt);
return 0;
}
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "INIT_RESPONSE rid=%016llx", (unsigned long long)resp_reset_id);
etcp_conn_apply_peer_reset_id(link->etcp, server_node_id, resp_reset_id);
link->mtu_remote = be16toh(*(uint16_t*)resp->mtu);
if (link->mtu_remote > PACKET_DATA_MAX_MTU) link->mtu_remote = PACKET_DATA_MAX_MTU;
@ -1766,7 +1762,7 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
link->remote_socket_id = resp->remote_socket_id;
link->remote_only_local = resp->only_local;
link->remote_type = resp->type;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] INIT_RESPONSE received (link=%d, mtu=%d, session=%08x)", link->etcp->log_name, link->remote_link_id, link->mtu, resp_session_id);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] INIT_RESPONSE received (link=%d, mtu=%d, rid=%016llx)", link->etcp->log_name, link->remote_link_id, link->mtu, (unsigned long long)resp_reset_id);
// Parse NAT IP:port from response (new format includes 4+2 bytes)
if (pkt_len >= ETCP_INIT_RESP_SIZE) {
@ -1837,12 +1833,6 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
link->init_timer = NULL;
}
if (pkt_code == ETCP_INIT_RESPONSE && link->etcp->got_initial_pkt) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] REINIT from client: INIT_RESPONSE(0x03) received, reinit conn=%p",
link->etcp->log_name, (void*)link->etcp);
etcp_conn_reinit(link->etcp, "server requested");
}
if (link->etcp->initialized == 0) {
etcp_conn_ready(link->etcp);
}
@ -2058,13 +2048,12 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct ETCP_INIT_REQUEST_PKT* req = (struct ETCP_INIT_REQUEST_PKT*)pkt->data;
peer_id = be64toh(*(uint64_t*)req->node_id);
uint32_t session_id = be32toh(*(uint32_t*)req->session_id);
uint64_t reset_id = be64toh(*(uint64_t*)req->reset_id);
uint16_t mtu = be16toh(*(uint16_t*)req->mtu);
uint16_t src_port = be16toh(*(uint16_t*)req->src_port);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "INIT received: peer=0x%016llx mtu=%u link=%u sock=%u session=%08x rid=%016llx src=%s",
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "INIT received: peer=0x%016llx mtu=%u link=%u sock=%u rid=%016llx src=%s",
(unsigned long long)peer_id, mtu, req->link_id, req->socket_id,
session_id, (unsigned long long)reset_id, sockaddr_storage_to_str(&addr).str);
(unsigned long long)reset_id, sockaddr_storage_to_str(&addr).str);
struct ETCP_CONN* conn = NULL;
{
@ -2119,12 +2108,6 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
}// коллизия - peer id совпал а ключи разные.
}
// Синхронизация эпохи ресета (для нового conn — просто принять эпоху пира)
if (new_conn) {
conn->reset_id = reset_id;
conn->peer_reset_id = reset_id;
}
if (conn->fin_wait) {
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] received INIT during fin_wait, clearing", conn->log_name);
conn->fin_wait = 0;
@ -2213,14 +2196,11 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
if (req->collision) {
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] INIT collision=1 from peer=%016llx — remote is master, becoming slave",
conn->log_name, (unsigned long long)peer_id);
conn->session_id = session_id;
etcp_conn_reinit(conn, "collision yield");
send_reset = 1;
} else {
// Check if WE have an outbound (master) link on this conn
struct ETCP_LINK* ml = conn->links;
while (ml) { if (ml->is_server == 0) break; ml = ml->next; }
int yielding = 0;
struct ETCP_LINK* ml = etcp_select_collision_link(conn, &addr);
if (ml) {
if (conn->instance->node_id < peer_id) {
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: we=master node_id=%016llx < peer=%016llx — sending collision INIT",
@ -2231,23 +2211,19 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
}
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: peer smaller, yielding master, processing as slave",
conn->log_name);
yielding = 1;
if (ml->init_timer) { uasync_cancel_timeout(conn->instance->ua, ml->init_timer); ml->init_timer = NULL; }
}
/* Sync session_id; reset only if remote session changed */
{ int sess_changed = (conn->session_id != session_id);
conn->session_id = session_id;
if (req->code == ETCP_INIT_REQUEST) {
if (sess_changed || conn->got_initial_pkt) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] INIT_REQUEST on existing link: code=0x%02x sess_ch=%d got_init=%d → reinit",
conn->log_name, req->code, sess_changed, conn->got_initial_pkt);
if (conn->got_initial_pkt) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] INIT_REQUEST on existing link: code=0x%02x got_init=%d → reinit",
conn->log_name, req->code, conn->got_initial_pkt);
etcp_conn_reinit(conn, "duplicate INIT");
}
send_reset = 0;
} else {
if (conn->got_initial_pkt == 0) send_reset = 1;
} }
}
}
// Cancel existing timers
@ -2270,13 +2246,11 @@ create_new_link:
if (req->collision) {
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] INIT collision=1 from peer=%016llx — remote is master, becoming slave",
conn->log_name, (unsigned long long)peer_id);
conn->session_id = session_id;
etcp_conn_reinit(conn, "collision yield");
send_reset = 1;
} else {
// Check if WE have an outbound (master) link
struct ETCP_LINK* ml = conn->links;
while (ml) { if (ml->is_server == 0) break; ml = ml->next; }
struct ETCP_LINK* ml = etcp_select_collision_link(conn, &addr);
if (ml && conn->instance->node_id < peer_id) {
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: we=master node_id=%016llx < peer=%016llx — sending collision INIT",
conn->log_name, (unsigned long long)conn->instance->node_id, (unsigned long long)peer_id);
@ -2285,17 +2259,7 @@ create_new_link:
return;
}
// Always sync session_id; reset only if remote session changed
{ int sess_changed = (conn->session_id != session_id);
conn->session_id = session_id;
if (sess_changed) {
send_reset = 1;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] REINIT new link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d",
conn->log_name, code, conn->session_id, session_id, conn->got_initial_pkt, conn->initialized, conn->links_up);
etcp_conn_reinit(conn, "session changed");
} else if (conn->got_initial_pkt == 0) {
send_reset = 1;
} }
if (conn->got_initial_pkt == 0) send_reset = 1;
}
uint16_t client_ka = (req->keepalive[0]<<8) | req->keepalive[1];
link->peer_device_type = req->device_type;
@ -2315,8 +2279,8 @@ create_new_link:
memcpy(conn->peer_ed25519_pubkey, req->ed25519_pubkey, SC_PUBKEY_SIZE);
// Применяем эпоху ресета пира ПОСЛЕ всей reinit-логики (adopt должен быть финальным словом)
if (!new_conn) etcp_conn_apply_peer_reset_id(conn, peer_id, reset_id);
// Применяем эпоху ресета пира ПОСЛЕ всей reinit-логики
etcp_conn_apply_peer_reset_id(conn, peer_id, reset_id);
send_init_response(e_sock, pkt, link, conn, req, &addr, send_reset, req_src_ip, req_src_port, pkt_len);
return;

54
src/transport_layer/etcp_connections.h

@ -73,22 +73,21 @@ struct ETCP_DGRAM {// пакет (незашифрованный)
struct ETCP_INIT_REQUEST_PKT {
uint8_t code; // 0: ETCP_INIT_REQUEST (0x02) или ETCP_INIT_REQUEST_NOINIT (0x04)
uint8_t node_id[8]; // 1: sender node_id (big-endian)
uint8_t session_id[4]; // 9: session (big-endian)
uint8_t reset_id[8]; // 13: reset epoch id (big-endian)
uint8_t mtu[2]; // 21: client MTU (big-endian)
uint8_t keepalive[2]; // 23: keepalive interval (big-endian)
uint8_t recovery[2]; // 25: recovery interval/100 (big-endian)
uint8_t link_id; // 27: client's local link id
uint8_t socket_id; // 28: client's socket id
uint8_t only_local; // 29: client only_local flag
uint8_t type; // 30: client socket type (CFG_SERVER_TYPE_*)
uint8_t reset_id[8]; // 9: reset epoch id (big-endian)
uint8_t mtu[2]; // 17: client MTU (big-endian)
uint8_t keepalive[2]; // 19: keepalive interval (big-endian)
uint8_t recovery[2]; // 21: recovery interval/100 (big-endian)
uint8_t link_id; // 23: client's local link id
uint8_t socket_id; // 24: client's socket id
uint8_t only_local; // 25: client only_local flag
uint8_t type; // 26: client socket type (CFG_SERVER_TYPE_*)
// V2 fields (NAT_DIRECT detection):
uint8_t src_ipv4[4]; // 31: client interface_addr IPv4 (big-endian, 0 if N/A)
uint8_t src_port[2]; // 35: client interface_addr port (big-endian)
uint8_t collision; // 37: 1 = cross-connect, remote claims master
uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 38: client Ed25519 pubkey (32 bytes)
uint8_t src_ipv4[4]; // 27: client interface_addr IPv4 (big-endian, 0 if N/A)
uint8_t src_port[2]; // 31: client interface_addr port (big-endian)
uint8_t collision; // 33: 1 = cross-connect, remote claims master
uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 34: client Ed25519 pubkey (32 bytes)
// V4 fields:
uint8_t device_type; // 70: CLIENT_TYPE_SERVER/DESKTOP/MOBILE
uint8_t device_type; // 66: CLIENT_TYPE_SERVER/DESKTOP/MOBILE
} __attribute__((packed));
#define ETCP_INIT_REQ_SIZE sizeof(struct ETCP_INIT_REQUEST_PKT)
@ -96,21 +95,20 @@ struct ETCP_INIT_REQUEST_PKT {
struct ETCP_INIT_RESPONSE_PKT {
uint8_t code; // 0: ETCP_INIT_RESPONSE (0x03) или ETCP_INIT_RESPONSE_NOINIT (0x05)
uint8_t node_id[8]; // 1: server node_id (big-endian)
uint8_t session_id[4]; // 9: session (big-endian)
uint8_t reset_id[8]; // 13: reset epoch id (big-endian)
uint8_t mtu[2]; // 21: server MTU (big-endian)
uint8_t link_id; // 23: server's local link id
uint8_t remote_socket_id; // 24: echo of client's socket_id
uint8_t only_local; // 25: server only_local flag
uint8_t type; // 26: server socket type (CFG_SERVER_TYPE_*)
uint8_t reset_id[8]; // 9: reset epoch id (big-endian)
uint8_t mtu[2]; // 17: server MTU (big-endian)
uint8_t link_id; // 19: server's local link id
uint8_t remote_socket_id; // 20: echo of client's socket_id
uint8_t only_local; // 21: server only_local flag
uint8_t type; // 22: server socket type (CFG_SERVER_TYPE_*)
// V2 fields:
uint8_t peer_ipv4[4]; // 27: client's external NAT address (big-endian)
uint8_t peer_port[2]; // 31: client's external NAT port (big-endian)
uint8_t peer_ipv4[4]; // 23: client's external NAT address (big-endian)
uint8_t peer_port[2]; // 27: client's external NAT port (big-endian)
// V3 fields:
uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 33: server Ed25519 pubkey (32 bytes)
uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 29: server Ed25519 pubkey (32 bytes)
// V4 fields:
uint8_t device_type; // 65: CLIENT_TYPE_SERVER/DESKTOP/MOBILE
uint8_t keepalive[2]; // 66: server keepalive interval (big-endian)
uint8_t device_type; // 61: CLIENT_TYPE_SERVER/DESKTOP/MOBILE
uint8_t keepalive[2]; // 62: server keepalive interval (big-endian)
} __attribute__((packed));
#define ETCP_INIT_RESP_SIZE sizeof(struct ETCP_INIT_RESPONSE_PKT)
@ -372,6 +370,10 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram);// зашифровывает и
// find link by address
struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr, int is_tcp);
// Выбор линка для collision INIT: outbound-линк (is_server==0), чей remote_addr совпадает
// с адресом пришедшего INIT (симметричный сокет). NULL — симметричного сокета нет.
struct ETCP_LINK* etcp_select_collision_link(struct ETCP_CONN* conn, const struct sockaddr_storage* addr);
// find free local_link_id for connection
// scans all links in connection, marks used ids in bit array
// returns first free id (0-255) or -1 if all occupied

4
src/transport_layer/etcp_dump.c

@ -56,9 +56,9 @@ void etcp_dump_conn_state(struct ETCP_CONN* conn) {
DHDR("=== ETCP CONN [%s] ===", conn->log_name);
DLOG("GENERAL: peer=0x%016llx state=%d init=%d l_up=%d tx=%d sess=0x%08x mtu=%d rout_ex=%d",
DLOG("GENERAL: peer=0x%016llx state=%d init=%d l_up=%d tx=%d mtu=%d rout_ex=%d",
(unsigned long long)conn->peer_node_id, conn->state, conn->initialized, conn->links_up,
conn->tx_state, conn->session_id, conn->mtu, conn->routing_exchange_active);
conn->tx_state, conn->mtu, conn->routing_exchange_active);
DLOG("IDS: next_tx=%u last_rx=%u last_del=%u rx_ack_till=%u got_init=%d reset_done=%d",
conn->next_tx_id, conn->last_rx_id, conn->last_delivered_id, conn->rx_ack_till,

21
src/transport_layer/stcp.h

@ -30,19 +30,18 @@ typedef void (*stcp_ping_cb)(int success, uint16_t rtt, void *arg);
#define STCP_HS_CLIENT_MIN (SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT) // 40+55=95
#define STCP_HS_SERVER_MIN (SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_SERVER) // 40+55=95
#define STCP_HS_ENC_CLIENT 55 // ed25519_pubkey(32) + got_initial_pkt(1) + session_id(4) + reset_id(8) + padding_size(2) + device_type(1) + keepalive(2) + flags(1) + CRC32(4)
#define STCP_HS_ENC_SERVER 55 // ed25519_pubkey(32) + got_initial_pkt(1) + session_id(4) + reset_id(8) + padding_size(2) + device_type(1) + keepalive(2) + flags(1) + CRC32(4)
#define STCP_HS_ENC_CLIENT 51 // ed25519_pubkey(32) + got_initial_pkt(1) + reset_id(8) + padding_size(2) + device_type(1) + keepalive(2) + flags(1) + CRC32(4)
#define STCP_HS_ENC_SERVER 51 // ed25519_pubkey(32) + got_initial_pkt(1) + reset_id(8) + padding_size(2) + device_type(1) + keepalive(2) + flags(1) + CRC32(4)
// handshake plain layout (before CRC):
// [0..31] ed25519_pubkey
// [32] got_initial_pkt
// [33..36] session_id
// [37..44] reset_id (epoch)
// [45..46] padding_size
// [47] device_type
// [48..49] keepalive_interval
// [50] flags
#define STCP_HS_PLAIN_SIZE 51 // без CRC32
// [33..40] reset_id (epoch)
// [41..42] padding_size
// [43] device_type
// [44..45] keepalive_interval
// [46] flags
#define STCP_HS_PLAIN_SIZE 47 // без CRC32
#define STCP_HANDSHAKE_FLAG_PING 0x01
@ -73,7 +72,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
struct ETCP_CONN *etcp_conn; // клиент: родительский conn для live-чтения gop/reset_id при handshake
enum stcp_state state;
uint8_t is_server;
@ -93,8 +92,6 @@ struct stcp_conn {
uint8_t got_initial_pkt; // local, sent to peer during handshake
uint8_t peer_got_initial_pkt; // remote, received from peer during handshake
uint32_t session_id; // local, sent to peer during handshake
uint32_t peer_session_id; // remote, received from peer during handshake
uint64_t reset_id; // local, sent to peer during handshake (reset epoch)
uint64_t peer_reset_id; // remote, received from peer during handshake
uint8_t device_type; // CLIENT_TYPE_* sent to peer during handshake

36
src/transport_layer/stcp_client.c

@ -64,26 +64,24 @@ static void client_send_handshake(struct stcp_conn *c, const uint8_t *server_pub
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;
uint64_t rid = c->etcp_conn ? c->etcp_conn->reset_id : c->reset_id;
uint8_t plain[STCP_HS_PLAIN_SIZE]; memcpy(plain, my_ed25519, 32);
plain[32] = gop;
memcpy(plain + 33, &sid, 4);
{ uint64_t rid_be = htobe64(rid); memcpy(plain + 37, &rid_be, 8); }
plain[45] = (uint8_t)padding; plain[46] = (uint8_t)(padding >> 8);
plain[47] = c->device_type;
*(uint16_t*)(plain + 48) = htobe16(c->keepalive_interval);
plain[50] = c->hs_flags;
{ uint64_t rid_be = htobe64(rid); memcpy(plain + 33, &rid_be, 8); }
plain[41] = (uint8_t)padding; plain[42] = (uint8_t)(padding >> 8);
plain[43] = c->device_type;
*(uint16_t*)(plain + 44) = htobe16(c->keepalive_interval);
plain[46] = c->hs_flags;
uint32_t crc = crc32_calc(plain, STCP_HS_PLAIN_SIZE);
uint8_t *enc_dst = hs + SC_PUBKEY_ENC_SIZE;
memcpy(enc_dst, plain, STCP_HS_PLAIN_SIZE);
enc_dst[51] = (uint8_t)(crc >> 0); enc_dst[52] = (uint8_t)(crc >> 8); enc_dst[53] = (uint8_t)(crc >> 16); enc_dst[54] = (uint8_t)(crc >> 24);
enc_dst[47] = (uint8_t)(crc >> 0); enc_dst[48] = (uint8_t)(crc >> 8); enc_dst[49] = (uint8_t)(crc >> 16); enc_dst[50] = (uint8_t)(crc >> 24);
if (sc_stream_xor(&c->stream_send, enc_dst, STCP_HS_ENC_CLIENT) != SC_OK) { u_free(hs); stcp_conn_do_close(c, 2); return; }
for (int i = 0; i < padding; i++) hs[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT + i] = (uint8_t)(salt[0] ^ i);
c->hs_send_time = get_time_tb();
c->state = STCP_STATE_HS_CLIENT_SENT;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: handshake sent (%zu bytes) gop=%d sid=%08x flags=%02x, entering HS_CLIENT_SENT", total, gop, sid, c->hs_flags);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: handshake sent (%zu bytes) gop=%d rid=%016llx flags=%02x, entering HS_CLIENT_SENT", total, gop, (unsigned long long)rid, c->hs_flags);
c->send_buf = hs; c->send_len = total; c->send_offset = 0;
uasync_set_socket_write(c->ua, c->socket_id, 1);
}
@ -109,14 +107,13 @@ static void client_hs_cb(struct stcp_conn *c, uint8_t *data, size_t len) {
log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_client enc_hs AFTER xor", enc_hs, STCP_HS_ENC_SERVER);
memcpy(c->peer_ed25519_pubkey, enc_hs, SC_PUBKEY_SIZE); c->peer_ed25519_set = 1;
c->peer_got_initial_pkt = enc_hs[32];
memcpy(&c->peer_session_id, enc_hs + 33, 4);
{ uint64_t rid_be; memcpy(&rid_be, enc_hs + 37, 8); c->peer_reset_id = be64toh(rid_be); }
uint16_t padding_size = (uint16_t)enc_hs[45] | ((uint16_t)enc_hs[46] << 8);
c->peer_device_type = enc_hs[47];
c->peer_keepalive_interval = ((uint16_t)enc_hs[48] << 8) | enc_hs[49];
c->peer_flags = enc_hs[50];
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: server response OK gop=%d sid=%08x rid=%016llx padding=%u dev=%d ka=%u flags=%02x",
c->peer_got_initial_pkt, c->peer_session_id, (unsigned long long)c->peer_reset_id, padding_size, c->peer_device_type, c->peer_keepalive_interval, c->peer_flags);
{ uint64_t rid_be; memcpy(&rid_be, enc_hs + 33, 8); c->peer_reset_id = be64toh(rid_be); }
uint16_t padding_size = (uint16_t)enc_hs[41] | ((uint16_t)enc_hs[42] << 8);
c->peer_device_type = enc_hs[43];
c->peer_keepalive_interval = ((uint16_t)enc_hs[44] << 8) | enc_hs[45];
c->peer_flags = enc_hs[46];
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: server response OK gop=%d rid=%016llx padding=%u dev=%d ka=%u flags=%02x",
c->peer_got_initial_pkt, (unsigned long long)c->peer_reset_id, padding_size, c->peer_device_type, c->peer_keepalive_interval, c->peer_flags);
stcp_recv_set(c, padding_size, 0, client_hs_padding_cb);
}
@ -219,7 +216,7 @@ static void client_connect_write_cb(socket_t sock, void *arg) {
struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uint16_t port,
struct SC_MYKEYS *keys, const uint8_t *peer_pubkey,
const uint8_t *my_ed25519_pubkey,
uint8_t got_initial_pkt, uint32_t session_id,
uint8_t got_initial_pkt,
struct ETCP_CONN *etcp_conn,
uint8_t device_type, uint16_t keepalive_interval,
uint8_t hs_flags,
@ -244,7 +241,6 @@ struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uin
c->on_write_error = stcp_conn_do_close;
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;
@ -315,7 +311,7 @@ struct stcp_client *stcp_ping_send(struct UASYNC *ua, const char *addr, uint16_t
uint8_t device_type, uint16_t keepalive_interval,
int timeout_ms, stcp_ping_cb cb, void *arg) {
struct stcp_client *cli = stcp_client_connect(ua, addr, port, keys, peer_pubkey, my_ed25519_pubkey,
0, 0, NULL, device_type, keepalive_interval,
0, NULL, device_type, keepalive_interval,
STCP_HANDSHAKE_FLAG_PING,
NULL, NULL, cb, arg, ping_close_cb, NULL, NULL, timeout_ms, NULL);
if (cli) cli->conn.free_on_close = cli;

2
src/transport_layer/stcp_client.h

@ -15,7 +15,7 @@ typedef void (*stcp_close_cb)(struct stcp_conn *conn, int err, void *arg);
struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uint16_t port,
struct SC_MYKEYS *keys, const uint8_t *peer_pubkey,
const uint8_t *my_ed25519_pubkey,
uint8_t got_initial_pkt, uint32_t session_id,
uint8_t got_initial_pkt,
struct ETCP_CONN *etcp_conn,
uint8_t device_type, uint16_t keepalive_interval,
uint8_t hs_flags,

13
src/transport_layer/stcp_link.c

@ -47,7 +47,6 @@ struct stcp_link {
uint8_t conn_pre_closed; // 1 = conn already CLOSED before stcp_link_close
uint8_t peer_got_initial_pkt; // received from peer during handshake
uint32_t peer_session_id; // received from peer during handshake
uint64_t peer_reset_id; // received from peer during handshake (reset epoch)
uint8_t peer_device_type; // CLIENT_TYPE_* from peer handshake
uint16_t peer_keepalive_interval; // keepalive interval from peer handshake
@ -114,7 +113,6 @@ static void server_accept_cb(struct stcp_conn *conn, void *arg) {
link->ready = 1;
link->conn = conn;
link->peer_got_initial_pkt = conn->peer_got_initial_pkt;
link->peer_session_id = conn->peer_session_id;
link->peer_reset_id = conn->peer_reset_id;
link->peer_device_type = conn->peer_device_type;
link->peer_keepalive_interval = conn->peer_keepalive_interval;
@ -142,7 +140,6 @@ static void client_ready_cb(struct stcp_conn *conn, void *arg) {
link->ready = 1;
link->conn = conn;
link->peer_got_initial_pkt = conn->peer_got_initial_pkt;
link->peer_session_id = conn->peer_session_id;
link->peer_reset_id = conn->peer_reset_id;
link->peer_device_type = conn->peer_device_type;
link->peer_keepalive_interval = conn->peer_keepalive_interval;
@ -160,11 +157,11 @@ static void client_ready_cb(struct stcp_conn *conn, void *arg) {
{
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",
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: client handshake OK [%s] link=%d addr=%s gop=%d rid=%016llx",
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);
link->peer_got_initial_pkt, (unsigned long long)link->peer_reset_id);
}
if (link->etcp_link) etcp_link_enter_ready_tcp(link->etcp_link);
if (link->on_ready_cb) link->on_ready_cb(link, link->ready_arg);
@ -242,7 +239,7 @@ struct stcp_link *stcp_link_connect(struct ETCP_LINK *etcp_link,
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,
etcp->got_initial_pkt, etcp,
inst->client_type, inst->keepalive_interval,
0,
client_ready_cb, link, NULL, NULL, NULL, NULL, local_addr, 0, reality);
@ -375,10 +372,6 @@ uint8_t stcp_link_get_peer_got_initial_pkt(struct stcp_link *link) {
return link ? link->peer_got_initial_pkt : 0;
}
uint32_t stcp_link_get_peer_session_id(struct stcp_link *link) {
return link ? link->peer_session_id : 0;
}
uint64_t stcp_link_get_peer_reset_id(struct stcp_link *link) {
return link ? link->peer_reset_id : 0;
}

1
src/transport_layer/stcp_link.h

@ -63,7 +63,6 @@ void stcp_link_set_on_close(struct stcp_link *link, void (*cb)(struct stcp_link
const uint8_t *stcp_link_get_peer_pubkey(struct stcp_link *link);
const uint8_t *stcp_link_get_peer_ed25519_pubkey(struct stcp_link *link);
uint8_t stcp_link_get_peer_got_initial_pkt(struct stcp_link *link);
uint32_t stcp_link_get_peer_session_id(struct stcp_link *link);
uint64_t stcp_link_get_peer_reset_id(struct stcp_link *link);
uint8_t stcp_link_get_peer_device_type(struct stcp_link *link);
uint16_t stcp_link_get_peer_keepalive_interval(struct stcp_link *link);

36
src/transport_layer/stcp_server.c

@ -94,14 +94,13 @@ static void server_hs_phase1_cb(struct stcp_conn *c, uint8_t *data, size_t len)
}
memcpy(c->peer_ed25519_pubkey, enc_hs, SC_PUBKEY_SIZE); c->peer_ed25519_set = 1;
c->peer_got_initial_pkt = enc_hs[32];
memcpy(&c->peer_session_id, enc_hs + 33, 4);
{ uint64_t rid_be; memcpy(&rid_be, enc_hs + 37, 8); c->peer_reset_id = be64toh(rid_be); }
uint16_t padding_size = (uint16_t)enc_hs[45] | ((uint16_t)enc_hs[46] << 8);
c->peer_device_type = enc_hs[47];
c->peer_keepalive_interval = ((uint16_t)enc_hs[48] << 8) | enc_hs[49];
c->peer_flags = enc_hs[50];
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: client handshake OK gop=%d sid=%08x rid=%016llx padding=%u dev=%d ka=%u flags=%02x",
c->peer_got_initial_pkt, c->peer_session_id, (unsigned long long)c->peer_reset_id, padding_size, c->peer_device_type, c->peer_keepalive_interval, c->peer_flags);
{ uint64_t rid_be; memcpy(&rid_be, enc_hs + 33, 8); c->peer_reset_id = be64toh(rid_be); }
uint16_t padding_size = (uint16_t)enc_hs[41] | ((uint16_t)enc_hs[42] << 8);
c->peer_device_type = enc_hs[43];
c->peer_keepalive_interval = ((uint16_t)enc_hs[44] << 8) | enc_hs[45];
c->peer_flags = enc_hs[46];
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: client handshake OK gop=%d rid=%016llx padding=%u dev=%d ka=%u flags=%02x",
c->peer_got_initial_pkt, (unsigned long long)c->peer_reset_id, padding_size, c->peer_device_type, c->peer_keepalive_interval, c->peer_flags);
stcp_recv_set(c, padding_size, 0, server_hs_phase2_cb);
}
@ -111,17 +110,15 @@ static void server_hs_phase2_cb(struct stcp_conn *c, uint8_t *data, size_t len)
if (c->hs_timer) { uasync_cancel_timeout(c->ua, c->hs_timer); c->hs_timer = NULL; }
uint8_t server_gop = 0;
uint32_t server_sid = 0;
uint64_t server_rid = 0;
if (c->inst && c->peer_pubkey_set) {
uint64_t node_id = sc_derive_node_id_from_pubkey(c->peer_pubkey);
struct ETCP_CONN *conn = instance_find_conn(c->inst, node_id);
server_gop = conn ? conn->got_initial_pkt : 0;
server_sid = conn ? conn->session_id : 0;
server_rid = conn ? conn->reset_id : 0;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: node=0x%016llx conn=%p server_gop=%d server_sid=%08x server_rid=%016llx client_gop=%d client_sid=%08x client_rid=%016llx",
(unsigned long long)node_id, (void*)conn, server_gop, server_sid, (unsigned long long)server_rid,
c->peer_got_initial_pkt, c->peer_session_id, (unsigned long long)c->peer_reset_id);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: node=0x%016llx conn=%p server_gop=%d server_rid=%016llx client_gop=%d client_rid=%016llx",
(unsigned long long)node_id, (void*)conn, server_gop, (unsigned long long)server_rid,
c->peer_got_initial_pkt, (unsigned long long)c->peer_reset_id);
}
uint8_t salt2[SC_PUBKEY_ENC_SALT_SIZE];
@ -138,16 +135,15 @@ static void server_hs_phase2_cb(struct stcp_conn *c, uint8_t *data, size_t len)
uint8_t plain_hs[STCP_HS_PLAIN_SIZE]; memcpy(plain_hs, c->my_ed25519_pubkey, SC_PUBKEY_SIZE);
plain_hs[32] = server_gop;
memcpy(plain_hs + 33, &server_sid, 4);
{ uint64_t rid_be = htobe64(server_rid); memcpy(plain_hs + 37, &rid_be, 8); }
plain_hs[45] = (uint8_t)padding; plain_hs[46] = (uint8_t)(padding >> 8);
plain_hs[47] = c->device_type;
*(uint16_t*)(plain_hs + 48) = htobe16(c->keepalive_interval);
plain_hs[50] = (c->peer_flags & STCP_HANDSHAKE_FLAG_PING);
{ uint64_t rid_be = htobe64(server_rid); memcpy(plain_hs + 33, &rid_be, 8); }
plain_hs[41] = (uint8_t)padding; plain_hs[42] = (uint8_t)(padding >> 8);
plain_hs[43] = c->device_type;
*(uint16_t*)(plain_hs + 44) = htobe16(c->keepalive_interval);
plain_hs[46] = (c->peer_flags & STCP_HANDSHAKE_FLAG_PING);
uint32_t crc = crc32_calc(plain_hs, STCP_HS_PLAIN_SIZE);
uint8_t *enc_dst = resp + SC_PUBKEY_ENC_SIZE;
memcpy(enc_dst, plain_hs, STCP_HS_PLAIN_SIZE);
enc_dst[51] = (uint8_t)(crc >> 0); enc_dst[52] = (uint8_t)(crc >> 8); enc_dst[53] = (uint8_t)(crc >> 16); enc_dst[54] = (uint8_t)(crc >> 24);
enc_dst[47] = (uint8_t)(crc >> 0); enc_dst[48] = (uint8_t)(crc >> 8); enc_dst[49] = (uint8_t)(crc >> 16); enc_dst[50] = (uint8_t)(crc >> 24);
log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_server hs_resp BEFORE xor", enc_dst, STCP_HS_ENC_SERVER);
if (sc_stream_xor(&c->stream_send, enc_dst, STCP_HS_ENC_SERVER) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "encrypt failed");

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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, rogue.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &clip[i], NULL, NULL, peer_close_cb, &clip[i], NULL, 0, NULL);
clients[i] = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &clip[i], NULL, NULL, peer_close_cb, &clip[i], NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, 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, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
struct stcp_client *sc = stcp_client_connect(ua, "127.0.0.1", port, &c_keys, s_keys.public_key, NULL, 0, NULL, 0, 200, 0, client_ready_cb, &cli, NULL, NULL, peer_close_cb, &cli, NULL, 0, NULL); TASSERT(sc);
int ticks = 0;
while ((!srv.ready || !cli.ready) && ticks < 200) { uasync_poll(ua, 10); ticks++; }

12
tests/test_stcp_link.c

@ -50,9 +50,9 @@ static int test1_basic(void) {
int cli_ready = 0;
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, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL);
s_keys.public_key, NULL,
0, NULL,
0, 200, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL);
TASSERT(sc);
int ticks = 0;
@ -79,9 +79,9 @@ static int test2_wrong_key(void) {
struct SC_MYKEYS rogue; TASSERT(sc_generate_keypair(&rogue) == SC_OK);
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, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL);
rogue.public_key, NULL,
0, NULL,
0, 200, 0, on_cli_ready, &cli_ready, NULL, NULL, NULL, NULL, NULL, 0, NULL);
TASSERT(sc);
int ticks = 0;

Loading…
Cancel
Save