keepalive handshake: device_type + keepalive negotiation in UDP/TCP INIT
- Добавлен device_type (1 байт, CLIENT_TYPE_*) в INIT_REQUEST и INIT_RESPONSE - Добавлен keepalive_interval (2 байта) в INIT_RESPONSE - STCP handshake расширен с 43 до 46 байт (device_type+keepalive) - negotiate_keepalive(): оба desktop/server → min, иначе (есть mobile) → max - keepalive_interval вынесен в UTUN_INSTANCE для использования в handshake - stcp_client_connect() принимает device_type и keepalive_interval - peer_device_type/peer_keepalive_interval передаются через stcp_link в ETCP_LINK
This commit is contained in:
1 parent
43aca4a41b
commit
0f1bd3d120
37 files changed
+535
-309
No files matched your search
@@ -86,8 +86,9 @@ static int collect_my_addrs(uint8_t* buf, int max_buf_sz) {
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
{ struct ETCP_SOCKET* ts = g_cc.inst->tcp_sockets;
|
||||
{ struct ETCP_SOCKET* ts = g_cc.inst->etcp_sockets;
|
||||
while (ts) {
|
||||
if (!ts->is_tcp) { ts = ts->next; continue; }
|
||||
struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr;
|
||||
if (addr && addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)addr;
|
||||
|
||||
@@ -344,6 +344,7 @@ static void hc_handle_invite(struct headless_client* cli, int id, const char* js
|
||||
/* fallback: collect from sockets directly */
|
||||
struct ETCP_SOCKET* s = g_hc.inst->etcp_sockets;
|
||||
while (s && inv.addrCount < INVITE_ADDR_MAX) {
|
||||
if (s->is_tcp) { s = s->next; continue; }
|
||||
if (s->local_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&s->local_addr;
|
||||
struct InviteAddr* a = &inv.addrs[inv.addrCount++];
|
||||
@@ -352,8 +353,9 @@ static void hc_handle_invite(struct headless_client* cli, int id, const char* js
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
struct ETCP_SOCKET* ts = g_hc.inst->tcp_sockets;
|
||||
struct ETCP_SOCKET* ts = g_hc.inst->etcp_sockets;
|
||||
while (ts && inv.addrCount < INVITE_ADDR_MAX) {
|
||||
if (!ts->is_tcp) { ts = ts->next; continue; }
|
||||
if (ts->interface_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&ts->interface_addr;
|
||||
struct InviteAddr* a = &inv.addrs[inv.addrCount++];
|
||||
|
||||
@@ -161,9 +161,10 @@ void chat_core_sync_my_addresses(void) {
|
||||
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
|
||||
" VALUES(?,?,2,?,?,?,?)", -1, &tcp_ins, NULL);
|
||||
if (tcp_ins) {
|
||||
struct ETCP_SOCKET* ts = g_cc.inst->tcp_sockets;
|
||||
struct ETCP_SOCKET* ts = g_cc.inst->etcp_sockets;
|
||||
int tcp_count = 0;
|
||||
while (ts) { if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
while (ts) { if (!ts->is_tcp) { ts = ts->next; continue; }
|
||||
if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
tcp_count++;
|
||||
struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr;
|
||||
if (!addr || !addr->ss_family) { ts = ts->next; continue; }
|
||||
|
||||
+13
-18
@@ -102,8 +102,10 @@ static void chat_core_collect_status(void) {
|
||||
while (link) {
|
||||
char rtt_str[32]; rtt_str[0] = '\0';
|
||||
if (link->rtt_last > 0) snprintf(rtt_str, sizeof(rtt_str), " / rtt=%ums", link->rtt_last / 10);
|
||||
off += snprintf(buf + off, sizeof(buf) - off, " LINK#%d: %s /NAT=%s%s\n",
|
||||
off += snprintf(buf + off, sizeof(buf) - off, " LINK#%d: %s %s %s NAT=%s%s\n",
|
||||
link_idx,
|
||||
link->is_tcp ? "TCP" : "UDP",
|
||||
link->conn ? link->conn->name : "?",
|
||||
link->link_status ? "UP" : "DOWN",
|
||||
nat_type_str(link->nat_type),
|
||||
rtt_str);
|
||||
@@ -261,7 +263,7 @@ static void collect_conn_metrics(uint64_t peer_node_id) {
|
||||
while (link) {
|
||||
const char* is_tcp_str = link->is_tcp ? "TCP" : "UDP";
|
||||
char local_str[54], remote_str[54];
|
||||
strncpy(local_str, link->conn ? sockaddr_storage_to_str(&link->conn->local_addr).str : "stcp", sizeof(local_str) - 1);
|
||||
strncpy(local_str, link->conn ? (link->conn->interface_addr.ss_family ? sockaddr_storage_to_str(&link->conn->interface_addr).str : sockaddr_storage_to_str(&link->conn->local_addr).str) : "stcp", sizeof(local_str) - 1);
|
||||
strncpy(remote_str, sockaddr_storage_to_str(&link->remote_addr).str, sizeof(remote_str) - 1);
|
||||
off += snprintf(buf + off, sizeof(buf) - off,
|
||||
"\n--- LINK#%d: %s %s NAT=%s ---\n"
|
||||
@@ -367,8 +369,6 @@ static void collect_member_detail(uint64_t node_id) {
|
||||
uint8_t sock_count = 0;
|
||||
for (struct ETCP_SOCKET* s = inst->etcp_sockets; s && sock_count < MEMBER_DETAIL_MAX_SOCKS; s = s->next)
|
||||
sock_count++;
|
||||
for (struct ETCP_SOCKET* ts = inst->tcp_sockets; ts && sock_count < MEMBER_DETAIL_MAX_SOCKS; ts = ts->next)
|
||||
sock_count++;
|
||||
|
||||
size_t buf_sz = 12 + (size_t)link_count * MEMBER_DETAIL_LINK_SIZE
|
||||
+ 1 + (size_t)sock_count * MEMBER_DETAIL_SOCK_SIZE;
|
||||
@@ -390,12 +390,19 @@ static void collect_member_detail(uint64_t node_id) {
|
||||
|
||||
{ uint8_t lf = 0; uint8_t la[16] = {0}; uint16_t lp = 0;
|
||||
if (lk->conn) {
|
||||
const struct sockaddr_storage* lsa = &lk->conn->local_addr;
|
||||
const struct sockaddr_storage* lsa = lk->conn->interface_addr.ss_family ? &lk->conn->interface_addr : &lk->conn->local_addr;
|
||||
if (lsa->ss_family == AF_INET) {
|
||||
lf = 4; memcpy(la, &((const struct sockaddr_in*)lsa)->sin_addr, 4); lp = ntohs(((const struct sockaddr_in*)lsa)->sin_port);
|
||||
} else if (lsa->ss_family == AF_INET6) {
|
||||
lf = 6; memcpy(la, &((const struct sockaddr_in6*)lsa)->sin6_addr, 16); lp = ntohs(((const struct sockaddr_in6*)lsa)->sin6_port);
|
||||
}
|
||||
} else if (lk->is_tcp && lk->tcp_link) {
|
||||
const struct sockaddr_storage* lsa = stcp_link_get_local_addr(lk->tcp_link);
|
||||
if (lsa && lsa->ss_family == AF_INET) {
|
||||
lf = 4; memcpy(la, &((const struct sockaddr_in*)lsa)->sin_addr, 4); lp = ntohs(((const struct sockaddr_in*)lsa)->sin_port);
|
||||
} else if (lsa && lsa->ss_family == AF_INET6) {
|
||||
lf = 6; memcpy(la, &((const struct sockaddr_in6*)lsa)->sin6_addr, 16); lp = ntohs(((const struct sockaddr_in6*)lsa)->sin6_port);
|
||||
}
|
||||
}
|
||||
*p++ = lf; memcpy(p, la, 16); p += 16; memcpy(p, &lp, 2); p += 2;
|
||||
}
|
||||
@@ -418,25 +425,13 @@ static void collect_member_detail(uint64_t node_id) {
|
||||
const struct sockaddr_storage* sa = s->interface_addr.ss_family ? &s->interface_addr : &s->local_addr;
|
||||
if (sa->ss_family == AF_INET) sp = ntohs(((const struct sockaddr_in*)sa)->sin_port);
|
||||
else if (sa->ss_family == AF_INET6) sp = ntohs(((const struct sockaddr_in6*)sa)->sin6_port);
|
||||
uint32_t lc = s->links_queue ? (uint32_t)queue_entry_count(s->links_queue) : 0;
|
||||
uint32_t lc = s->is_tcp ? 0 : (s->links_queue ? (uint32_t)queue_entry_count(s->links_queue) : 0);
|
||||
char ifname[38] = {0}; sock_ifname(s->name, ifname, sizeof(ifname));
|
||||
memcpy(p, &sid, 4); p += 4;
|
||||
memcpy(p, &sp, 2); p += 2;
|
||||
memcpy(p, &lc, 4); p += 4;
|
||||
memcpy(p, ifname, 38); p += 38;
|
||||
}
|
||||
for (struct ETCP_SOCKET* ts = inst->tcp_sockets; ts && sock_count; ts = ts->next, sock_count--) {
|
||||
uint32_t sid = ts->sock_id;
|
||||
uint16_t sp = 0;
|
||||
const struct sockaddr_storage* sa = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr;
|
||||
if (sa->ss_family == AF_INET) sp = ntohs(((const struct sockaddr_in*)sa)->sin_port);
|
||||
else if (sa->ss_family == AF_INET6) sp = ntohs(((const struct sockaddr_in6*)sa)->sin6_port);
|
||||
char ifname[38] = {0}; sock_ifname(ts->name, ifname, sizeof(ifname));
|
||||
memcpy(p, &sid, 4); p += 4;
|
||||
memcpy(p, &sp, 2); p += 2;
|
||||
uint32_t lc = 0; memcpy(p, &lc, 4); p += 4;
|
||||
memcpy(p, ifname, 38); p += 38;
|
||||
}
|
||||
|
||||
chat_event_post(CHAT_EVT_MEMBER_DETAIL, buf, (int)(p - buf));
|
||||
u_free(buf);
|
||||
|
||||
@@ -528,7 +528,7 @@ static void cm_ping_cb_impl(int success, uint16_t rtt, void* arg, uint64_t nonce
|
||||
* Если ни одного линка не создалось — закрывает NCD и переходит к REVERSE/INDIRECT. */
|
||||
static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* entry,
|
||||
struct TOPO_NODE* ni, int db_loaded) {
|
||||
int any = 0;
|
||||
int any = 0, v4_cnt = 0, v6_cnt = 0, v4_tcp = 0, v6_tcp = 0;
|
||||
/* v4 */
|
||||
if (db_loaded) {
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
@@ -536,8 +536,11 @@ static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* e
|
||||
memcpy(&sin.sin_addr.s_addr,a->addr,4); sin.sin_port=htons(a->port);
|
||||
struct sockaddr_storage sa; memcpy(&sa,&sin,sizeof(sin));
|
||||
if (a->protocol & TOPO_PROTO_TCP) {
|
||||
struct ETCP_LINK *tlink = etcp_link_new(conn, NULL, NULL, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); any = 1; }
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
while (s) { if (s->is_tcp && s->local_addr.ss_family == AF_INET && s->type != CFG_SERVER_TYPE_PRIVATE) {
|
||||
struct ETCP_LINK *tlink = etcp_link_new(conn, s, &sa, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); any = 1; v4_tcp++; v4_cnt++; }
|
||||
} s = s->next; }
|
||||
}
|
||||
if (a->protocol & TOPO_PROTO_UDP) {
|
||||
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
@@ -571,17 +574,25 @@ static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* e
|
||||
{sin6.sin6_scope_id=sv->netif_index;break;} sv=sv->next;}
|
||||
}
|
||||
struct sockaddr_storage sa; memcpy(&sa,&sin6,sizeof(sin6));
|
||||
struct ETCP_LINK *tlink = etcp_link_new(conn, NULL, NULL, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a6->port); any = 1; }
|
||||
{ struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
|
||||
while (s) { if (s->is_tcp && s->local_addr.ss_family == AF_INET6 && s->type != CFG_SERVER_TYPE_PRIVATE) {
|
||||
struct ETCP_LINK *tlink = etcp_link_new(conn, s, &sa, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a6->port); any = 1; v6_tcp++; v6_cnt++; }
|
||||
} s = s->next; }
|
||||
}
|
||||
}
|
||||
if (a6->protocol & TOPO_PROTO_UDP) {
|
||||
uint8_t tc=cm_classify_v6_addr(a6->addr); if(tc==CM_V6_OTH) continue;
|
||||
struct ETCP_SOCKET* s=entry->mgr->instance->etcp_sockets;
|
||||
while(s){uint8_t sc=cm_sock_v6_classify(s);if(sc==CM_V6_ANY||sc==tc){cm_add_v6_link(conn,a6->addr,a6->port,s);any=1;} s=s->next;}
|
||||
while(s){uint8_t sc=cm_sock_v6_classify(s);if(sc==CM_V6_ANY||sc==tc){cm_add_v6_link(conn,a6->addr,a6->port,s);any=1; v6_cnt++;} s=s->next;}
|
||||
}
|
||||
}
|
||||
|
||||
if (any) return;
|
||||
if (any) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: direct_add_links node=0x%016llx db=%d v4=%d/tcp=%d v6=%d/tcp=%d conn=[%s]",
|
||||
(unsigned long long)entry->node_id, db_loaded, v4_cnt, v4_tcp, v6_cnt, v6_tcp, conn->log_name);
|
||||
return;
|
||||
}
|
||||
node_conn_direct_close(entry->ncd_handle); entry->ncd_handle=NULL;
|
||||
if (db_loaded) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: db_node 0x%016llx direct failed (no compatible addr/socket)", (unsigned long long)entry->node_id);
|
||||
|
||||
@@ -55,7 +55,7 @@ void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_
|
||||
}
|
||||
for (uint8_t i=0;i<resp->my_count&&cnt<8;i++) {
|
||||
struct TOPO_GROUP_NODE* nq=topo_node_find_by_id(entry->mgr->group,resp->my_candidates[i].node_id);
|
||||
uint16_t our=nq?cm_get_node_min_rtt(nq):0; if(our==0xFFFF)our=0;
|
||||
uint16_t our=nq?topo_get_chain_rtt(nq):0; if(our==0xFFFF)our=0;
|
||||
all[cnt]=(typeof(all[0])){resp->my_candidates[i].node_id,(uint64_t)our+resp->my_candidates[i].rtt}; cnt++;
|
||||
}
|
||||
for (uint8_t i=0;i<cnt;i++) for(uint8_t j=i+1;j<cnt;j++) if(all[j].rtt<all[i].rtt){typeof(all[0])t=all[i];all[i]=all[j];all[j]=t;}
|
||||
@@ -65,7 +65,7 @@ void cm_compute_intermediaries(struct CONN_MGR_ENTRY* entry, struct CM_EXCHANGE_
|
||||
struct CM_INTERM_SEL pkt; memset(&pkt,0,sizeof(pkt));
|
||||
pkt.cmd=ETCP_RT_ID_CONN_MGR; pkt.subcmd=CM_SUBCMD_INTERM_SELECTED; pkt.count=sel;
|
||||
for(uint8_t i=0;i<sel;i++){pkt.selected[i].node_id=all[i].nid;pkt.selected[i].rtt=0;
|
||||
struct TOPO_GROUP_NODE* nq=topo_node_find_by_id(entry->mgr->group,all[i].nid); if(nq)pkt.selected[i].rtt=cm_get_node_min_rtt(nq);}
|
||||
struct TOPO_GROUP_NODE* nq=topo_node_find_by_id(entry->mgr->group,all[i].nid); if(nq)pkt.selected[i].rtt=topo_get_chain_rtt(nq);}
|
||||
struct ll_entry* qe=queue_entry_new(0);
|
||||
if(qe){qe->dgram=u_malloc(sizeof(pkt));memcpy(qe->dgram,&pkt,sizeof(pkt));qe->len=sizeof(pkt);etcp_route_send(entry->mgr->instance,entry->mgr->group->group_id,entry->node_id,qe,1);}
|
||||
entry->conn_type=CONN_TYPE_INDIRECT; entry->state=CONN_MGR_STATE_CONNECTED;
|
||||
@@ -136,7 +136,7 @@ void cm_handle_interm_exchange_req(struct ETCP_CONN* conn, struct CM_EXCHANGE_RE
|
||||
for(uint8_t i=0;i<resp.your_count;i++){
|
||||
resp.your_candidates[i].node_id=req->candidates[i].node_id;
|
||||
struct TOPO_GROUP_NODE* nq2=topo_node_find_by_id(mgr->group,req->candidates[i].node_id);
|
||||
resp.your_candidates[i].rtt=nq2?cm_get_node_min_rtt(nq2):0;
|
||||
resp.your_candidates[i].rtt=nq2?topo_get_chain_rtt(nq2):0;
|
||||
}
|
||||
size_t sz=offsetof(struct CM_EXCHANGE_RESP,your_candidates)+(size_t)resp.your_count*sizeof(struct CONN_MGR_CANDIDATE);
|
||||
struct ll_entry* qe=queue_entry_new(0);
|
||||
|
||||
@@ -14,15 +14,7 @@
|
||||
#include "route_connectivity.h"
|
||||
#include "route_ping.h"
|
||||
|
||||
/* ═══════ RTT утилиты ═══════ */
|
||||
|
||||
uint16_t cm_get_node_min_rtt(struct TOPO_GROUP_NODE* nq) {
|
||||
uint16_t r = 0xFFFF;
|
||||
if (nq->connectivity.interface_status == PROBE_RESULT_REACHABLE && nq->connectivity.interface_min_rtt < r) r = nq->connectivity.interface_min_rtt;
|
||||
if (nq->connectivity.nat_status == PROBE_RESULT_REACHABLE && nq->connectivity.nat_min_rtt < r) r = nq->connectivity.nat_min_rtt;
|
||||
if (nq->connectivity.real_status == PROBE_RESULT_REACHABLE && nq->connectivity.real_min_rtt < r) r = nq->connectivity.real_min_rtt;
|
||||
return r;
|
||||
}
|
||||
/* ═══════ probe time утилиты ═══════ */
|
||||
|
||||
uint64_t cm_get_node_max_probe_time(struct TOPO_GROUP_NODE* nq) {
|
||||
uint64_t t = nq->connectivity.interface_probe_time;
|
||||
|
||||
@@ -224,7 +224,6 @@ void cm_handle_interm_selected(struct CONN_MGR* mgr, const uint8_t* data, size_t
|
||||
void cm_idle_timer_cb(void* arg);
|
||||
void cm_bg_ping_timer_cb(void* arg);
|
||||
void cm_candidate_ping_timer_cb(void* arg);
|
||||
uint16_t cm_get_node_min_rtt(struct TOPO_GROUP_NODE* nq);
|
||||
uint64_t cm_get_node_max_probe_time(struct TOPO_GROUP_NODE* nq);
|
||||
int cm_is_rtt_fresh(struct TOPO_GROUP_NODE* nq, uint64_t now_tb);
|
||||
void cm_invite_overall_timeout(void* arg);
|
||||
|
||||
@@ -763,7 +763,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
|
||||
if (id != node_id) {
|
||||
int found = 0; for (int i = 0; i < hop_count; i++) if (hop_list[i] == id) found = 1;
|
||||
if (found == 0) {
|
||||
uint16_t out_rtt = (uint16_t)((uint32_t)item->conn->rtt_last + incoming_cumulative_rtt);
|
||||
uint16_t out_rtt = topo_get_chain_rtt(nodeinfo1);
|
||||
topo_group_send_nodeinfo(group, nodeinfo1, item->conn, out_rtt);
|
||||
}
|
||||
}
|
||||
@@ -868,7 +868,7 @@ static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CON
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
if (nq->node_id == group->instance->node_id) { e = e->next; continue; }
|
||||
if (!nq->paths) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "node has no paths"); e = e->next; continue; }
|
||||
if (topo_group_should_send_to(nq, target)) { uint8_t _hc; uint16_t _rtt; topo_node_best_hop_list(nq, &_hc, &_rtt); topo_group_send_nodeinfo(group, nq, conn, (uint16_t)((uint32_t)conn->rtt_last + _rtt)); }
|
||||
if (topo_group_should_send_to(nq, target)) topo_group_send_nodeinfo(group, nq, conn, topo_get_chain_rtt(nq));
|
||||
e = e->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,14 +442,27 @@ void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uin
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t node_best_rtt(struct TOPO_GROUP_NODE* nq) {
|
||||
if (!nq) return 0xFFFF;
|
||||
struct TOPO_CONNECTIVITY* c = &nq->connectivity;
|
||||
uint16_t best = 0x3FFF; uint8_t type = 0;
|
||||
if (c->interface_status == PROBE_RESULT_REACHABLE && c->interface_min_rtt < best) { best = c->interface_min_rtt; type = 0; }
|
||||
if (c->nat_status == PROBE_RESULT_REACHABLE && c->nat_min_rtt < best) { best = c->nat_min_rtt; type = 1; }
|
||||
if (c->real_status == PROBE_RESULT_REACHABLE && c->real_min_rtt < best) { best = c->real_min_rtt; type = 2; }
|
||||
return ((uint16_t)type << 14) | best;
|
||||
uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq) {
|
||||
if (!nq || !nq->paths || !nq->paths->head) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx NO PATHS", (unsigned long long)(nq ? nq->node_id : 0));
|
||||
return 0xFFFF;
|
||||
}
|
||||
uint16_t best = 0xFFFF;
|
||||
for (struct ll_entry* e = nq->paths->head; e; e = e->next) {
|
||||
struct TOPO_NODEPATH* p = (struct TOPO_NODEPATH*)e;
|
||||
if (!p->conn || !p->conn->links_up || !p->conn->rtt_last) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx SKIP conn=%s up=%d rtt=%u cum=%u",
|
||||
(unsigned long long)nq->node_id, p->conn ? p->conn->log_name : "NULL",
|
||||
p->conn ? p->conn->links_up : 0, p->conn ? p->conn->rtt_last : 0, p->cumulative_rtt);
|
||||
continue;
|
||||
}
|
||||
uint16_t total = (uint16_t)((uint32_t)p->conn->rtt_last + p->cumulative_rtt);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx PATH %s rtt=%u+cum=%u=%u best=%u",
|
||||
(unsigned long long)nq->node_id, p->conn->log_name, p->conn->rtt_last, p->cumulative_rtt, total, best);
|
||||
if (total < best) best = total;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "chain_rtt: nid=%016llx RESULT=%u(0x%04X)", (unsigned long long)nq->node_id, best, best);
|
||||
return best;
|
||||
}
|
||||
|
||||
// ===== dump / format =====
|
||||
@@ -656,8 +669,8 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
if (!instance || !group) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return -1; }
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: ENTER inst=%p nid=0x%016llx grp=%p grp_inst=%p grp_type=%d",
|
||||
(void*)instance, (unsigned long long)instance->node_id, (void*)group, (void*)group->instance, group->group_type);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: topo_groups=%p etcp=%p tcp=%p reg=%p",
|
||||
(void*)instance->topo_groups, (void*)instance->etcp_sockets, (void*)instance->tcp_sockets,
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: topo_groups=%p etcp=%p reg=%p",
|
||||
(void*)instance->topo_groups, (void*)instance->etcp_sockets,
|
||||
instance->topo_groups ? (void*)instance->topo_groups->node_registry : NULL);
|
||||
if (instance->topo_groups) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: pools sm4=%p a4=%p sm6=%p a6=%p sub4=%p sub6=%p",
|
||||
@@ -683,8 +696,9 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
else if (e_sock->local_addr.ss_family == AF_INET6) { sock6_count++; addr6_count++; }
|
||||
e_sock = e_sock->next;
|
||||
}
|
||||
{ struct ETCP_SOCKET* ts = instance->tcp_sockets;
|
||||
while (ts) { if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
{ struct ETCP_SOCKET* ts = instance->etcp_sockets;
|
||||
while (ts) { if (!ts->is_tcp) { ts = ts->next; continue; }
|
||||
if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
if (ts->interface_addr.ss_family == AF_INET || ts->local_addr.ss_family == AF_INET) { tcp4_count++; addr_count++; }
|
||||
else if (ts->interface_addr.ss_family == AF_INET6 || ts->local_addr.ss_family == AF_INET6) { tcp6_count++; addr6_count++; }
|
||||
ts = ts->next; }
|
||||
@@ -800,11 +814,11 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
}
|
||||
e_sock = e_sock->next;
|
||||
}
|
||||
{ struct ETCP_SOCKET* ts = instance->tcp_sockets;
|
||||
{ struct ETCP_SOCKET* ts = instance->etcp_sockets;
|
||||
int tcp_iter_cnt = 0;
|
||||
while (ts) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "TOPO_UPD_SELF: tcp_iter[%d] ts=%p type=%d fam=%d next=%p",
|
||||
tcp_iter_cnt, (void*)ts, ts->type, ts->local_addr.ss_family, (void*)ts->next);
|
||||
tcp_iter_cnt++; if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
tcp_iter_cnt++; if (!ts->is_tcp) { ts = ts->next; continue; }
|
||||
struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr;
|
||||
if (!addr || !addr->ss_family) { ts = ts->next; continue; }
|
||||
if (addr->ss_family == AF_INET) {
|
||||
@@ -907,8 +921,9 @@ void topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
e_sock = e_sock->next;
|
||||
}
|
||||
{ struct ETCP_SOCKET* ts = instance->tcp_sockets;
|
||||
while (ts) { if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
{ struct ETCP_SOCKET* ts = instance->etcp_sockets;
|
||||
while (ts) { if (!ts->is_tcp) { ts = ts->next; continue; }
|
||||
if (ts->type == CFG_SERVER_TYPE_PRIVATE || ts->type == CFG_SERVER_TYPE_LOCAL) { ts = ts->next; continue; }
|
||||
struct sockaddr_storage* addr = ts->interface_addr.ss_family ? &ts->interface_addr : &ts->local_addr;
|
||||
if (!addr || !addr->ss_family) { ts = ts->next; continue; }
|
||||
if (addr->ss_family == AF_INET) {
|
||||
|
||||
@@ -202,9 +202,7 @@ void topo_node_dump_all(struct TOPO_GROUP* group);
|
||||
int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size);
|
||||
int topo_node_ping_request_cbk(struct TOPO_GROUPS* groups, uint64_t node_id);
|
||||
void topo_node_ping_update_rtt(struct TOPO_GROUPS* groups, uint64_t node_id, uint16_t rtt);
|
||||
uint16_t node_best_rtt(struct TOPO_GROUP_NODE* nq);
|
||||
#define NODE_RTT_TYPE(v) ((v) >> 14)
|
||||
#define NODE_RTT_VALUE(v) ((v) & 0x3FFF)
|
||||
uint16_t topo_get_chain_rtt(struct TOPO_GROUP_NODE* nq);
|
||||
|
||||
/** Build canonical message for Ed25519 signature: x25519_pubkey || name || client_type || client_activity || addresses */
|
||||
#define TOPO_SIG_MSG_MAX_SIZE 2048
|
||||
|
||||
@@ -60,17 +60,6 @@ static int node_has_direct_ip(struct TOPO_GROUP* group, const struct TOPO_GROUP_
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Минимальный RTT из данных connectivity-проб (interface/nat/real). 0xFFFF если неизвестен */
|
||||
static uint16_t node_get_min_rtt(const struct TOPO_GROUP_NODE* nq) {
|
||||
uint16_t rtt = 0xFFFF;
|
||||
if (nq->connectivity.interface_status == PROBE_RESULT_REACHABLE && nq->connectivity.interface_min_rtt < rtt)
|
||||
rtt = nq->connectivity.interface_min_rtt;
|
||||
if (nq->connectivity.nat_status == PROBE_RESULT_REACHABLE && nq->connectivity.nat_min_rtt < rtt)
|
||||
rtt = nq->connectivity.nat_min_rtt;
|
||||
if (nq->connectivity.real_status == PROBE_RESULT_REACHABLE && nq->connectivity.real_min_rtt < rtt)
|
||||
rtt = nq->connectivity.real_min_rtt;
|
||||
return rtt;
|
||||
}
|
||||
|
||||
/* Ищет незапущенный (started==0) контекст по next_hop_id */
|
||||
static struct TOPO_RECOVERY_CTX* topo_recovery_find_by_next_hop(struct TOPO_GROUP* group, uint64_t next_hop_id) {
|
||||
@@ -188,7 +177,7 @@ void topo_recovery_add_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq
|
||||
}
|
||||
|
||||
int list = node_has_direct_ip(group, nq) ? 0 : 1;
|
||||
uint16_t rtt = node_get_min_rtt(nq);
|
||||
uint16_t rtt = topo_get_chain_rtt(nq);
|
||||
|
||||
if (ctx->count[list] >= ctx->capacity[list]) {
|
||||
size_t new_cap = ctx->capacity[list] * 2;
|
||||
|
||||
@@ -410,8 +410,9 @@ static void remove_iface_sockets(struct AUTO_SOCKET* as, uint32_t ifindex) {
|
||||
if (ifa->v4_tcp) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] removing v4 TCP socket ifidx=%u", ifindex);
|
||||
{ uint16_t v4_port = load_port_from_db(as, ifname, AF_INET, AS_PROTO_TCP);
|
||||
struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets;
|
||||
struct ETCP_SOCKET** tsp = &as->instance->etcp_sockets;
|
||||
while (*tsp) {
|
||||
if (!(*tsp)->is_tcp) { tsp = &(*tsp)->next; continue; }
|
||||
uint16_t tsp_port = 0;
|
||||
const struct sockaddr_storage* addr = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr;
|
||||
if (addr->ss_family == AF_INET) tsp_port = ntohs(((struct sockaddr_in*)addr)->sin_port);
|
||||
@@ -426,8 +427,9 @@ static void remove_iface_sockets(struct AUTO_SOCKET* as, uint32_t ifindex) {
|
||||
if (ifa->v6_tcp) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] removing v6 TCP socket ifidx=%u", ifindex);
|
||||
{ uint16_t v6_port = load_port_from_db(as, ifname, AF_INET6, AS_PROTO_TCP);
|
||||
struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets;
|
||||
struct ETCP_SOCKET** tsp = &as->instance->etcp_sockets;
|
||||
while (*tsp) {
|
||||
if (!(*tsp)->is_tcp) { tsp = &(*tsp)->next; continue; }
|
||||
uint16_t tsp_port = 0;
|
||||
const struct sockaddr_storage* addr = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr;
|
||||
if (addr->ss_family == AF_INET6) tsp_port = ntohs(((struct sockaddr_in6*)addr)->sin6_port);
|
||||
@@ -708,8 +710,8 @@ static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char
|
||||
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v4 TCP removed: %s ifidx=%u", ifname, ifindex);
|
||||
{ char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname;
|
||||
uint16_t p = load_port_from_db(as, nm, AF_INET, AS_PROTO_TCP);
|
||||
struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets;
|
||||
while (*tsp) { uint16_t tp = 0; const struct sockaddr_storage* a = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr;
|
||||
struct ETCP_SOCKET** tsp = &as->instance->etcp_sockets;
|
||||
while (*tsp) { if (!(*tsp)->is_tcp) { tsp = &(*tsp)->next; continue; } uint16_t tp = 0; const struct sockaddr_storage* a = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr;
|
||||
if (a->ss_family == AF_INET) tp = ntohs(((struct sockaddr_in*)a)->sin_port);
|
||||
if (tp == p && p > 0) { struct ETCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; }
|
||||
}
|
||||
@@ -731,8 +733,8 @@ static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char
|
||||
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v6 TCP removed: %s ifidx=%u", ifname, ifindex);
|
||||
{ char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname;
|
||||
uint16_t p = load_port_from_db(as, nm, AF_INET6, AS_PROTO_TCP);
|
||||
struct ETCP_SOCKET** tsp = &as->instance->tcp_sockets;
|
||||
while (*tsp) { uint16_t tp = 0; const struct sockaddr_storage* a = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr;
|
||||
struct ETCP_SOCKET** tsp = &as->instance->etcp_sockets;
|
||||
while (*tsp) { if (!(*tsp)->is_tcp) { tsp = &(*tsp)->next; continue; } uint16_t tp = 0; const struct sockaddr_storage* a = (*tsp)->interface_addr.ss_family ? &(*tsp)->interface_addr : &(*tsp)->local_addr;
|
||||
if (a->ss_family == AF_INET6) tp = ntohs(((struct sockaddr_in6*)a)->sin6_port);
|
||||
if (tp == p && p > 0) { struct ETCP_SOCKET* rm = *tsp; *tsp = rm->next; u_free(rm); break; } tsp = &(*tsp)->next; }
|
||||
}
|
||||
|
||||
@@ -1247,6 +1247,8 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) {
|
||||
link->last_recv_updated=0;
|
||||
if (dt<1000000) {
|
||||
dgram->data[ptr++]=ETCP_SECTION_TIMESTAMP;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] KA-TX: ts_section dt=%llu tcp=%d",
|
||||
link->etcp->log_name, (unsigned long long)dt, dgram->link->is_tcp);
|
||||
|
||||
uint16_t t=link->last_recv_timestamp + dt;
|
||||
dgram->data[ptr++]=t;
|
||||
@@ -1537,6 +1539,8 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
uint16_t ret_ts=data[1] | (data[2]<<8);// cur_ts=ret_ts = RTT
|
||||
uint16_t new_rtt=cur_ts-ret_ts;
|
||||
pkt->link->rtt_last=new_rtt;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] KA-RTT: rtt=%u cur=%u ret=%u dlen=%u",
|
||||
etcp->log_name, new_rtt, cur_ts, ret_ts, pkt->data_len);
|
||||
etcp_metrics_add_rtt(etcp, new_rtt);
|
||||
|
||||
int recv_dt_tx1=data[3] | (data[4]<<8);// localtime удаленной стороны момента принятия пакета - timestamp этого пакета (на стороне отправителя, т.е. у нас)
|
||||
|
||||
@@ -78,16 +78,22 @@ static void connect_create_links_v4(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_
|
||||
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
|
||||
memcpy(&sin.sin_addr.s_addr, a->addr, 4); sin.sin_port = htons(a->port);
|
||||
struct sockaddr_storage sa; memcpy(&sa, &sin, sizeof(sin));
|
||||
int addr_links = 0;
|
||||
if (!(a->protocol & TOPO_PROTO_TCP)) {
|
||||
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets;
|
||||
while (s) { if (s->local_addr.ss_family == AF_INET && etcp_link_new(ctx->conn, s, &sa, 0)) link_count++; s = s->next; }
|
||||
while (s) { if (s->local_addr.ss_family == AF_INET && etcp_link_new(ctx->conn, s, &sa, 0)) { link_count++; addr_links++; } s = s->next; }
|
||||
}
|
||||
if ((a->protocol & TOPO_PROTO_TCP)) {
|
||||
struct ETCP_LINK *tlink = etcp_link_new(ctx->conn, NULL, NULL, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); link_count++; }
|
||||
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets;
|
||||
while (s) { if (s->is_tcp && s->local_addr.ss_family == AF_INET) {
|
||||
struct ETCP_LINK *tlink = etcp_link_new(ctx->conn, s, &sa, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); link_count++; addr_links++; }
|
||||
} s = s->next; }
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] link_v4: %d.%d.%d.%d:%d proto=%d links=%d conn=[%s]",
|
||||
a->addr[0], a->addr[1], a->addr[2], a->addr[3], a->port, a->protocol, addr_links, ctx->conn->log_name);
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[etcp_connect] links_v4: addrs=%d socks=%d links=%d for node=%016llx",
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] links_v4: TOTAL addrs=%d socks=%d links=%d for node=%016llx",
|
||||
addr_count, sock_count, link_count, (unsigned long long)node->node_id);
|
||||
}
|
||||
|
||||
@@ -115,8 +121,11 @@ static void connect_create_links_v6(struct ETCP_CONNECT* ctx, struct TOPO_GROUP_
|
||||
{ sin6.sin6_scope_id = sv->netif_index; break; } sv = sv->next; }
|
||||
}
|
||||
struct sockaddr_storage sa; memcpy(&sa, &sin6, sizeof(sin6));
|
||||
struct ETCP_LINK *tlink = etcp_link_new(ctx->conn, NULL, NULL, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); }
|
||||
struct ETCP_SOCKET* s = ctx->instance->etcp_sockets;
|
||||
while (s) { if (s->is_tcp && s->local_addr.ss_family == AF_INET6) {
|
||||
struct ETCP_LINK *tlink = etcp_link_new(ctx->conn, s, &sa, 0);
|
||||
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); }
|
||||
} s = s->next; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,8 +161,9 @@ static void connect_settle_timeout_cb(void* arg) {
|
||||
while (link) {
|
||||
struct ETCP_LINK* next = link->next;
|
||||
if (!link->initialized) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] removing failed link=%p for node 0x%016llx",
|
||||
(void*)link, (unsigned long long)ctx->node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_CONNECT, "[etcp_connect] settle: removing link=%d is_tcp=%d state=%d addr=%s for node 0x%016llx",
|
||||
link->local_link_id, link->is_tcp, link->link_state,
|
||||
sockaddr_storage_to_str(&link->remote_addr).str, (unsigned long long)ctx->node_id);
|
||||
etcp_link_close(link);
|
||||
}
|
||||
link = next;
|
||||
@@ -173,7 +183,10 @@ static void connect_init_cb(struct ETCP_CONN* conn, int event, void* arg) { (voi
|
||||
total_links++;
|
||||
if (link->initialized && link->rtt_last && link->rtt_last < ctx->min_rtt)
|
||||
ctx->min_rtt = link->rtt_last;
|
||||
if (link->link_state == 3) up_links++;
|
||||
if (link->link_state == LINK_STATE_CONNECTED) up_links++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[etcp_connect] init_cb: link=%d state=%d init=%d is_tcp=%d rtt=%u addr=%s",
|
||||
link->local_link_id, link->link_state, link->initialized, link->is_tcp, link->rtt_last,
|
||||
sockaddr_storage_to_str(&link->remote_addr).str);
|
||||
link = link->next;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,8 @@ void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: new ETCP_CONN peer=0x%016llx", (unsigned long long)node_id);
|
||||
}
|
||||
|
||||
const struct sockaddr_storage* ra = stcp_link_get_remote_addr(link);
|
||||
const struct sockaddr_storage* ra = stcp_link_get_peer_addr(link);
|
||||
if (!ra) ra = stcp_link_get_remote_addr(link);
|
||||
struct ETCP_LINK *tlink = etcp_link_new(conn, tcp_sock, ra, 1);
|
||||
if (!tlink) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: etcp_link_new failed"); return; }
|
||||
tlink->tcp_link = link;
|
||||
@@ -176,7 +177,7 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
|
||||
*(uint64_t*)req->node_id = htobe64(link->etcp->instance->node_id);
|
||||
*(uint32_t*)req->session_id = htobe32(link->etcp->session_id);
|
||||
*(uint16_t*)req->mtu = htobe16(link->mtu_local);
|
||||
*(uint16_t*)req->keepalive = htobe16(link->keepalive_interval);
|
||||
*(uint16_t*)req->keepalive = htobe16(link->etcp->instance->keepalive_interval);
|
||||
*(uint16_t*)req->recovery = htobe16(link->recovery_interval / 100);
|
||||
req->link_id = link->local_link_id;
|
||||
req->socket_id = link->conn ? link->conn->sock_id : 0;
|
||||
@@ -196,6 +197,7 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
|
||||
}
|
||||
req->collision = collision;
|
||||
memcpy(req->ed25519_pubkey, link->etcp->instance->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
req->device_type = link->etcp->instance->client_type;
|
||||
size_t offset = ETCP_INIT_REQ_SIZE;
|
||||
|
||||
// padding
|
||||
@@ -269,7 +271,7 @@ static void etcp_link_init_timer_cbk(void* arg) {
|
||||
}
|
||||
link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk, "link_init");
|
||||
|
||||
if (link->link_state == 3 && link->initialized) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d", link->etcp->log_name, link->link_state, link->initialized, link->link_status, link->recv_keepalive, link->remote_keepalive, link->etcp->links_up); return; }
|
||||
if (link->link_state == LINK_STATE_CONNECTED && link->initialized) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d", link->etcp->log_name, link->link_state, link->initialized, link->link_status, link->recv_keepalive, link->remote_keepalive, link->etcp->links_up); return; }
|
||||
if (link->etcp->links_up > 0) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED (links_up=%d > 0)", link->etcp->log_name, link->etcp->links_up); return; }
|
||||
if (link->etcp->fin_wait) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED (fin_wait)", link->etcp->log_name); return; }
|
||||
if (link->is_tcp) { etcp_tcp_link_start_reconnect(link); return; } // TCP uses STCP handshake, not ETCP INIT
|
||||
@@ -288,7 +290,7 @@ void etcp_link_enter_init(struct ETCP_LINK* link) {//
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "");
|
||||
if (!link) return;
|
||||
int old_state = link->link_state;
|
||||
link->link_state = 1; // handshake
|
||||
link->link_state = LINK_STATE_HANDSHAKE; // handshake
|
||||
etcp_fire_link_status_cbk(link, old_state, link->link_status);
|
||||
if (link->is_server != 0) return;
|
||||
etcp_link_send_init(link,1,0);// init with reset
|
||||
@@ -299,7 +301,7 @@ void etcp_link_enter_reinit(struct ETCP_LINK* link) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, "");
|
||||
if (!link) return;
|
||||
int old_state = link->link_state;
|
||||
link->link_state = 2; // reconnect
|
||||
link->link_state = LINK_STATE_TRY_RECONNECT; // reconnect
|
||||
etcp_fire_link_status_cbk(link, old_state, link->link_status);
|
||||
etcp_on_link_down(link->etcp, link);
|
||||
if (link->is_server != 0) return;
|
||||
@@ -315,6 +317,19 @@ void etcp_link_enter_reinit(struct ETCP_LINK* link) {
|
||||
}
|
||||
|
||||
|
||||
// Вычислить keepalive по типу устройств: оба десктоп/сервер → min, иначе (есть mobile) → max
|
||||
static uint16_t negotiate_keepalive(uint8_t my_type, uint16_t my_ka,
|
||||
uint8_t peer_type, uint16_t peer_ka) {
|
||||
int my_lp = (my_type == CLIENT_TYPE_MOBILE);
|
||||
int peer_lp = (peer_type == CLIENT_TYPE_MOBILE);
|
||||
uint16_t result = (my_lp || peer_lp) ? (my_ka > peer_ka ? my_ka : peer_ka)
|
||||
: (my_ka < peer_ka ? my_ka : peer_ka);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "negotiate: my=%d(type=%d) peer=%d(type=%d) → %d (rule=%s)",
|
||||
my_ka, my_type, peer_ka, peer_type, result,
|
||||
(my_lp || peer_lp) ? "max(low_power)" : "min(both_desktop)");
|
||||
return result;
|
||||
}
|
||||
|
||||
// Send empty keepalive packet (only timestamp, no sections)
|
||||
static void etcp_link_send_keepalive(struct ETCP_LINK* link) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_KEEPALIVE, "");
|
||||
@@ -403,6 +418,8 @@ static void keepalive_timer_cb(void* arg) {
|
||||
uint64_t now = get_time_tb();
|
||||
uint64_t timeout_units = (uint64_t)link->keepalive_timeout * 10; // ms -> 0.1ms units
|
||||
uint64_t elapsed = now - link->last_recv_local_time;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] ka_check: recv=%d elapsed=%llu timeout=%llu",
|
||||
link->etcp->log_name, link->recv_keepalive, (unsigned long long)elapsed, (unsigned long long)timeout_units);
|
||||
|
||||
if (elapsed > timeout_units) {
|
||||
if (link->recv_keepalive != 0) {
|
||||
@@ -835,13 +852,15 @@ void etcp_socket_remove(struct ETCP_SOCKET* conn) {
|
||||
}
|
||||
|
||||
|
||||
struct ll_entry* entry;
|
||||
while ((entry = conn->links_queue->head) != NULL) {
|
||||
struct link_queue_entry* lqe = (struct link_queue_entry*)entry->data;
|
||||
etcp_link_close(lqe->link);
|
||||
if (conn->links_queue) {
|
||||
struct ll_entry* entry;
|
||||
while ((entry = conn->links_queue->head) != NULL) {
|
||||
struct link_queue_entry* lqe = (struct link_queue_entry*)entry->data;
|
||||
etcp_link_close(lqe->link);
|
||||
}
|
||||
queue_free(conn->links_queue);
|
||||
conn->links_queue = NULL;
|
||||
}
|
||||
queue_free(conn->links_queue);
|
||||
conn->links_queue = NULL;
|
||||
|
||||
u_free(conn);
|
||||
}
|
||||
@@ -925,8 +944,8 @@ struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SE
|
||||
}
|
||||
}
|
||||
|
||||
ts->next = instance->tcp_sockets;
|
||||
instance->tcp_sockets = ts;
|
||||
ts->next = instance->etcp_sockets;
|
||||
instance->etcp_sockets = ts;
|
||||
{ char loc_str[64] = "none", if_str[64] = "none";
|
||||
if (ts->local_addr.ss_family) snprintf(loc_str, sizeof(loc_str), "%s", sockaddr_storage_to_str(&ts->local_addr).str);
|
||||
if (ts->interface_addr.ss_family) snprintf(if_str, sizeof(if_str), "%s", sockaddr_storage_to_str(&ts->interface_addr).str);
|
||||
@@ -938,7 +957,7 @@ struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SE
|
||||
void tcp_socket_remove(struct ETCP_SOCKET* sock) {
|
||||
if (!sock || !sock->instance) return;
|
||||
struct UTUN_INSTANCE* inst = sock->instance;
|
||||
struct ETCP_SOCKET** pp = &inst->tcp_sockets;
|
||||
struct ETCP_SOCKET** pp = &inst->etcp_sockets;
|
||||
while (*pp && *pp != sock) pp = &(*pp)->next;
|
||||
if (*pp) *pp = sock->next;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "tcp_socket_remove: %s sock_id=%u", sock->name, sock->sock_id);
|
||||
@@ -1116,6 +1135,7 @@ void etcp_link_close(struct ETCP_LINK* link) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d closed: addr=%s rcvd=%zub ack=%llub infl=%ub/%upkt",
|
||||
link->etcp->log_name, link->local_link_id, sockaddr_storage_to_str(&link->remote_addr).str, link->total_decrypted,
|
||||
(unsigned long long)link->acked_bytes, link->inflight_bytes, link->inflight_packets);
|
||||
etcp_fire_link_status_cbk(link, link->link_state, link->link_status);
|
||||
u_free(link->bbr);
|
||||
u_free(link);
|
||||
}
|
||||
@@ -1141,10 +1161,17 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
|
||||
etcp_conn_reinit(etcp, "tcp session changed");
|
||||
}
|
||||
etcp->session_id = peer_sid;
|
||||
|
||||
link->peer_device_type = stcp_link_get_peer_device_type(link->tcp_link);
|
||||
{ uint16_t peer_ka = stcp_link_get_peer_keepalive_interval(link->tcp_link);
|
||||
link->keepalive_interval = negotiate_keepalive(etcp->instance->client_type,
|
||||
etcp->instance->keepalive_interval, link->peer_device_type, peer_ka); }
|
||||
}
|
||||
|
||||
link->initialized = 1; link->link_state = 3; link->link_status = 1;
|
||||
int old_state = link->link_state;
|
||||
link->initialized = 1; link->link_state = LINK_STATE_CONNECTED; link->link_status = 1;
|
||||
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;
|
||||
@@ -1154,6 +1181,7 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
|
||||
etcp_link_send_keepalive(link);
|
||||
start_keepalive_timer(link);
|
||||
loadbalancer_link_ready(link);
|
||||
etcp_fire_link_status_cbk(link, old_state, link->link_status);
|
||||
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);
|
||||
@@ -1168,8 +1196,15 @@ 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, .got_initial_pkt = link->etcp->got_initial_pkt, .session_id = link->etcp->session_id};
|
||||
.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);
|
||||
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; }
|
||||
@@ -1179,13 +1214,23 @@ static void tcp_link_reconnect_cb(void *arg) {
|
||||
|
||||
void etcp_tcp_link_start_connect(struct ETCP_LINK *link, struct sockaddr_storage *addr, uint16_t port) {
|
||||
if (!link || !link->etcp || !addr) return;
|
||||
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);
|
||||
@@ -1201,7 +1246,7 @@ void etcp_tcp_link_start_reconnect(struct ETCP_LINK *link) {
|
||||
if (link->etcp->state == 2) return;
|
||||
if (link->tcp_reconnect_timer) return;
|
||||
if (link->tcp_link) { stcp_link_close(link->tcp_link); link->tcp_link = NULL; }
|
||||
link->link_state = 1;
|
||||
link->link_state = LINK_STATE_HANDSHAKE;
|
||||
if (link->etcp->tcp_link_count > 0) link->etcp->tcp_link_count--;
|
||||
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");
|
||||
}
|
||||
@@ -1210,9 +1255,12 @@ static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg) {
|
||||
struct ETCP_LINK *link = (struct ETCP_LINK *)arg;
|
||||
if (!link || !link->etcp) return;
|
||||
if (link->etcp->state == 2) return;
|
||||
int old_state = link->link_state;
|
||||
stcp_link_close(sl);
|
||||
link->tcp_link = NULL;
|
||||
|
||||
etcp_fire_link_status_cbk(link, old_state, 0);
|
||||
|
||||
if (link->is_server) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] TCP server link %d down err=%d, closing", link->etcp->log_name, link->local_link_id, err);
|
||||
etcp_on_link_down(link->etcp, link);
|
||||
@@ -1229,13 +1277,21 @@ static int etcp_tcp_send(struct ETCP_DGRAM* dgram) {
|
||||
if (!link->tcp_link || !stcp_link_is_ready(link->tcp_link)) return -1;
|
||||
link->pkt_sent_since_keepalive = 1;
|
||||
dgram->flag_up = 1;
|
||||
dgram->timestamp = get_current_timestamp();
|
||||
size_t total_len = 3 + dgram->data_len;
|
||||
uint8_t *buf = u_malloc(total_len);
|
||||
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] TCP send: malloc %zu failed", link->etcp->log_name, total_len); return -1; }
|
||||
memcpy(buf, &dgram->timestamp, 2);
|
||||
buf[2] = dgram->flag_up;
|
||||
if (dgram->data_len) memcpy(buf + 3, dgram->data, dgram->data_len);
|
||||
int rc;
|
||||
if (link->send_hook) rc = (int)link->send_hook(0, dgram->data, dgram->data_len, NULL, 0, link, link->send_hook_ctx);
|
||||
else if (link->tcp_link) rc = stcp_link_send(link->tcp_link, dgram->data, dgram->data_len) == 0 ? (int)dgram->data_len : -1;
|
||||
if (link->send_hook) rc = (int)link->send_hook(0, buf, total_len, NULL, 0, link, link->send_hook_ctx);
|
||||
else if (link->tcp_link) rc = stcp_link_send(link->tcp_link, buf, total_len) == 0 ? (int)dgram->data_len : -1;
|
||||
else rc = -1;
|
||||
u_free(buf);
|
||||
if (rc > 0) link->total_encrypted += (size_t)rc;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] TCP send: link=%d dlen=%d rc=%d via=%s",
|
||||
link->etcp->log_name, link->local_link_id, dgram->data_len, rc,
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] TCP send: link=%d total=%zu dlen=%d rc=%d via=%s",
|
||||
link->etcp->log_name, link->local_link_id, total_len, dgram->data_len, rc,
|
||||
link->send_hook ? "hook" : (link->tcp_link ? "stcp" : "NONE"));
|
||||
return rc;
|
||||
}
|
||||
@@ -1686,6 +1742,8 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
|
||||
}
|
||||
}
|
||||
memcpy(resp->ed25519_pubkey, e_sock->instance->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
resp->device_type = e_sock->instance->client_type;
|
||||
*(uint16_t*)resp->keepalive = htobe16(e_sock->instance->keepalive_interval);
|
||||
pkt->noencrypt_len=0;
|
||||
pkt->link=link;
|
||||
link->recv_keepalive = 1;
|
||||
@@ -1718,7 +1776,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
|
||||
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
link->initialized = 1;
|
||||
{ int old_state = link->link_state; link->link_state = 3; etcp_fire_link_status_cbk(link, old_state, link->link_status); }
|
||||
{ int old_state = link->link_state; link->link_state = LINK_STATE_CONNECTED; etcp_fire_link_status_cbk(link, old_state, link->link_status); }
|
||||
if (link->init_timer) {
|
||||
uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer);
|
||||
link->init_timer = NULL;
|
||||
@@ -1735,6 +1793,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
|
||||
}
|
||||
|
||||
static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, uint8_t pkt_code, size_t pkt_len) {
|
||||
if (!e_sock) return -1;
|
||||
if (pkt_len < ETCP_INIT_RESP_SIZE) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "INIT_RESPONSE too short: pkt_len=%zu", pkt_len);
|
||||
return 46;
|
||||
@@ -1817,12 +1876,16 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
|
||||
memcpy(link->etcp->peer_ed25519_pubkey, resp->ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CRYPTO, "[%s] Received Ed25519 pubkey from peer", link->etcp->log_name);
|
||||
|
||||
link->peer_device_type = resp->device_type;
|
||||
{ uint16_t server_ka = (resp->keepalive[0]<<8) | resp->keepalive[1];
|
||||
link->keepalive_interval = negotiate_keepalive(link->etcp->instance->client_type,
|
||||
link->etcp->instance->keepalive_interval, resp->device_type, server_ka); }
|
||||
|
||||
link->etcp->peer_node_id = server_node_id;
|
||||
etcp_update_log_name(link->etcp);
|
||||
|
||||
link->initialized = 1;// получен init response (client)
|
||||
{ int old_state = link->link_state; link->link_state = 3; etcp_fire_link_status_cbk(link, old_state, link->link_status); }
|
||||
{ int old_state = link->link_state; link->link_state = LINK_STATE_CONNECTED; etcp_fire_link_status_cbk(link, old_state, link->link_status); }
|
||||
if (link->init_timer) {
|
||||
uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer);
|
||||
link->init_timer = NULL;
|
||||
@@ -1876,7 +1939,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
// 66 - не удалось создать линк
|
||||
struct ETCP_SOCKET* e_sock = (struct ETCP_SOCKET*)arg;
|
||||
if (!e_sock) return;
|
||||
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
uint8_t data[PACKET_DATA_SIZE];
|
||||
socklen_t addr_len=sizeof(addr);
|
||||
@@ -1911,7 +1974,9 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
recv_len, (unsigned long long)link->etcp->crypto_ctx.rx_counter);
|
||||
sc_status_t dec_rc = sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, (uint8_t*)&pkt->timestamp, &pkt_len);
|
||||
if (!dec_rc) {
|
||||
goto process_decrypted;
|
||||
int ec = etcp_packet_decrypted(e_sock, pkt, link, pkt_len);
|
||||
if (ec) { errorcode = ec; goto ec_fr; }
|
||||
return;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp: DECRYPT FAIL on existing link. rc=%d link=%p log=%s from=%s sess=%d link_state=%d keepalive=%d enc_errs=%zu my_pub=%016llx peer_pub=%016llx seskey=%02x%02x%02x%02x",
|
||||
dec_rc, link, link->etcp->log_name, sockaddr_storage_to_str(&addr).str, link->etcp->crypto_ctx.session_ready,
|
||||
@@ -2122,32 +2187,32 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
struct ETCP_LINK* existing_link = etcp_link_find_by_remote_id(conn, req->link_id);
|
||||
if (!existing_link) {
|
||||
existing_link = etcp_link_find_by_addr(e_sock, &addr);
|
||||
if (existing_link && existing_link->etcp == conn) {
|
||||
if (memcmp(conn->crypto_ctx.peer_public_key, sc.peer_public_key, SC_PUBKEY_SIZE)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] link address match but pubkey mismatch, firing node_changed", conn->log_name);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "pubkey mismatch on reused link for node %016llx", (unsigned long long)peer_id);
|
||||
conn->callbacks_running = 1;
|
||||
etcp_cbk_fire(conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
conn->callbacks_running = 0;
|
||||
if (existing_link && existing_link->etcp == conn) {
|
||||
if (memcmp(conn->crypto_ctx.peer_public_key, sc.peer_public_key, SC_PUBKEY_SIZE)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] link address match but pubkey mismatch, firing node_changed", conn->log_name);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "pubkey mismatch on reused link for node %016llx", (unsigned long long)peer_id);
|
||||
conn->callbacks_running = 1;
|
||||
etcp_cbk_fire(conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
conn->callbacks_running = 0;
|
||||
errorcode = 67;
|
||||
goto ec_fr;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] found existing outbound link by addr for incoming INIT, reusing link=%p",
|
||||
conn->log_name, existing_link);
|
||||
} else if (existing_link) {
|
||||
struct ETCP_CONN* old_conn = existing_link->etcp;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] conflicting link at %s belongs to %s, firing node_changed",
|
||||
conn->log_name, sockaddr_storage_to_str(&addr).str, old_conn->log_name);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "link address conflict for node %016llx, firing node_changed callbacks on %s",
|
||||
(unsigned long long)peer_id, old_conn->log_name);
|
||||
old_conn->callbacks_running = 1;
|
||||
etcp_cbk_fire(old_conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
old_conn->callbacks_running = 0;
|
||||
errorcode = 67;
|
||||
goto ec_fr;
|
||||
} else {
|
||||
existing_link = NULL;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] found existing outbound link by addr for incoming INIT, reusing link=%p",
|
||||
conn->log_name, existing_link);
|
||||
} else if (existing_link) {
|
||||
struct ETCP_CONN* old_conn = existing_link->etcp;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] conflicting link at %s belongs to %s, firing node_changed",
|
||||
conn->log_name, sockaddr_storage_to_str(&addr).str, old_conn->log_name);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "link address conflict for node %016llx, firing node_changed callbacks on %s",
|
||||
(unsigned long long)peer_id, old_conn->log_name);
|
||||
old_conn->callbacks_running = 1;
|
||||
etcp_cbk_fire(old_conn, ETCP_CBK_EVENT_NODE_CHANGED);
|
||||
old_conn->callbacks_running = 0;
|
||||
errorcode = 67;
|
||||
goto ec_fr;
|
||||
} else {
|
||||
existing_link = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t send_reset = 0;
|
||||
@@ -2256,7 +2321,9 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
etcp_conn_reinit(conn, "session changed");
|
||||
} }
|
||||
}
|
||||
link->keepalive_interval=(req->keepalive[0]<<8) | req->keepalive[1];
|
||||
uint16_t client_ka = (req->keepalive[0]<<8) | req->keepalive[1];
|
||||
link->peer_device_type = req->device_type;
|
||||
link->keepalive_interval = negotiate_keepalive(e_sock->instance->client_type, e_sock->instance->keepalive_interval, req->device_type, client_ka);
|
||||
link->recovery_interval=((req->recovery[0]<<8) | req->recovery[1])*100;// timebase в link, timebase/100 в кодограмме
|
||||
if (link->keepalive_interval < 10) link->keepalive_interval = 10;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "set keepalive for link=%d", link->keepalive_interval);
|
||||
@@ -2276,16 +2343,29 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
return;
|
||||
|
||||
|
||||
process_decrypted:
|
||||
ec_fr:
|
||||
e_sock->pkt_format_errors++;
|
||||
if (e_sock->pkt_format_errors < 3 || (e_sock->pkt_format_errors % 500 == 0))
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "error %d, from %s (count=%zu)", errorcode, sockaddr_storage_to_str(&addr).str, e_sock->pkt_format_errors);
|
||||
e_sock->errorcode=errorcode;
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
int etcp_packet_decrypted(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
|
||||
struct ETCP_LINK* link, size_t pkt_len) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Decrypt ok - normal pkt");
|
||||
if (pkt_len<3) { errorcode=46; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "decrypted packet too small, size=%zu", pkt_len); goto ec_fr; }
|
||||
if (pkt_len<3) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "decrypted packet too small, size=%zu", pkt_len); return 46; }
|
||||
pkt->data_len=pkt_len-3;
|
||||
pkt->noencrypt_len=0;
|
||||
pkt->link=link;
|
||||
if (pkt->data_len && pkt->data[0] != ETCP_KEEPALIVE) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] decrypt: code=%02x dlen=%u plen=%zu recv=%d sock=%p",
|
||||
link->etcp->log_name, pkt->data[0], pkt->data_len, pkt_len,
|
||||
link->recv_keepalive, (void*)e_sock);
|
||||
}
|
||||
|
||||
link->remote_keepalive = pkt->flag_up;
|
||||
|
||||
/* restore recv_keepalive BEFORE computing link_status = remote && local */
|
||||
if (link->recv_keepalive != 1) {
|
||||
link->recv_keepalive = 1;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d recv_keepalive restored to 1 (was 0) link_status=%d remote_ka=%d state=%d init=%d links_up=%d",
|
||||
@@ -2297,19 +2377,16 @@ process_decrypted:
|
||||
if (link->link_status != was_up)
|
||||
etcp_fire_link_status_cbk(link, link->link_state, was_up);
|
||||
if (link->link_status && !was_up && link->initialized) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d status popped UP: recv_ka=%d remote_ka=%d state=%d init=%d → calling loadbalancer_link_ready", link->etcp->log_name, link->local_link_id, link->recv_keepalive, link->remote_keepalive, link->link_state, link->initialized);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d status popped UP: recv_ka=%d remote_ka=%d state=%d init=%d", link->etcp->log_name, link->local_link_id, link->recv_keepalive, link->remote_keepalive, link->link_state, link->initialized);
|
||||
loadbalancer_link_ready(link);
|
||||
}
|
||||
|
||||
link->last_recv_local_time=get_time_tb();
|
||||
link->last_recv_timestamp=pkt->timestamp;
|
||||
link->last_recv_updated=1;
|
||||
|
||||
// Count decrypted bytes
|
||||
link->total_decrypted += pkt->data_len;
|
||||
|
||||
size_t offset = 0;
|
||||
uint8_t pkt_code = pkt->data[offset++];
|
||||
uint8_t pkt_code = pkt->data[0];
|
||||
|
||||
if (pkt_code == ETCP_KEEPALIVE) {
|
||||
if (pkt->data_len >= 3) {
|
||||
@@ -2318,40 +2395,29 @@ process_decrypted:
|
||||
}
|
||||
link->keepalive_recv_count++;
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return; // KA handled, nothing more to process
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pkt_code == ETCP_INIT_RESPONSE || pkt_code == ETCP_INIT_RESPONSE_NOINIT) {
|
||||
int ret = handle_init_response_client(e_sock, pkt, link, pkt_code, pkt_len);
|
||||
if (ret) { errorcode = ret; goto ec_fr; }
|
||||
return;
|
||||
if (ret) return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (link->link_state == 2) {// из recovery получен нормальный пакет - восстанавливаем линк в нормальный режим
|
||||
if (link->link_state == LINK_STATE_TRY_RECONNECT) {// 0 - just init, 1 - handshake, 2 - try reconnect, 3 - connected
|
||||
start_keepalive_timer(link);
|
||||
etcp_link_send_keepalive(link); // Start keepalive timer
|
||||
{ int old_state = link->link_state; link->link_state = 3; etcp_fire_link_status_cbk(link, old_state, link->link_status); }
|
||||
etcp_link_send_keepalive(link);
|
||||
int old_state = link->link_state; link->link_state = LINK_STATE_CONNECTED;
|
||||
etcp_fire_link_status_cbk(link, old_state, link->link_status);
|
||||
}
|
||||
|
||||
|
||||
// log_dump("RECV decrypted:", pkt->data, pkt->data_len, link);
|
||||
|
||||
if (link->link_state == 3) {
|
||||
if (link->link_state == LINK_STATE_CONNECTED) {
|
||||
if (memory_pool_is_freed(e_sock->instance->pkt_pool, pkt)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "pkt=%p ALREADY FREED in pkt_pool — HALTING", (void*)pkt);
|
||||
volatile int _halt = 1; while (_halt) {}
|
||||
}
|
||||
etcp_conn_input(pkt);
|
||||
} else memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
|
||||
ec_fr:
|
||||
e_sock->pkt_format_errors++;
|
||||
if (e_sock->pkt_format_errors < 3 || (e_sock->pkt_format_errors % 500 == 0))
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "error %d, from %s (count=%zu)", errorcode, sockaddr_storage_to_str(&addr).str, e_sock->pkt_format_errors);
|
||||
e_sock->errorcode=errorcode;
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize only sockets (servers for incoming connections)
|
||||
@@ -2424,7 +2490,7 @@ int init_sockets(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TCP transport: create stcp_server instead of UDP socket
|
||||
if (server->transport) {
|
||||
uint16_t port = 0;
|
||||
@@ -2469,7 +2535,7 @@ int init_sockets(struct UTUN_INSTANCE* instance) {
|
||||
continue;
|
||||
}
|
||||
success_count++;
|
||||
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Initialized server %s on %s (links: %d)",
|
||||
server->name, sockaddr_storage_to_str(&server->ip).str, queue_entry_count(e_sock->links_queue));
|
||||
server = server->next;
|
||||
|
||||
@@ -85,6 +85,8 @@ struct ETCP_INIT_REQUEST_PKT {
|
||||
uint8_t src_port[2]; // 27: client interface_addr port (big-endian)
|
||||
uint8_t collision; // 29: 1 = cross-connect, remote claims master
|
||||
uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 30: client Ed25519 pubkey (32 bytes)
|
||||
// V4 fields:
|
||||
uint8_t device_type; // 62: CLIENT_TYPE_SERVER/DESKTOP/MOBILE
|
||||
} __attribute__((packed));
|
||||
#define ETCP_INIT_REQ_SIZE sizeof(struct ETCP_INIT_REQUEST_PKT)
|
||||
|
||||
@@ -103,6 +105,9 @@ struct ETCP_INIT_RESPONSE_PKT {
|
||||
uint8_t peer_port[2]; // 23: client's external NAT port (big-endian)
|
||||
// V3 fields:
|
||||
uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 25: server Ed25519 pubkey (32 bytes)
|
||||
// V4 fields:
|
||||
uint8_t device_type; // 57: CLIENT_TYPE_SERVER/DESKTOP/MOBILE
|
||||
uint8_t keepalive[2]; // 58: server keepalive interval (big-endian)
|
||||
} __attribute__((packed));
|
||||
#define ETCP_INIT_RESP_SIZE sizeof(struct ETCP_INIT_RESPONSE_PKT)
|
||||
|
||||
@@ -178,6 +183,10 @@ struct ETCP_SOCKET {
|
||||
#define NAT_VERIFIED_DIRECT 7 // real public IP, no NAT
|
||||
|
||||
|
||||
#define LINK_STATE_HANDSHAKE 1
|
||||
#define LINK_STATE_TRY_RECONNECT 2
|
||||
#define LINK_STATE_CONNECTED 3
|
||||
|
||||
// Тип функции-перехватчика отправки UDP.
|
||||
// Если link->send_hook != NULL, etcp_udp_send вызывает её вместо socket_sendto.
|
||||
struct ETCP_LINK;
|
||||
@@ -270,6 +279,7 @@ struct ETCP_LINK {
|
||||
uint8_t pkt_sent_since_keepalive; // Флаг: был ли отправлен пакет с последнего keepalive тика
|
||||
uint32_t keepalive_sent_count; // Счётчик отправленных keepalive
|
||||
uint32_t keepalive_recv_count; // Счётчик полученных keepalive
|
||||
uint8_t peer_device_type; // CLIENT_TYPE_* удалённой стороны (из handshake)
|
||||
uint16_t handshake_minsize; // минимальный размер udp при handshake
|
||||
uint16_t handshake_maxsize; // мax размер udp при handshake (выбирает рандом)
|
||||
|
||||
@@ -361,6 +371,9 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link);
|
||||
void etcp_tcp_link_start_connect(struct ETCP_LINK *link, struct sockaddr_storage *addr, uint16_t port);
|
||||
void etcp_tcp_link_start_reconnect(struct ETCP_LINK *link);
|
||||
|
||||
int etcp_packet_decrypted(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
|
||||
struct ETCP_LINK* link, size_t pkt_len);
|
||||
|
||||
int etcp_send_ping(struct UTUN_INSTANCE* instance, const uint8_t* peer_pubkey_bin,
|
||||
const struct sockaddr_storage* addr, int timeout_ms,
|
||||
etcp_ping_callback_t cb, void* user_arg,
|
||||
|
||||
@@ -129,7 +129,7 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
|
||||
struct ETCP_SOCKET* specific_sock) {
|
||||
struct ETCP_CONN* conn = entry->conn;
|
||||
struct UTUN_INSTANCE* inst = conn->instance;
|
||||
int link_count = 0;
|
||||
int link_count = 0, v4_skip = 0, v6_skip = 0, v4_addrs = 0, v6_addrs = 0;
|
||||
uint64_t nid = entry->node_id;
|
||||
|
||||
/* ---- IPv4 ---- */
|
||||
@@ -148,7 +148,8 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
|
||||
if (sock_count > 0) {
|
||||
int rr = 0;
|
||||
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) {
|
||||
if (a->port == 0 || !(a->protocol & TOPO_PROTO_UDP)) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[ncd] v4 skip proto=%02x port=%d node=0x%016llx", a->protocol, (int)a->port, (unsigned long long)nid); continue; }
|
||||
v4_addrs++;
|
||||
if (a->port == 0 || !(a->protocol & TOPO_PROTO_UDP)) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[ncd] v4 skip proto=%02x port=%d node=0x%016llx", a->protocol, (int)a->port, (unsigned long long)nid); v4_skip++; continue; }
|
||||
int zero = 1; for (int j = 0; j < 4; j++) if (a->addr[j] != 0) { zero = 0; break; }
|
||||
if (zero) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[ncd] v4 skip zero-addr node=0x%016llx", (unsigned long long)nid); continue; }
|
||||
struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET;
|
||||
@@ -198,7 +199,8 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
|
||||
if (sock_count > 0) {
|
||||
int rr = 0;
|
||||
for (const struct TOPO_ADDR6* a = ni->v6_addrs; a; a = a->next) {
|
||||
if (a->port == 0 || !(a->protocol & TOPO_PROTO_UDP)) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[ncd] v6 skip proto=%02x port=%d node=0x%016llx", a->protocol, (int)a->port, (unsigned long long)nid); continue; }
|
||||
v6_addrs++;
|
||||
if (a->port == 0 || !(a->protocol & TOPO_PROTO_UDP)) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[ncd] v6 skip proto=%02x port=%d node=0x%016llx", a->protocol, (int)a->port, (unsigned long long)nid); v6_skip++; continue; }
|
||||
int zero = 1; for (int j = 0; j < 16; j++) if (a->addr[j] != 0) { zero = 0; break; }
|
||||
if (zero) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[ncd] v6 skip zero-addr node=0x%016llx", (unsigned long long)nid); continue; }
|
||||
struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6;
|
||||
@@ -230,6 +232,10 @@ static int ncd_create_links(struct ncd_entry* entry, struct TOPO_NODE* ni,
|
||||
}
|
||||
}
|
||||
|
||||
if (link_count == 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] create_links: node=0x%016llx v4=%d/skp=%d v6=%d/skp=%d → %d UDP links (TCP handled by cm_direct_add_links)",
|
||||
(unsigned long long)nid, v4_addrs, v4_skip, v6_addrs, v6_skip, link_count);
|
||||
}
|
||||
return link_count;
|
||||
}
|
||||
|
||||
@@ -636,7 +642,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id,
|
||||
int link_count = ncd_create_links(entry, ni, specific_sock);
|
||||
|
||||
if (link_count == 0)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] no links created for node=0x%016llx", (unsigned long long)node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] no links created (UDP only, TCP added by conn_mgr) node=0x%016llx", (unsigned long long)node_id);
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "[ncd] connect timer SET: node=0x%016llx value_tb=%u now_tb=%llu path=NEW_node_conn_direct_open",
|
||||
(unsigned long long)node_id, inst->etcp_connect_timeout_tb, (unsigned long long)get_time_tb());
|
||||
@@ -778,7 +784,7 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id,
|
||||
int link_count = ncd_create_links(entry, ni, specific_sock);
|
||||
|
||||
if (link_count == 0)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_NCD, "[ncd] open_node no links created for node=0x%016llx", (unsigned long long)node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node (UDP only, TCP added by conn_mgr) node=0x%016llx links=%d", (unsigned long long)node_id, link_count);
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "[ncd] connect timer SET: node=0x%016llx value_tb=%u now_tb=%llu path=NEW_node_conn_direct_open_node",
|
||||
(unsigned long long)node_id, inst->etcp_connect_timeout_tb, (unsigned long long)get_time_tb());
|
||||
|
||||
@@ -23,10 +23,10 @@ struct UTUN_INSTANCE;
|
||||
#define STCP_HS_TIMEOUT 50000 // 5s in 0.1ms timebase units
|
||||
#define STCP_CONNECT_TIMEOUT 100000 // 10s in 0.1ms timebase units
|
||||
|
||||
#define STCP_HS_CLIENT_MIN (SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT) // 72+43=115
|
||||
#define STCP_HS_SERVER_MIN (SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_SERVER) // 72+43=115
|
||||
#define STCP_HS_ENC_CLIENT 43 // ed25519_pubkey(32) + got_initial_pkt(1) + session_id(4) + padding_size(2) + CRC32(4)
|
||||
#define STCP_HS_ENC_SERVER 43 // ed25519_pubkey(32) + got_initial_pkt(1) + session_id(4) + padding_size(2) + CRC32(4)
|
||||
#define STCP_HS_CLIENT_MIN (SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT) // 72+46=118
|
||||
#define STCP_HS_SERVER_MIN (SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_SERVER) // 72+46=118
|
||||
#define STCP_HS_ENC_CLIENT 46 // ed25519_pubkey(32) + got_initial_pkt(1) + session_id(4) + padding_size(2) + device_type(1) + keepalive(2) + CRC32(4)
|
||||
#define STCP_HS_ENC_SERVER 46 // ed25519_pubkey(32) + got_initial_pkt(1) + session_id(4) + padding_size(2) + device_type(1) + keepalive(2) + CRC32(4)
|
||||
|
||||
#define STCP_STREAM_CLIENT_SEND 0
|
||||
#define STCP_STREAM_SERVER_SEND 1
|
||||
@@ -76,6 +76,10 @@ struct stcp_conn {
|
||||
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
|
||||
uint8_t device_type; // CLIENT_TYPE_* sent to peer during handshake
|
||||
uint16_t keepalive_interval; // keepalive interval sent to peer during handshake
|
||||
uint8_t peer_device_type; // CLIENT_TYPE_* from peer handshake
|
||||
uint16_t peer_keepalive_interval; // keepalive interval from peer handshake
|
||||
|
||||
struct ll_queue *rx_queue;
|
||||
struct ll_queue *tx_queue;
|
||||
|
||||
@@ -54,14 +54,16 @@ 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 plain[39]; memcpy(plain, my_ed25519, 32);
|
||||
uint8_t plain[42]; memcpy(plain, my_ed25519, 32);
|
||||
plain[32] = c->got_initial_pkt;
|
||||
memcpy(plain + 33, &c->session_id, 4);
|
||||
plain[37] = (uint8_t)padding; plain[38] = (uint8_t)(padding >> 8);
|
||||
uint32_t crc = crc32_calc(plain, 39);
|
||||
plain[39] = c->device_type;
|
||||
*(uint16_t*)(plain + 40) = htobe16(c->keepalive_interval);
|
||||
uint32_t crc = crc32_calc(plain, 42);
|
||||
uint8_t *enc_dst = hs + SC_PUBKEY_ENC_SIZE;
|
||||
memcpy(enc_dst, plain, 39);
|
||||
enc_dst[39] = (uint8_t)(crc >> 0); enc_dst[40] = (uint8_t)(crc >> 8); enc_dst[41] = (uint8_t)(crc >> 16); enc_dst[42] = (uint8_t)(crc >> 24);
|
||||
memcpy(enc_dst, plain, 42);
|
||||
enc_dst[42] = (uint8_t)(crc >> 0); enc_dst[43] = (uint8_t)(crc >> 8); enc_dst[44] = (uint8_t)(crc >> 16); enc_dst[45] = (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);
|
||||
|
||||
@@ -94,8 +96,10 @@ static void client_hs_cb(struct stcp_conn *c, uint8_t *data, size_t len) {
|
||||
c->peer_got_initial_pkt = enc_hs[32];
|
||||
memcpy(&c->peer_session_id, enc_hs + 33, 4);
|
||||
uint16_t padding_size = (uint16_t)enc_hs[37] | ((uint16_t)enc_hs[38] << 8);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: server response OK gop=%d sid=%08x padding=%u",
|
||||
c->peer_got_initial_pkt, c->peer_session_id, padding_size);
|
||||
c->peer_device_type = enc_hs[39];
|
||||
c->peer_keepalive_interval = ((uint16_t)enc_hs[40] << 8) | enc_hs[41];
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: server response OK gop=%d sid=%08x padding=%u dev=%d ka=%u",
|
||||
c->peer_got_initial_pkt, c->peer_session_id, padding_size, c->peer_device_type, c->peer_keepalive_interval);
|
||||
stcp_recv_set(c, padding_size, 0, client_hs_padding_cb);
|
||||
}
|
||||
|
||||
@@ -145,8 +149,10 @@ 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,
|
||||
uint8_t device_type, uint16_t keepalive_interval,
|
||||
stcp_ready_cb ready_cb, void *arg,
|
||||
stcp_close_cb close_cb, void *close_arg) {
|
||||
stcp_close_cb close_cb, void *close_arg,
|
||||
const struct sockaddr_storage *local_addr) {
|
||||
if (!ua || !addr || !keys || !peer_pubkey || !ready_cb) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "invalid args"); return NULL; }
|
||||
struct stcp_client *cli = u_calloc(1, sizeof(struct stcp_client));
|
||||
if (!cli) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "calloc failed"); return NULL; }
|
||||
@@ -161,6 +167,8 @@ 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->device_type = device_type;
|
||||
c->keepalive_interval = keepalive_interval;
|
||||
|
||||
struct addrinfo hints = {0};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
@@ -174,6 +182,11 @@ struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uin
|
||||
c->sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (c->sock == SOCKET_INVALID) { freeaddrinfo(res); u_free(cli); return NULL; }
|
||||
socket_set_nonblocking(c->sock);
|
||||
if (local_addr && local_addr->ss_family) {
|
||||
if (bind(c->sock, (const struct sockaddr*)local_addr, local_addr->ss_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "stcp_client bind to %s port=0 failed err=%d(%s), continuing to %s:%u",
|
||||
sockaddr_storage_to_str(local_addr).str, socket_get_error(), socket_strerror(socket_get_error()), addr, port);
|
||||
}
|
||||
int conn_ret = connect(c->sock, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo(res);
|
||||
if (conn_ret < 0) {
|
||||
|
||||
@@ -16,8 +16,10 @@ 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,
|
||||
uint8_t device_type, uint16_t keepalive_interval,
|
||||
stcp_ready_cb ready_cb, void *arg,
|
||||
stcp_close_cb close_cb, void *close_arg);
|
||||
stcp_close_cb close_cb, void *close_arg,
|
||||
const struct sockaddr_storage *local_addr);
|
||||
void stcp_client_destroy(struct stcp_client *cli);
|
||||
struct stcp_conn *stcp_client_get_conn(struct stcp_client *cli);
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ struct stcp_link {
|
||||
|
||||
uint8_t peer_got_initial_pkt; // received from peer during handshake
|
||||
uint32_t peer_session_id; // received from peer during handshake
|
||||
uint8_t peer_device_type; // CLIENT_TYPE_* from peer handshake
|
||||
uint16_t peer_keepalive_interval; // keepalive interval from peer handshake
|
||||
};
|
||||
|
||||
// ====== rx dispatch ======
|
||||
@@ -56,31 +58,31 @@ static void link_rx_cb(struct ll_queue *q, void *arg) {
|
||||
if (!e) { queue_resume_callback(q); return; }
|
||||
|
||||
if (link->etcp_conn && link->etcp_link && link->cfg.inst) {
|
||||
if (e->len >= 1 && e->dgram[0] == ETCP_KEEPALIVE) {
|
||||
struct ETCP_LINK *l = link->etcp_link;
|
||||
if (e->len >= 3) { uint16_t pp = e->dgram[1] | ((uint16_t)e->dgram[2] << 8); l->keepalive_timeout = (uint32_t)pp * KA_TIMEOUT_MULT; }
|
||||
l->recv_keepalive = 1; l->remote_keepalive = 1; l->link_status = 1; l->keepalive_recv_count++;
|
||||
l->total_decrypted += e->len;
|
||||
l->last_recv_local_time = get_time_tb();
|
||||
queue_dgram_free(e); queue_entry_free(e);
|
||||
} else {
|
||||
if (e->len > PACKET_DATA_SIZE) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_link rx oversized pkt: %u > %u, closing link=%p", e->len, (unsigned)PACKET_DATA_SIZE, (void*)link);
|
||||
queue_dgram_free(e); queue_entry_free(e);
|
||||
queue_resume_callback(q);
|
||||
if (link->conn) stcp_conn_do_close(link->conn, EMSGSIZE);
|
||||
return;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_link rx → etcp_conn_input len=%zu link=%p", e->len, (void*)link->etcp_link);
|
||||
struct ETCP_DGRAM *pkt = memory_pool_alloc(link->cfg.inst->pkt_pool);
|
||||
if (pkt) {
|
||||
pkt->link = link->etcp_link; pkt->data_len = (uint16_t)e->len; pkt->noencrypt_len = 0;
|
||||
if (e->len > 0) memcpy(pkt->data, e->dgram, e->len);
|
||||
link->etcp_link->total_decrypted += e->len;
|
||||
etcp_conn_input(pkt);
|
||||
}
|
||||
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,
|
||||
e->dgram && e->len>=3 ? e->dgram[1] : 0,
|
||||
e->dgram && e->len>=3 ? e->dgram[2] : 0,
|
||||
(void*)link->etcp_link->conn);
|
||||
if (e->len > PACKET_DATA_SIZE) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_link rx oversized pkt: %u > %u, closing link=%p", e->len, (unsigned)PACKET_DATA_SIZE, (void*)link);
|
||||
queue_dgram_free(e); queue_entry_free(e);
|
||||
queue_resume_callback(q);
|
||||
if (link->conn) stcp_conn_do_close(link->conn, EMSGSIZE);
|
||||
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);
|
||||
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;
|
||||
if (e->len > 3) memcpy(pkt->data, e->dgram + 3, e->len - 3);
|
||||
else memset(pkt->data, 0, 1);
|
||||
pkt->link = link->etcp_link;
|
||||
link->etcp_link->total_decrypted += e->len;
|
||||
struct ETCP_SOCKET *sock = link->etcp_link->conn;
|
||||
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;
|
||||
uint8_t id = (e->dgram && e->len > 0) ? e->dgram[0] : 0;
|
||||
@@ -115,6 +117,8 @@ static void server_accept_cb(struct stcp_conn *conn, void *arg) {
|
||||
link->conn = conn;
|
||||
link->peer_got_initial_pkt = conn->peer_got_initial_pkt;
|
||||
link->peer_session_id = conn->peer_session_id;
|
||||
link->peer_device_type = conn->peer_device_type;
|
||||
link->peer_keepalive_interval = conn->peer_keepalive_interval;
|
||||
|
||||
stcp_conn_set_on_close(conn, stcp_link_on_stcp_close, link);
|
||||
|
||||
@@ -140,6 +144,8 @@ static void client_ready_cb(struct stcp_conn *conn, void *arg) {
|
||||
link->conn = conn;
|
||||
link->peer_got_initial_pkt = conn->peer_got_initial_pkt;
|
||||
link->peer_session_id = conn->peer_session_id;
|
||||
link->peer_device_type = conn->peer_device_type;
|
||||
link->peer_keepalive_interval = conn->peer_keepalive_interval;
|
||||
|
||||
stcp_conn_set_on_close(conn, stcp_link_on_stcp_close, link);
|
||||
|
||||
@@ -152,8 +158,18 @@ 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);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: client handshake OK, link=%p etcp_link=%p",
|
||||
(void*)link, (void*)link->etcp_link);
|
||||
if (link->cfg.remote_addr) {
|
||||
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,
|
||||
link->peer_got_initial_pkt, link->peer_session_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);
|
||||
}
|
||||
@@ -220,11 +236,14 @@ struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg) {
|
||||
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,
|
||||
client_ready_cb, link, NULL, NULL);
|
||||
cfg->inst ? cfg->inst->client_type : 0,
|
||||
cfg->inst ? cfg->inst->keepalive_interval : 200,
|
||||
client_ready_cb, link, NULL, NULL, cfg->local_addr);
|
||||
if (!link->cli) { u_free(link); return NULL; }
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_link: connecting to %s:%u pubkey=%016llx",
|
||||
addr_str, port, (unsigned long long)*(const uint64_t*)pubkey);
|
||||
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");
|
||||
return link;
|
||||
}
|
||||
|
||||
@@ -305,6 +324,26 @@ const struct sockaddr_storage *stcp_link_get_remote_addr(struct stcp_link *link)
|
||||
return link && link->cfg.remote_addr ? link->cfg.remote_addr : NULL;
|
||||
}
|
||||
|
||||
static struct sockaddr_storage g_peer_addr;
|
||||
const struct sockaddr_storage *stcp_link_get_peer_addr(struct stcp_link *link) {
|
||||
if (!link || !link->conn || link->conn->sock == SOCKET_INVALID) return NULL;
|
||||
memset(&g_peer_addr, 0, sizeof(g_peer_addr));
|
||||
socklen_t slen = sizeof(g_peer_addr);
|
||||
if (getpeername(link->conn->sock, (struct sockaddr*)&g_peer_addr, &slen) == 0)
|
||||
return &g_peer_addr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sockaddr_storage g_local_addr;
|
||||
const struct sockaddr_storage *stcp_link_get_local_addr(struct stcp_link *link) {
|
||||
if (!link || !link->conn || link->conn->sock == SOCKET_INVALID) return NULL;
|
||||
memset(&g_local_addr, 0, sizeof(g_local_addr));
|
||||
socklen_t slen = sizeof(g_local_addr);
|
||||
if (getsockname(link->conn->sock, (struct sockaddr*)&g_local_addr, &slen) == 0)
|
||||
return &g_local_addr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void stcp_link_set_on_ready(struct stcp_link *link, stcp_link_cb cb, void *arg) {
|
||||
if (!link) return;
|
||||
link->on_ready_cb = cb;
|
||||
@@ -333,6 +372,14 @@ uint32_t stcp_link_get_peer_session_id(struct stcp_link *link) {
|
||||
return link ? link->peer_session_id : 0;
|
||||
}
|
||||
|
||||
uint8_t stcp_link_get_peer_device_type(struct stcp_link *link) {
|
||||
return link ? link->peer_device_type : 0;
|
||||
}
|
||||
|
||||
uint16_t stcp_link_get_peer_keepalive_interval(struct stcp_link *link) {
|
||||
return link ? link->peer_keepalive_interval : 0;
|
||||
}
|
||||
|
||||
void stcp_server_list_add(struct UTUN_INSTANCE *inst, struct stcp_server *srv) {
|
||||
if (!inst || !srv) return;
|
||||
srv->next = inst->stcp_servers;
|
||||
|
||||
@@ -27,7 +27,8 @@ struct stcp_link_config {
|
||||
struct UTUN_INSTANCE *inst; // для диспатча через api_bindings
|
||||
const uint8_t *peer_pubkey; // pubkey пира (клиент)
|
||||
int peer_pubkey_mode; // 0=binary, 1=hex
|
||||
const struct sockaddr_storage *remote_addr; // адрес пира (клиент)
|
||||
const struct sockaddr_storage *local_addr; // локальный адрес/интерфейс для bind (клиент, NULL=авто)
|
||||
const struct sockaddr_storage *remote_addr; // адрес пира (клиент)
|
||||
uint16_t remote_port; // порт пира (клиент)
|
||||
int listen_family; // AF_INET или AF_INET6 для сервера (0 = v4)
|
||||
uint8_t got_initial_pkt; // моё значение, отправляется пиру при handshake
|
||||
@@ -59,6 +60,8 @@ struct ETCP_CONN *stcp_link_get_etcp_conn(struct stcp_link *link);
|
||||
void stcp_link_set_etcp_conn(struct stcp_link *link, struct ETCP_CONN *conn);
|
||||
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);
|
||||
const struct sockaddr_storage *stcp_link_get_peer_addr(struct stcp_link *link); /* getpeername(conn->sock) */
|
||||
const struct sockaddr_storage *stcp_link_get_local_addr(struct stcp_link *link); /* getsockname(conn->sock) */
|
||||
|
||||
typedef void (*stcp_link_cb)(struct stcp_link *link, void *arg);
|
||||
void stcp_link_set_on_ready(struct stcp_link *link, stcp_link_cb cb, void *arg);
|
||||
@@ -67,6 +70,8 @@ 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);
|
||||
uint8_t stcp_link_get_peer_device_type(struct stcp_link *link);
|
||||
uint16_t stcp_link_get_peer_keepalive_interval(struct stcp_link *link);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -78,8 +78,10 @@ static void server_hs_phase1_cb(struct stcp_conn *c, uint8_t *data, size_t len)
|
||||
c->peer_got_initial_pkt = enc_hs[32];
|
||||
memcpy(&c->peer_session_id, enc_hs + 33, 4);
|
||||
uint16_t padding_size = (uint16_t)enc_hs[37] | ((uint16_t)enc_hs[38] << 8);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: client handshake OK gop=%d sid=%08x padding=%u",
|
||||
c->peer_got_initial_pkt, c->peer_session_id, padding_size);
|
||||
c->peer_device_type = enc_hs[39];
|
||||
c->peer_keepalive_interval = ((uint16_t)enc_hs[40] << 8) | enc_hs[41];
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: client handshake OK gop=%d sid=%08x padding=%u dev=%d ka=%u",
|
||||
c->peer_got_initial_pkt, c->peer_session_id, padding_size, c->peer_device_type, c->peer_keepalive_interval);
|
||||
stcp_recv_set(c, padding_size, 0, server_hs_phase2_cb);
|
||||
}
|
||||
|
||||
@@ -112,14 +114,16 @@ static void server_hs_phase2_cb(struct stcp_conn *c, uint8_t *data, size_t len)
|
||||
memcpy(resp, salt2, SC_PUBKEY_ENC_SALT_SIZE);
|
||||
sc_obfuscate_pubkey(salt2, c->peer_pubkey, c->my_keys.public_key, resp + SC_PUBKEY_ENC_SALT_SIZE);
|
||||
|
||||
uint8_t plain_hs[39]; memcpy(plain_hs, c->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
uint8_t plain_hs[42]; memcpy(plain_hs, c->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
plain_hs[32] = server_gop;
|
||||
memcpy(plain_hs + 33, &server_sid, 4);
|
||||
plain_hs[37] = (uint8_t)padding; plain_hs[38] = (uint8_t)(padding >> 8);
|
||||
uint32_t crc = crc32_calc(plain_hs, 39);
|
||||
plain_hs[39] = c->device_type;
|
||||
*(uint16_t*)(plain_hs + 40) = htobe16(c->keepalive_interval);
|
||||
uint32_t crc = crc32_calc(plain_hs, 42);
|
||||
uint8_t *enc_dst = resp + SC_PUBKEY_ENC_SIZE;
|
||||
memcpy(enc_dst, plain_hs, 39);
|
||||
enc_dst[39] = (uint8_t)(crc >> 0); enc_dst[40] = (uint8_t)(crc >> 8); enc_dst[41] = (uint8_t)(crc >> 16); enc_dst[42] = (uint8_t)(crc >> 24);
|
||||
memcpy(enc_dst, plain_hs, 42);
|
||||
enc_dst[42] = (uint8_t)(crc >> 0); enc_dst[43] = (uint8_t)(crc >> 8); enc_dst[44] = (uint8_t)(crc >> 16); enc_dst[45] = (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");
|
||||
@@ -179,6 +183,8 @@ static void server_accept_cb(socket_t listen_sock, void *arg) {
|
||||
c->close_arg = srv->close_arg;
|
||||
c->socket_id = uasync_add_socket_t(srv->ua, cli_sock, server_conn_read_cb, stcp_write_cb, NULL, c);
|
||||
c->inst = srv->inst;
|
||||
c->device_type = srv->inst ? srv->inst->client_type : 0;
|
||||
c->keepalive_interval = srv->inst ? srv->inst->keepalive_interval : 200;
|
||||
stcp_recv_set(c, SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT, 0, server_hs_phase1_cb);
|
||||
c->hs_timer = uasync_set_timeout(c->ua, STCP_HS_TIMEOUT, c, hs_timeout_cb, "stcp_hs");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: accepted connection fd=%d", (int)cli_sock);
|
||||
|
||||
+2
-1
@@ -101,6 +101,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
|
||||
// Set client type
|
||||
instance->client_type = config->global.client_type;
|
||||
instance->keepalive_interval = (uint16_t)(config->global.keepalive_interval > 0 ? config->global.keepalive_interval : 200);
|
||||
instance->client_activity = (instance->client_type == CLIENT_TYPE_SERVER) ? CLIENT_ACTIVITY_ACTIVE : CLIENT_ACTIVITY_STANDBY;
|
||||
instance->client_activity_timer = NULL;
|
||||
|
||||
@@ -512,7 +513,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
if (tc) DEBUG_INFO(DEBUG_CATEGORY_SYS, "[DESTROY] J: closed %d TCP links", tc);
|
||||
}
|
||||
queue_free(instance->tcp_connections); instance->tcp_connections = NULL;
|
||||
while (instance->tcp_sockets) tcp_socket_remove(instance->tcp_sockets);
|
||||
/* TCP sockets already cleaned in Phase G via etcp_sockets */
|
||||
uasync_drain_immediate(instance->ua);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[DESTROY] J done — TCP");
|
||||
|
||||
|
||||
+3
-3
@@ -134,9 +134,8 @@ struct UTUN_INSTANCE {
|
||||
struct memory_pool* pkt_pool;
|
||||
struct memory_pool* ack_pool;
|
||||
|
||||
// Active sockets (UDP)
|
||||
struct ETCP_SOCKET* etcp_sockets;// linked-list (UDP + TCP is_tcp=1)
|
||||
struct ETCP_SOCKET* tcp_sockets; // linked-list (TCP, filtered by is_tcp=1)
|
||||
// Active sockets (UDP + TCP, is_tcp=1 flag)
|
||||
struct ETCP_SOCKET* etcp_sockets;// linked-list (UDP + TCP)
|
||||
struct stcp_server *stcp_servers; // TCP servers linked list (via stcp_link.c)
|
||||
void* socket_monitor; // SOCKET_MONITOR* (opaque, transport_layer/socket_monitor.c)
|
||||
void* auto_socket_state; // AUTO_SOCKET* (opaque, transport_layer/auto_socket.c)
|
||||
@@ -187,6 +186,7 @@ struct UTUN_INSTANCE {
|
||||
struct broadcast_ctx* broadcast; // Broadcast protocol instance handler (ETCP_ID_BROADCAST dispatcher)
|
||||
|
||||
uint8_t client_type; // CLIENT_TYPE_SERVER/DESKTOP/MOBILE (from config)
|
||||
uint16_t keepalive_interval; // желаемый keepalive (ms), из конфига. для handshake
|
||||
uint8_t client_activity; // CLIENT_ACTIVITY_STANDBY/ACTIVE
|
||||
void* client_activity_timer; // uasync timer handle for inactivity timeout
|
||||
|
||||
|
||||
Reference in new issue
Block a user