Browse Source

fix NTP ping-pong + normalizer counters

- ntp_node_time.c: respond to TIME_SYNC only when peer is unsynced (not always)
  Prevents infinite 10-byte ping-pong that ate bandwidth when both sides synced.

- pkt_normalizer.c: add in_total_pkts/in_total_bytes increments in
  etcp_input_ready_cb (real send path), matching pn_packer_send (test path).

- conn_mgr_core.c/conn_mgr_priv.h: full INVITE_INFO_RESP with channel info
topo_upd
Evgeny 2 months ago
parent
commit
6b6657c6b8
  1. 7
      src/ntp_node_time.c
  2. 244
      src/routing_layer/conn_mgr_core.c
  3. 28
      src/routing_layer/conn_mgr_priv.h
  4. 2
      src/transport_layer/pkt_normalizer.c

7
src/ntp_node_time.c

@ -161,8 +161,11 @@ static void ntp_node_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
queue_dgram_free(entry); queue_entry_free(entry);
// Ответный TIME_SYNC — всегда
send_time_sync(inst, conn);
// Отвечаем только несинхронизированному пиру — помогаем ему получить время.
// Когда оба синхронизированы — не отвечаем, чтобы не создавать бесконечный пинг-понг.
if (!sender_synced && ntp_time_is_synced(inst)) {
send_time_sync(inst, conn);
}
// Если мы только что скорректировались → раздаём коррекцию всем peer'ам
if (was_unsynced && ntp_time_is_synced(inst)) {

244
src/routing_layer/conn_mgr_core.c

@ -23,6 +23,7 @@
#include "topo_group.h"
#include "../transport_layer/etcp_connect.h"
#include "route_ping.h"
#include "../chat/chat_core.h"
/* ═══════ forward-декларации ═══════ */
@ -741,55 +742,254 @@ void conn_mgr_direct_recv_handler(struct ETCP_CONN* conn, struct ll_entry* entry
/* ═══════ invite обработчики ═══════ */
/* Формирует полный INVITE_INFO_RESP: если сервер участник канала — возвращает
* is_member=1 + ВСЕ поля канала (name, owner, ключи, ch_sig, join/update_sig).
* Если не участник — is_member=0. Попутно создаёт инфраструктуру группы через
* chat_core_ensure_channel_ready, чтобы группа была готова к маршрутизации сразу. */
void cm_handle_invite_info_req(struct CONN_MGR* mgr, struct ETCP_CONN* conn, const uint8_t* data, size_t len) {
if (len < sizeof(struct CM_INVITE_REQ)) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_REQ too short (%zu)", len); return; }
struct CM_INVITE_REQ* req = (struct CM_INVITE_REQ*)data;
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "invite: INFO_REQ from=%016llx group=%016llx",
(unsigned long long)conn->peer_node_id, (unsigned long long)req->group_id);
char ch_id[32]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)req->group_id);
/* данные узла-ответчика для ed_pubkey и node_name */
struct TOPO_GROUP* grp = topo_groups_find(mgr->instance->topo_groups, req->group_id);
struct TOPO_GROUP* sg = grp ? grp : mgr->group;
struct TOPO_NODE* ln = sg->local_node ? topo_node_registry_find(sg->instance->topo_groups, sg->local_node->node_id) : NULL;
const char* nm = ln ? ln->node_name : NULL; size_t nl = nm ? strlen(nm) : 0; if (nl > 255) nl = 255;
size_t rs = sizeof(struct CM_INVITE_RESP) + nl;
struct CM_INVITE_RESP* resp = u_calloc(1, rs); if (!resp) return;
resp->cmd=ETCP_RT_ID_CONN_MGR; resp->subcmd=CM_SUBCMD_INVITE_INFO_RESP; resp->group_id=req->group_id; resp->is_member=1;
memcpy(resp->ed25519_pubkey, sg->ed25519_public_key, SC_PUBKEY_SIZE); resp->node_name_len=(uint8_t)nl;
if (nl) memcpy(resp->node_name, nm, nl);
struct ll_entry* qe = queue_entry_new(0);
if (qe) {
size_t new_len = rs + 1; /* +1 for duplicate cmd: dgram[0]=dispatch, dgram[1]=handler-skip, dgram[2]=subcmd, dgram[3..]=payload */
uint8_t* buf = u_malloc(new_len);
if (buf) { buf[0]=ETCP_RT_ID_CONN_MGR; buf[1]=ETCP_RT_ID_CONN_MGR; buf[2]=CM_SUBCMD_INVITE_INFO_RESP;
memcpy(buf+3, (uint8_t*)resp+2, rs-2); qe->dgram=buf; qe->len=(uint16_t)new_len; etcp_send(conn, qe); u_free(resp); }
else { queue_entry_free(qe); u_free(resp); }
} else u_free(resp);
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "invite: membership check RECEIVED from 0x%016llx — responding is_member=yes name=\"%.*s\"",
(unsigned long long)conn->peer_node_id, (int)nl, nm ? nm : "");
/* ── ищем канал в SQLite ── */
sqlite3* db = mgr->instance->topo_sqlite_db;
char ch_name[128] = ""; uint64_t owner = 0;
uint8_t ch_x25519[32] = {0}, ch_ed_pub[32] = {0}, ch_sig[64] = {0};
int have_channel = db && topo_node_sqlite_channel_get(db, ch_id, ch_name, (int)sizeof(ch_name),
&owner, ch_x25519, ch_ed_pub, ch_sig) == 0;
if (!have_channel) {
size_t rs = CM_INVITE_RESP_HDR_SIZE + nl;
struct CM_INVITE_RESP* resp = u_calloc(1, rs); if (!resp) return;
resp->cmd = ETCP_RT_ID_CONN_MGR; resp->subcmd = CM_SUBCMD_INVITE_INFO_RESP;
resp->group_id = req->group_id; resp->is_member = 0;
memcpy(resp->ed25519_pubkey, sg->ed25519_public_key, SC_PUBKEY_SIZE);
resp->node_name_len = (uint8_t)nl; if (nl) memcpy(resp->node_name, nm, nl);
struct ll_entry* qe = queue_entry_new(0);
if (qe) { size_t new_len = rs + 1; uint8_t* buf = u_malloc(new_len);
if (buf) { buf[0]=ETCP_RT_ID_CONN_MGR; buf[1]=ETCP_RT_ID_CONN_MGR; buf[2]=CM_SUBCMD_INVITE_INFO_RESP;
memcpy(buf + 3, (uint8_t*)resp + 2, rs - 2); qe->dgram = buf; qe->len = (uint16_t)new_len; etcp_send(conn, qe); }
else { queue_entry_free(qe); }
}
u_free(resp);
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: group=%016llx NOT in DB — responding is_member=NO to 0x%016llx",
(unsigned long long)req->group_id, (unsigned long long)conn->peer_node_id);
return;
}
/* ── участник: генерируем join_sig / update_sig ── */
uint64_t myid = mgr->instance->node_id;
uint8_t my_join_sig[64] = {0}; uint64_t my_join_ts = 0;
{
if (db && topo_node_sqlite_member_get_join(db, ch_id, myid, my_join_sig, &my_join_ts) != 0) {
uint8_t join_msg[256]; size_t mlen = 0;
memcpy(join_msg + mlen, ch_x25519, 32); mlen += 32;
memcpy(join_msg + mlen, ch_ed_pub, 32); mlen += 32;
memcpy(join_msg + mlen, &myid, 8); mlen += 8;
memcpy(join_msg + mlen, mgr->instance->my_keys.public_key, 32); mlen += 32;
my_join_ts = (uint64_t)ntp_time_get_seconds(mgr->instance);
memcpy(join_msg + mlen, &my_join_ts, 8); mlen += 8;
if (sc_ed25519_sign(mgr->instance->my_ed25519_privkey, join_msg, mlen, my_join_sig) != SC_OK)
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "invite: join_sig sign FAILED myid=%016llx ch=%s", (unsigned long long)myid, ch_id);
else
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "invite: join_sig NEW myid=%016llx ts=%llu ch=%s",
(unsigned long long)myid, (unsigned long long)my_join_ts, ch_id);
} else {
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "invite: join_sig REUSED myid=%016llx ts=%llu ch=%s",
(unsigned long long)myid, (unsigned long long)my_join_ts, ch_id);
}
}
uint8_t my_update_sig[64] = {0}; uint64_t my_update_ts = 0;
{
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}",
mgr->instance->name[0] ? mgr->instance->name : "");
uint8_t umsg[256]; size_t ulen = 0;
memcpy(umsg + ulen, my_join_sig, 64); ulen += 64;
my_update_ts = (uint64_t)ntp_time_get_seconds(mgr->instance);
memcpy(umsg + ulen, &my_update_ts, 8); ulen += 8;
size_t jl = strlen(juser); memcpy(umsg + ulen, juser, jl); umsg[ulen + jl] = '\0'; ulen += jl + 1;
if (sc_ed25519_sign(mgr->instance->my_ed25519_privkey, umsg, ulen, my_update_sig) != SC_OK)
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "invite: update_sig sign FAILED myid=%016llx", (unsigned long long)myid);
}
/* ── создаём инфраструктуру группы СРАЗУ (topo_group, db_sync, msg-таблицу) ── */
chat_core_ensure_channel_ready(ch_id);
/* ── сериализуем ответ ── */
size_t ch_nl = strlen(ch_name); if (ch_nl > 255) ch_nl = 255;
uint8_t inv_flags = (my_join_sig[0] || my_join_ts) ? PEERS_FLAG_HAS_JOIN : 0;
char userinfo[256]; size_t userinfo_len = (size_t)snprintf(userinfo, sizeof(userinfo),
"{\"name\":\"%s\"}", mgr->instance->name[0] ? mgr->instance->name : "");
size_t ch_info_len = 1 + ch_nl + 8 + 32 + 32 + 64 + 1
+ (inv_flags & PEERS_FLAG_HAS_JOIN ? 72 : 0)
+ 64 + 8 + 1 + userinfo_len;
size_t rs = CM_INVITE_RESP_HDR_SIZE + nl + ch_info_len;
uint8_t* rb = u_malloc(rs); if (!rb) return;
memset(rb, 0, rs);
{ struct CM_INVITE_RESP* resp = (struct CM_INVITE_RESP*)rb;
resp->cmd = ETCP_RT_ID_CONN_MGR; resp->subcmd = CM_SUBCMD_INVITE_INFO_RESP;
resp->group_id = req->group_id; resp->is_member = 1;
memcpy(resp->ed25519_pubkey, sg->ed25519_public_key, SC_PUBKEY_SIZE);
resp->node_name_len = (uint8_t)nl; if (nl) memcpy(resp->node_name, nm, nl); }
uint8_t* ch = rb + CM_INVITE_RESP_HDR_SIZE + nl;
*ch++ = (uint8_t)ch_nl; memcpy(ch, ch_name, ch_nl); ch += ch_nl;
memcpy(ch, &owner, 8); ch += 8;
memcpy(ch, ch_x25519, 32); ch += 32;
memcpy(ch, ch_ed_pub, 32); ch += 32;
memcpy(ch, ch_sig, 64); ch += 64;
*ch++ = inv_flags;
if (inv_flags & PEERS_FLAG_HAS_JOIN) { memcpy(ch, my_join_sig, 64); ch += 64; memcpy(ch, &my_join_ts, 8); ch += 8; }
memcpy(ch, my_update_sig, 64); ch += 64;
memcpy(ch, &my_update_ts, 8); ch += 8;
*ch++ = (uint8_t)userinfo_len; memcpy(ch, userinfo, userinfo_len);
DEBUG_INFO(DEBUG_CATEGORY_GENERAL,
"invite: membership CHECK OK from=0x%016llx group=%016llx ch_name=%.*s owner=%016llx "
"ch_x25519=%016llx... ch_ed=%016llx... inv_flags=%u join_ts=%llu upd_ts=%llu my_name=%s → is_member=YES full_ch_info (%zu+%zu=%zuB)",
(unsigned long long)conn->peer_node_id, (unsigned long long)req->group_id,
(int)ch_nl, ch_name, (unsigned long long)owner,
*(const uint64_t*)ch_x25519, *(const uint64_t*)ch_ed_pub,
(unsigned)inv_flags, (unsigned long long)my_join_ts, (unsigned long long)my_update_ts,
mgr->instance->name[0] ? mgr->instance->name : "?",
CM_INVITE_RESP_HDR_SIZE + nl, ch_info_len, rs);
{ struct ll_entry* qe = queue_entry_new(0);
if (qe) { size_t dgram_len = rs + 1; uint8_t* dgram = u_malloc(dgram_len);
if (dgram) { dgram[0]=ETCP_RT_ID_CONN_MGR; dgram[1]=ETCP_RT_ID_CONN_MGR; dgram[2]=CM_SUBCMD_INVITE_INFO_RESP;
memcpy(dgram + 3, rb + 2, rs - 2); qe->dgram = dgram; qe->len = (uint16_t)dgram_len; etcp_send(conn, qe); }
else { queue_entry_free(qe); }
}
}
u_free(rb);
}
void cm_handle_invite_info_resp(struct CONN_MGR* mgr, struct ETCP_CONN* conn, const uint8_t* data, size_t len) {
if (len < sizeof(struct CM_INVITE_RESP)) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_RESP too short (%zu)", len); return; }
if (len < CM_INVITE_RESP_HDR_SIZE) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_RESP too short (%zu < %zu)", len, CM_INVITE_RESP_HDR_SIZE); return; }
struct CM_INVITE_RESP* resp = (struct CM_INVITE_RESP*)data;
if (len < sizeof(struct CM_INVITE_RESP) + (size_t)resp->node_name_len) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_RESP truncated"); return; }
uint8_t nnl = resp->node_name_len;
if (len < CM_INVITE_RESP_HDR_SIZE + (size_t)nnl) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_RESP truncated (need %zu, got %zu)", CM_INVITE_RESP_HDR_SIZE + (size_t)nnl, len); return; }
/* ── ищем ожидающий invite ── */
struct cm_invite_pending* inv = NULL;
{ struct TOPO_GROUP* grp = topo_groups_find(mgr->instance->topo_groups, resp->group_id);
if (grp && grp->conn_mgr) {
if (grp && grp->conn_mgr)
for (struct cm_invite_pending* p = grp->conn_mgr->invite_list; p; p = p->next)
if (p->state == CM_INVITE_WAIT_INFO && (!conn->peer_node_id || p->node_id == conn->peer_node_id)) { inv = p; break; }
}
}
if (!inv) { for (struct cm_invite_pending* p = mgr->invite_list; p; p = p->next) if (p->state == CM_INVITE_WAIT_INFO) { inv = p; break; } }
if (!inv) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_RESP — no pending invite in WAIT_INFO state"); return; }
if (!resp->is_member) {
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: membership DENIED by 0x%016llx — not in channel", (unsigned long long)inv->node_id);
cm_invite_fail(inv); return;
}
/* ── сохраняем Ed25519 pubkey ответчика для NODEINFO-верификации ── */
if (inv->temp_nq) {
struct TOPO_NODE* ni2 = topo_node_registry_find(inv->mgr->instance->topo_groups, inv->temp_nq->node_id);
if (ni2) memcpy(ni2->ed25519_public_key, resp->ed25519_pubkey, SC_PUBKEY_SIZE);
if (inv->mgr->instance->topo_sqlite_db) topo_node_sqlite_node_put(inv->mgr->instance->topo_sqlite_db, inv->mgr->instance->topo_groups, inv->temp_nq, (time_t)(get_time_tb()/10000));
if (inv->mgr->instance->topo_sqlite_db)
topo_node_sqlite_node_put(inv->mgr->instance->topo_sqlite_db, inv->mgr->instance->topo_groups, inv->temp_nq, (time_t)(get_time_tb() / 10000));
}
/* ── парсим channel_info (новое) ── */
const uint8_t* ch = data + CM_INVITE_RESP_HDR_SIZE + nnl;
size_t ch_remain = len - (CM_INVITE_RESP_HDR_SIZE + nnl);
if (ch_remain < CM_INVITE_RESP_CH_MIN_SIZE) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: INVITE_INFO_RESP channel info too short (%zu < %zu)", ch_remain, CM_INVITE_RESP_CH_MIN_SIZE); cm_invite_fail(inv); return; }
uint8_t c_nl = *ch++; ch_remain--;
if (ch_remain < (size_t)c_nl) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: ch_name truncated"); cm_invite_fail(inv); return; }
char ch_name[128]; size_t cn = c_nl > 127 ? 127 : c_nl; memcpy(ch_name, ch, cn); ch_name[cn] = '\0'; ch += c_nl; ch_remain -= c_nl;
uint64_t ch_owner; memcpy(&ch_owner, ch, 8); ch += 8; ch_remain -= 8;
const uint8_t* ch_x25519 = ch; ch += 32; ch_remain -= 32;
const uint8_t* ch_ed_pub = ch; ch += 32; ch_remain -= 32;
const uint8_t* ch_sig = ch; ch += 64; ch_remain -= 64;
if (ch_remain < 1) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: ch_info truncated at inv_flags"); cm_invite_fail(inv); return; }
uint8_t inv_flags = *ch++; ch_remain--;
const uint8_t* join_sig = NULL; uint64_t join_ts = 0;
if (inv_flags & PEERS_FLAG_HAS_JOIN) {
if (ch_remain < 72) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: ch_info truncated at join_sig"); cm_invite_fail(inv); return; }
join_sig = ch; ch += 64; memcpy(&join_ts, ch, 8); ch += 8; ch_remain -= 72;
}
if (ch_remain < 73) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: ch_info truncated at update"); cm_invite_fail(inv); return; }
const uint8_t* upd_sig = ch; ch += 64; uint64_t upd_ts; memcpy(&upd_ts, ch, 8); ch += 8; ch_remain -= 72;
uint8_t ui_len = *ch++; ch_remain--;
char ch_userinfo[256] = "";
if (ui_len > 0 && ch_remain >= ui_len) { size_t ul = ui_len > 255 ? 255 : ui_len; memcpy(ch_userinfo, ch, ul); ch_userinfo[ul] = '\0'; }
char ch_id[32]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)resp->group_id);
DEBUG_INFO(DEBUG_CATEGORY_GENERAL,
"invite: INFO_RESP from=0x%016llx group=%016llx node_name=%.*s "
"ch_name=%s ch_owner=%016llx ch_x25519=%016llx... ch_ed=%016llx... "
"inv_flags=%u join_ts=%llu upd_ts=%llu userinfo=%s",
(unsigned long long)conn->peer_node_id, (unsigned long long)resp->group_id,
(int)nnl, nnl ? (const char*)resp->node_name : "?",
ch_name, (unsigned long long)ch_owner,
*(const uint64_t*)ch_x25519, *(const uint64_t*)ch_ed_pub,
(unsigned)inv_flags, (unsigned long long)join_ts, (unsigned long long)upd_ts,
ch_userinfo[0] ? ch_userinfo : "?");
/* ── верифицируем ch_sig ── */
{
uint8_t vmsg[1024]; size_t vlen = 0;
vlen += snprintf((char*)vmsg + vlen, sizeof(vmsg) - vlen, "%s", ch_id) + 1;
vlen += (size_t)snprintf((char*)vmsg + vlen, sizeof(vmsg) - vlen, "%s", ch_name) + 1;
memcpy(vmsg + vlen, &ch_owner, 8); vlen += 8;
memcpy(vmsg + vlen, ch_x25519, 32); vlen += 32;
memcpy(vmsg + vlen, ch_ed_pub, 32); vlen += 32;
if (sc_ed25519_verify(ch_ed_pub, vmsg, vlen, ch_sig) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "invite: ch_sig VERIFY FAIL — rejecting group=%016llx from=0x%016llx",
(unsigned long long)resp->group_id, (unsigned long long)conn->peer_node_id);
cm_invite_fail(inv); return;
}
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "invite: ch_sig VERIFY OK");
}
/* ── сохраняем канал в БД и создаём ПОЛНОЦЕННУЮ группу (topo_group + db_sync + msg-таблицу) ── */
{
sqlite3* ldb = inv->mgr->instance->topo_sqlite_db;
if (ldb) topo_node_sqlite_channel_put(ldb, ch_id, ch_name, ch_owner,
ch_x25519, NULL, ch_ed_pub, NULL, ch_sig);
}
chat_core_ensure_channel_ready(ch_id);
/* ── верифицируем update_sig приглашающего ── */
{
const uint8_t* inv_ed = conn->peer_ed25519_pubkey;
uint8_t ivmsg[256]; size_t ilen = 0;
if (join_sig && (inv_flags & PEERS_FLAG_HAS_JOIN)) { memcpy(ivmsg + ilen, join_sig, 64); ilen += 64; }
else { memset(ivmsg + ilen, 0, 64); ilen += 64; }
memcpy(ivmsg + ilen, &upd_ts, 8); ilen += 8;
{ const char* nm2 = ch_userinfo[0] ? ch_userinfo : "";
size_t nl2 = strlen(nm2); memcpy(ivmsg + ilen, nm2, nl2 + 1); ilen += nl2 + 1; }
if (sc_ed25519_verify(inv_ed, ivmsg, ilen, upd_sig) != SC_OK) {
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "invite: inviter_update_sig VERIFY FAIL node=0x%016llx", (unsigned long long)conn->peer_node_id);
} else {
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "invite: inviter_update_sig VERIFY OK");
}
}
if (inv->overall_timer) { uasync_cancel_timeout(inv->mgr->instance->ua, inv->overall_timer); inv->overall_timer = NULL; }
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "invite: membership CONFIRMED by 0x%016llx name=\"%.*s\" — joined to channel, handle registered",
(unsigned long long)inv->node_id, resp->node_name_len, resp->node_name_len ? (const char*)resp->node_name : "");
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "invite: membership CONFIRMED by 0x%016llx name=\"%.*s\" ch=%s — full channel ready",
(unsigned long long)inv->node_id, (int)nnl, nnl ? (const char*)resp->node_name : "?", ch_id);
if (inv->cb) inv->cb(inv->handle, inv->node_id, inv->mgr->group->group_id, CONN_EVENT_JOIN, inv->cb_arg);
if (inv->invite_conn) {
node_conn_direct_open_node(inv->mgr->instance, inv->node_id, cm_ncd_callback, NULL, NULL, NULL, NULL);

28
src/routing_layer/conn_mgr_priv.h

@ -82,10 +82,38 @@ struct CM_DISCONNECT { uint8_t cmd, subcmd; uint64_t node_id; };
struct CM_INVITE_REQ { uint8_t cmd, subcmd; uint64_t group_id; };
#pragma pack(pop)
/*
* INVITE_INFO_RESP wire format (devel — без обратной совместимости):
*
* [0..1] cmd, subcmd
* [2..9] group_id
* [10] is_member (1=участник, 0=не в канале)
* [11..13] reserved
* [14..45] ed25519_pubkey (Ed25519 pubkey узла-ответчика, для NODEINFO-верификации)
* [46] node_name_len
* [47..N] node_name (node_name_len байт)
*
* Если is_member == 1 — далее полная информация о канале:
* [N+1] ch_name_len
* [N+2..] ch_name (ch_name_len байт)
* +8 owner (node_id создателя)
* +32 ch_x25519 (X25519 pubkey канала)
* +32 ch_ed_pub (Ed25519 pubkey канала)
* +64 ch_sig (Ed25519-подпись канала)
* +1 inv_flags (PEERS_FLAG_HAS_JOIN)
* [if PEERS_FLAG_HAS_JOIN: +64 join_sig + 8 join_ts]
* +64 update_sig
* +8 update_ts
* +1 userinfo_len
* +var userinfo (userinfo_len байт, JSON с именем узла)
*/
#pragma pack(push, 1)
struct CM_INVITE_RESP { uint8_t cmd, subcmd; uint64_t group_id; uint8_t is_member; uint8_t reserved[3]; uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; uint8_t node_name_len; uint8_t node_name[0]; };
#pragma pack(pop)
#define CM_INVITE_RESP_HDR_SIZE (sizeof(struct CM_INVITE_RESP)) /* 47 байт, без node_name */
#define CM_INVITE_RESP_CH_MIN_SIZE (1 + 8 + 32 + 32 + 64 + 1 + 64 + 8 + 1) /* 211 байт, без учёта join и имён */
#define CM_DIRECT_REQ_H_SIZE (sizeof(struct CM_DIRECT_REQ))
#define CM_DIRECT_RESP_HDR_SIZE (sizeof(struct CM_DIRECT_RESP))
#define CM_EXCHANGE_REQ_SIZE (sizeof(struct CM_EXCHANGE_REQ))

2
src/transport_layer/pkt_normalizer.c

@ -290,6 +290,8 @@ static void etcp_input_ready_cb(struct ll_queue* q, void* arg) {
queue_resume_callback(pn->input);
return;
}
pn->in_total_pkts++;
pn->in_total_bytes += in_dgram->len;
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP)) log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP, "->NORM", in_dgram->dgram, in_dgram->len);

Loading…
Cancel
Save