|
|
|
|
@ -86,7 +86,7 @@ struct stream_peer {
|
|
|
|
|
struct stream_network { |
|
|
|
|
struct UTUN_INSTANCE *inst; |
|
|
|
|
struct stream_peer *peers; |
|
|
|
|
void *timer; |
|
|
|
|
void *timer, *work; |
|
|
|
|
unsigned peer_count, flow_count; |
|
|
|
|
int stopping; |
|
|
|
|
struct stream_load load; |
|
|
|
|
@ -97,7 +97,7 @@ struct stream_network {
|
|
|
|
|
int global_candidate; |
|
|
|
|
struct stream_relay_request *relay_requests; |
|
|
|
|
struct stream_relay *relays; |
|
|
|
|
uint64_t relay_epoch; |
|
|
|
|
uint64_t relay_epoch, info_order; |
|
|
|
|
unsigned relay_count, relay_request_count; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
@ -110,6 +110,21 @@ static void pressure_receive(struct stream_peer *peer, const struct stream_messa
|
|
|
|
|
static void relay_tick(struct stream_network *net, uint64_t now); |
|
|
|
|
static void relay_dispatch(struct stream_network *net, uint64_t sender, const struct stream_message *message); |
|
|
|
|
|
|
|
|
|
/* Отложенное управление читает живые сессии; callbacks протокола уже закончили работу с handles. */ |
|
|
|
|
static void network_work(void *arg) { |
|
|
|
|
struct stream_network *net = arg; net->work = NULL; |
|
|
|
|
uint64_t now = get_time_tb() / 10; |
|
|
|
|
stream_optimizers_tick(net->inst, now); |
|
|
|
|
relay_tick(net, now); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Один call_soon объединяет INFO/ACCEPT/READY; DATA не запускает дополнительный обход на каждом блоке. */ |
|
|
|
|
void stream_network_wake(struct stream_network *net) { |
|
|
|
|
if (!net || net->stopping || net->work) return; |
|
|
|
|
net->work = uasync_call_soon(net->inst->ua, net, network_work); |
|
|
|
|
if (!net->work) DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream control scheduling failed"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Ключи очереди — cursor+кольцо, её возраст учитывает реальное время вставки и момент появления выдачи. */ |
|
|
|
|
static uint64_t flow_age(struct STREAM_RECEIVE *f, uint64_t now) { |
|
|
|
|
if (f->outgoing || !f->load.queued.packets) return 0; |
|
|
|
|
@ -348,6 +363,7 @@ static void ncd_changed(struct NODE_CONN_DIRECT *handle, enum ncd_event event, v
|
|
|
|
|
peer_reset(p, STREAM_REASON_TRANSPORT, STREAM_RESET_ROTATE, NULL); |
|
|
|
|
} else DEBUG_WARN(DEBUG_CATEGORY_STREAM, "stream NCD initial timeout peer=%llx", (unsigned long long)p->node_id); |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "stream NCD event peer=%llx event=%d up=%d", (unsigned long long)p->node_id, event, p->up); |
|
|
|
|
stream_network_wake(p->network); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* На пира ровно один stream NCD owner, общий для всех его выдач и групп. */ |
|
|
|
|
@ -762,7 +778,7 @@ static void dispatch(struct stream_network *net, uint64_t sender, const uint8_t
|
|
|
|
|
struct stream_message m; struct stream_local local; |
|
|
|
|
if (stream_wire_parse(wire, length, &m) != STREAM_OK || !sender || sender == net->inst->node_id) return; |
|
|
|
|
if (m.command >= STREAM_CMD_RELAY_REQUEST) { |
|
|
|
|
if (routed) relay_dispatch(net, sender, &m); |
|
|
|
|
if (routed) { relay_dispatch(net, sender, &m); stream_network_wake(net); } |
|
|
|
|
else DEBUG_WARN(DEBUG_CATEGORY_STREAM, "relay command requires signed routed control peer=%llx command=%u", |
|
|
|
|
(unsigned long long)sender, m.command); |
|
|
|
|
return; |
|
|
|
|
@ -836,6 +852,10 @@ static void dispatch(struct stream_network *net, uint64_t sender, const uint8_t
|
|
|
|
|
if (p->other_epoch && p->other_epoch != m.sender_epoch) |
|
|
|
|
peer_reset(p, STREAM_REASON_TRANSPORT, STREAM_RESET_KEEP_PENDING, f); |
|
|
|
|
p->other_epoch = m.sender_epoch; f->info_ready = f->info.info_ready = 1; |
|
|
|
|
if (net->info_order == UINT64_MAX) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream INFO response order exhausted"); |
|
|
|
|
flow_close(f, STREAM_REASON_LIMIT, 0); |
|
|
|
|
} else f->info.info_order = ++net->info_order; |
|
|
|
|
f->info.local_epoch = p->own_epoch; f->info.peer_epoch = p->other_epoch; peer_schedule(p); |
|
|
|
|
uint64_t rtt = get_time_tb() / 10 - f->probe_sent_ms; |
|
|
|
|
f->info.rtt_valid = f->probe_sent_ms != 0; f->info.rtt_ms = rtt > UINT32_MAX ? UINT32_MAX : (uint32_t)rtt; |
|
|
|
|
@ -910,6 +930,8 @@ static void dispatch(struct stream_network *net, uint64_t sender, const uint8_t
|
|
|
|
|
(unsigned long long)sender, m.command, (unsigned long long)m.handle, m.subblock, m.length); |
|
|
|
|
receive_progress(net, &local.descriptor); |
|
|
|
|
p->busy--; peer_sweep(p); |
|
|
|
|
if (m.command == STREAM_CMD_INFO_RESP || m.command == STREAM_CMD_ACCEPT || m.command == STREAM_CMD_REJECT |
|
|
|
|
|| m.command == STREAM_CMD_CLOSED || (m.command == STREAM_CMD_DATA && !local.anchored)) stream_network_wake(net); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Entry/dgram принадлежат обработчику во всех ветках. */ |
|
|
|
|
@ -1006,8 +1028,7 @@ static void network_tick(void *arg) {
|
|
|
|
|
p = next; |
|
|
|
|
} |
|
|
|
|
pressure_tick(net, now_ms); |
|
|
|
|
stream_optimizers_tick(net->inst, now_ms); |
|
|
|
|
relay_tick(net, now_ms); |
|
|
|
|
stream_network_wake(net); |
|
|
|
|
net->next_tick_ms = get_time_tb() / 10 + STREAM_TICK_TB / 10; |
|
|
|
|
net->timer = uasync_set_timeout(net->inst->ua, STREAM_TICK_TB, net, network_tick, "stream_network"); |
|
|
|
|
if (!net->timer) DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream network timer scheduling failed"); |
|
|
|
|
@ -1045,6 +1066,7 @@ int stream_network_init(struct UTUN_INSTANCE *inst, struct stream_network **out)
|
|
|
|
|
void stream_network_destroy(struct stream_network *net) { |
|
|
|
|
if (!net) return; |
|
|
|
|
net->stopping = 1; if (net->timer) uasync_cancel_timeout(net->inst->ua, net->timer); |
|
|
|
|
if (net->work) uasync_call_soon_cancel(net->inst->ua, net->work); |
|
|
|
|
while (net->relays) { |
|
|
|
|
struct stream_relay *relay = net->relays; net->relays = relay->next; |
|
|
|
|
stream_close(relay->owner); u_free(relay); |
|
|
|
|
|