Browse Source
- chat_core_connect_auto: direct ETCP connect from SQLite (no BGP) - auto_connect: parallel connect to peers with 3s timeout, retry 10s - RTT saved to node_addresses on disconnect - vertical status bar + circle badge with online count per channel - ChannelListView prevents deselectiontopo_upd
22 changed files with 909 additions and 10 deletions
@ -0,0 +1,184 @@
|
||||
#include "ntp_node_time.h" |
||||
#include "ntp_time.h" |
||||
#include "utun_instance.h" |
||||
#include "../lib/debug_config.h" |
||||
#include "../lib/mem.h" |
||||
#include "etcp_api.h" |
||||
#include "etcp_router.h" |
||||
#include "etcp.h" |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <sys/time.h> |
||||
|
||||
#define TIME_SYNC_FLAG_SYNCED 0x01 |
||||
|
||||
#pragma pack(push, 1) |
||||
struct time_sync_msg { |
||||
uint8_t flags; // bit0 = sender_synced
|
||||
int64_t t_sender_us; // corrected time if synced, local gettimeofday otherwise
|
||||
}; |
||||
#pragma pack(pop) |
||||
|
||||
_Static_assert(sizeof(struct time_sync_msg) == 9, "time_sync_msg size mismatch"); |
||||
|
||||
static void ntp_node_on_conn_ready(struct ETCP_CONN* conn, void* arg); |
||||
static void ntp_node_on_new_conn(struct ETCP_CONN* conn, void* arg); |
||||
static void ntp_node_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry); |
||||
|
||||
static int send_time_sync(struct UTUN_INSTANCE* inst, uint64_t dst_node_id) { |
||||
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, dst_node_id, ETCP_RT_ID_NTP_TIME); |
||||
if (!rconn) return -1; |
||||
|
||||
struct time_sync_msg msg; |
||||
msg.flags = ntp_time_is_synced(inst) ? TIME_SYNC_FLAG_SYNCED : 0; |
||||
|
||||
struct timeval tv; |
||||
#ifdef _WIN32 |
||||
utun_gettimeofday(&tv, NULL); |
||||
#else |
||||
gettimeofday(&tv, NULL); |
||||
#endif |
||||
msg.t_sender_us = ntp_time_is_synced(inst) |
||||
? ntp_time_get_us(inst) |
||||
: (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec; |
||||
|
||||
return etcp_router_conn_send(rconn, (const uint8_t*)&msg, sizeof(msg)); |
||||
} |
||||
|
||||
static int64_t gettimeofday_us(void) { |
||||
struct timeval tv; |
||||
#ifdef _WIN32 |
||||
utun_gettimeofday(&tv, NULL); |
||||
#else |
||||
gettimeofday(&tv, NULL); |
||||
#endif |
||||
return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec; |
||||
} |
||||
|
||||
static struct NTP_NODE_PEER* find_peer(struct NTP_NODE_TIME* np, uint64_t node_id) { |
||||
for (int i = 0; i < np->peer_count; i++) { |
||||
if (np->peers[i].node_id == node_id) return &np->peers[i]; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
static struct NTP_NODE_PEER* add_peer(struct NTP_NODE_TIME* np, uint64_t node_id) { |
||||
if (np->peer_count >= NTP_NODE_MAX_PEERS) return NULL; |
||||
struct NTP_NODE_PEER* p = &np->peers[np->peer_count]; |
||||
p->node_id = node_id; |
||||
p->offset_us = 0; |
||||
np->peer_count++; |
||||
return p; |
||||
} |
||||
|
||||
static void check_drift(uint64_t node_id, int64_t offset_us) { |
||||
int64_t abs_us = offset_us < 0 ? -offset_us : offset_us; |
||||
if (abs_us > NTP_NODE_DRIFT_ERROR_US) { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "NTP_node: clock drift >10s with node %012llx: %lldus", |
||||
(unsigned long long)node_id, (long long)offset_us); |
||||
} else if (abs_us > NTP_NODE_DRIFT_WARN_US) { |
||||
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "NTP_node: clock drift >2s with node %012llx: %lldus", |
||||
(unsigned long long)node_id, (long long)offset_us); |
||||
} |
||||
} |
||||
|
||||
static void ntp_node_on_conn_ready(struct ETCP_CONN* conn, void* arg) { |
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg; |
||||
if (!inst || !conn) return; |
||||
|
||||
if (send_time_sync(inst, conn->peer_node_id) == 0) { |
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "NTP_node: sent TIME_SYNC to node %012llx (synced=%d)", |
||||
(unsigned long long)conn->peer_node_id, ntp_time_is_synced(inst)); |
||||
} else { |
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "NTP_node: failed to send TIME_SYNC to node %012llx", |
||||
(unsigned long long)conn->peer_node_id); |
||||
} |
||||
} |
||||
|
||||
static void ntp_node_on_new_conn(struct ETCP_CONN* conn, void* arg) { |
||||
if (!conn) return; |
||||
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)arg; |
||||
if (!inst) return; |
||||
etcp_conn_add_ready_cbk(conn, ntp_node_on_conn_ready, inst); |
||||
} |
||||
|
||||
static void ntp_node_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { |
||||
if (!conn || !entry) return; |
||||
struct UTUN_INSTANCE* inst = conn->instance; |
||||
if (!inst) { queue_dgram_free(entry); return; } |
||||
|
||||
uint8_t svc_id = entry->dgram[offsetof(struct SVC_ROUTE_HDR, svc_id)]; |
||||
if (svc_id != ETCP_RT_ID_NTP_TIME) { queue_dgram_free(entry); return; } |
||||
|
||||
size_t payload_len = entry->len < SVC_ROUTE_HDR_SIZE ? 0 : entry->len - SVC_ROUTE_HDR_SIZE; |
||||
if (payload_len < sizeof(struct time_sync_msg)) { queue_dgram_free(entry); return; } |
||||
|
||||
struct time_sync_msg* msg = (struct time_sync_msg*)(entry->dgram + SVC_ROUTE_HDR_SIZE); |
||||
int sender_synced = (msg->flags & TIME_SYNC_FLAG_SYNCED) != 0; |
||||
|
||||
int64_t t4 = gettimeofday_us(); |
||||
int64_t peer_offset = t4 - msg->t_sender_us; |
||||
|
||||
struct NTP_NODE_TIME* np = &inst->ntp_node; |
||||
struct NTP_NODE_PEER* peer = find_peer(np, conn->peer_node_id); |
||||
if (!peer) peer = add_peer(np, conn->peer_node_id); |
||||
if (peer) peer->offset_us = peer_offset; |
||||
|
||||
check_drift(conn->peer_node_id, peer_offset); |
||||
|
||||
int was_unsynced = !ntp_time_is_synced(inst); |
||||
|
||||
if (was_unsynced && sender_synced) { |
||||
inst->ntp.offset_us = msg->t_sender_us - t4; |
||||
inst->ntp.synced = 1; |
||||
inst->ntp.last_sync_tb = get_time_tb(); |
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "NTP_node: synced from node %012llx, offset=%lldus", |
||||
(unsigned long long)conn->peer_node_id, (long long)inst->ntp.offset_us); |
||||
} |
||||
|
||||
queue_dgram_free(entry); |
||||
|
||||
// Ответный TIME_SYNC — всегда
|
||||
send_time_sync(inst, conn->peer_node_id); |
||||
|
||||
// Если мы только что скорректировались → раздаём коррекцию всем peer'ам
|
||||
if (was_unsynced && ntp_time_is_synced(inst)) { |
||||
ntp_node_sync_peers(inst); |
||||
} |
||||
} |
||||
|
||||
void ntp_node_sync_peers(struct UTUN_INSTANCE* inst) { |
||||
if (!inst || !ntp_time_is_synced(inst)) return; |
||||
|
||||
int sent = 0; |
||||
for (struct ETCP_CONN* conn = inst->connections; conn; conn = conn->next) { |
||||
if (!conn->initialized || !conn->links_up) continue; |
||||
if (send_time_sync(inst, conn->peer_node_id) == 0) sent++; |
||||
} |
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "NTP_node: broadcast TIME_SYNC to %d peers", sent); |
||||
} |
||||
|
||||
int ntp_node_time_init(struct UTUN_INSTANCE* inst) { |
||||
if (!inst) return -1; |
||||
struct NTP_NODE_TIME* np = &inst->ntp_node; |
||||
np->peer_count = 0; |
||||
|
||||
etcp_router_bind(inst, ETCP_RT_ID_NTP_TIME, ntp_node_recv_cb); |
||||
etcp_add_new_conn_cbk(inst, ntp_node_on_new_conn, inst); |
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "NTP_node: initialized (RT_ID=0x%02X)", ETCP_RT_ID_NTP_TIME); |
||||
return 0; |
||||
} |
||||
|
||||
void ntp_node_time_destroy(struct UTUN_INSTANCE* inst) { |
||||
if (!inst) return; |
||||
struct NTP_NODE_TIME* np = &inst->ntp_node; |
||||
|
||||
etcp_router_unbind(inst, ETCP_RT_ID_NTP_TIME); |
||||
etcp_remove_new_conn_cbk(inst, ntp_node_on_new_conn, inst); |
||||
|
||||
np->peer_count = 0; |
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "NTP_node: destroyed"); |
||||
} |
||||
@ -0,0 +1,35 @@
|
||||
#ifndef NTP_NODE_TIME_H |
||||
#define NTP_NODE_TIME_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
struct UTUN_INSTANCE; |
||||
|
||||
#define NTP_NODE_MAX_PEERS 32 |
||||
|
||||
#define NTP_NODE_DRIFT_WARN_US 2000000LL // 2 seconds
|
||||
#define NTP_NODE_DRIFT_ERROR_US 10000000LL // 10 seconds
|
||||
|
||||
struct NTP_NODE_PEER { |
||||
uint64_t node_id; |
||||
int64_t offset_us; // my_time_recv - peer_time (positive = my clock ahead)
|
||||
}; |
||||
|
||||
struct NTP_NODE_TIME { |
||||
struct NTP_NODE_PEER peers[NTP_NODE_MAX_PEERS]; |
||||
int peer_count; |
||||
}; |
||||
|
||||
int ntp_node_time_init(struct UTUN_INSTANCE* inst); |
||||
void ntp_node_time_destroy(struct UTUN_INSTANCE* inst); |
||||
void ntp_node_sync_peers(struct UTUN_INSTANCE* inst); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif // NTP_NODE_TIME_H
|
||||
Loading…
Reference in new issue