|
|
|
@ -33,9 +33,11 @@ static struct STREAM_HANDLE *reader1, *reader2; |
|
|
|
static unsigned data_events[4], end_events[4], closed_events[4]; |
|
|
|
static unsigned data_events[4], end_events[4], closed_events[4]; |
|
|
|
static int close_readers_in_callback; |
|
|
|
static int close_readers_in_callback; |
|
|
|
static unsigned network_data[4], network_end[4], accepts, reverse_requests, dropped_renew; |
|
|
|
static unsigned network_data[4], network_end[4], accepts, reverse_requests, dropped_renew; |
|
|
|
|
|
|
|
static unsigned network_gaps[4]; |
|
|
|
|
|
|
|
static uint64_t network_next[4] = {0, 1, 1, 0}; |
|
|
|
static uint8_t first_request[STREAM_WIRE_HEADER + 8]; |
|
|
|
static uint8_t first_request[STREAM_WIRE_HEADER + 8]; |
|
|
|
static etcp_recv_fn saved_raw[4], saved_route; |
|
|
|
static etcp_recv_fn saved_raw[4], saved_route; |
|
|
|
static int drop_renew; |
|
|
|
static int drop_renew, gap_batch; |
|
|
|
|
|
|
|
|
|
|
|
/* Протокол проходит настоящие ETCP/router обработчики; перехват только считает команды и имитирует потерю RENEW. */ |
|
|
|
/* Протокол проходит настоящие ETCP/router обработчики; перехват только считает команды и имитирует потерю RENEW. */ |
|
|
|
static void network_raw(struct ETCP_CONN *conn, struct ll_entry *entry) { |
|
|
|
static void network_raw(struct ETCP_CONN *conn, struct ll_entry *entry) { |
|
|
|
@ -46,6 +48,17 @@ static void network_raw(struct ETCP_CONN *conn, struct ll_entry *entry) { |
|
|
|
CHECK(entry->len == sizeof(first_request)); memcpy(first_request, entry->dgram, sizeof(first_request)); |
|
|
|
CHECK(entry->len == sizeof(first_request)); memcpy(first_request, entry->dgram, sizeof(first_request)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (node == 1 && command == STREAM_CMD_ACCEPT) accepts++; |
|
|
|
if (node == 1 && command == STREAM_CMD_ACCEPT) accepts++; |
|
|
|
|
|
|
|
/* Дыра поставщика внутри его окна: заменить DATA пачки 2 на честный GAP 2->3, сохранив сессию/handle. */ |
|
|
|
|
|
|
|
if (node == 1 && command == STREAM_CMD_DATA && gap_batch) { |
|
|
|
|
|
|
|
struct stream_message message; struct stream_path path; size_t used; |
|
|
|
|
|
|
|
CHECK(stream_wire_parse(entry->dgram, entry->len, &message) == STREAM_OK); |
|
|
|
|
|
|
|
CHECK(stream_path_parse(message.payload, message.length, &path, &used) == STREAM_OK); |
|
|
|
|
|
|
|
if (stream_read_be(message.payload + used + STREAM_BLOCK_SEQ_OFF, 8) == 2) { |
|
|
|
|
|
|
|
entry->dgram[2] = STREAM_CMD_GAP; entry->len = STREAM_WIRE_HEADER + 16; |
|
|
|
|
|
|
|
stream_write_be(entry->dgram + STREAM_WIRE_HEADER, 2, 8); |
|
|
|
|
|
|
|
stream_write_be(entry->dgram + STREAM_WIRE_HEADER + 8, 3, 8); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
if (node == 3 && command == STREAM_CMD_RENEW && drop_renew) { |
|
|
|
if (node == 3 && command == STREAM_CMD_RENEW && drop_renew) { |
|
|
|
dropped_renew++; queue_dgram_free(entry); queue_entry_free(entry); return; |
|
|
|
dropped_renew++; queue_dgram_free(entry); queue_entry_free(entry); return; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -64,8 +77,12 @@ static void on_network(struct UTUN_INSTANCE *inst, const struct stream_event *ev |
|
|
|
CHECK(event->descriptor.group_id == GROUP2 && event->descriptor.source_node_id == nodes[3]->node_id); |
|
|
|
CHECK(event->descriptor.group_id == GROUP2 && event->descriptor.source_node_id == nodes[3]->node_id); |
|
|
|
if (event->type == STREAM_EVENT_DATA) { |
|
|
|
if (event->type == STREAM_EVENT_DATA) { |
|
|
|
CHECK(event->length == sizeof(expected) && !memcmp(event->data, expected, sizeof(expected))); |
|
|
|
CHECK(event->length == sizeof(expected) && !memcmp(event->data, expected, sizeof(expected))); |
|
|
|
CHECK(event->first_seq == 1 + network_data[node]); network_data[node]++; |
|
|
|
CHECK(event->first_seq == network_next[node]++); network_data[node]++; |
|
|
|
} else if (event->type == STREAM_EVENT_END) network_end[node]++; |
|
|
|
} else if (event->type == STREAM_EVENT_END) network_end[node]++; |
|
|
|
|
|
|
|
else if (event->type == STREAM_EVENT_GAP) { |
|
|
|
|
|
|
|
CHECK(event->first_seq == network_next[node] && event->last_seq == 2); |
|
|
|
|
|
|
|
network_next[node] = event->last_seq + 1; network_gaps[node]++; |
|
|
|
|
|
|
|
} |
|
|
|
else CHECK(event->type == STREAM_EVENT_CLOSED); |
|
|
|
else CHECK(event->type == STREAM_EVENT_CLOSED); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -203,6 +220,15 @@ static void test_network(void) { |
|
|
|
} |
|
|
|
} |
|
|
|
CHECK(info.blocks == 1 && info.start == 1 && info.next == 2 && info.handle); |
|
|
|
CHECK(info.blocks == 1 && info.start == 1 && info.next == 2 && info.handle); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Новый bootstrap может получить уже сохранённый блок: DUPLICATE обязан установить общий старт. */ |
|
|
|
|
|
|
|
CHECK(stream_receive_restart(subscribers[1]) == STREAM_OK); |
|
|
|
|
|
|
|
network_data[1] = 0; network_next[1] = 1; first_request[0] = 0; |
|
|
|
|
|
|
|
for (unsigned i = 0; i < 8; i++) { |
|
|
|
|
|
|
|
struct stream_receive_info info; CHECK(stream_receive_get_info(up[i], &info) == STREAM_OK && info.state == STREAM_RECEIVE_CLOSED); |
|
|
|
|
|
|
|
stream_receive_close(up[i]); up[i] = NULL; |
|
|
|
|
|
|
|
CHECK(stream_receive_open(subscribers[1], nodes[3]->node_id, i, UINT64_MAX, &up[i]) == STREAM_OK); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
run_until(&network_data[1], 1); |
|
|
|
/* Node2 видит подписку relay через обычный Merkle-обмен, а не копирование из его SQLite. */ |
|
|
|
/* Node2 видит подписку relay через обычный Merkle-обмен, а не копирование из его SQLite. */ |
|
|
|
deadline = get_time_tb() + 150000; |
|
|
|
deadline = get_time_tb() + 150000; |
|
|
|
int ready = 0; |
|
|
|
int ready = 0; |
|
|
|
@ -243,10 +269,10 @@ static void test_network(void) { |
|
|
|
CHECK(etcp_route_send(nodes[1], GROUP2, nodes[3]->node_id, entry, 0, ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT) == 0); |
|
|
|
CHECK(etcp_route_send(nodes[1], GROUP2, nodes[3]->node_id, entry, 0, ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT) == 0); |
|
|
|
} |
|
|
|
} |
|
|
|
run_until(&reverse_requests, 2); |
|
|
|
run_until(&reverse_requests, 2); |
|
|
|
network_write(publisher, 2); run_until(&network_data[1], 2); run_until(&network_data[2], 2); |
|
|
|
gap_batch = 1; network_write(publisher, 2); run_until(&network_gaps[1], 1); gap_batch = 0; |
|
|
|
/* Снять два лишних проверочных субпотока: шесть оставшихся восстанавливают новые пачки. */ |
|
|
|
/* Снять два лишних проверочных субпотока: шесть оставшихся восстанавливают новые пачки. */ |
|
|
|
for (unsigned i = 6; i < 8; i++) { stream_receive_close(up[i]); up[i] = NULL; stream_receive_close(down[i]); down[i] = NULL; } |
|
|
|
for (unsigned i = 6; i < 8; i++) { stream_receive_close(up[i]); up[i] = NULL; stream_receive_close(down[i]); down[i] = NULL; } |
|
|
|
network_write(publisher, 3); run_until(&network_data[1], 3); run_until(&network_data[2], 3); |
|
|
|
network_write(publisher, 3); run_until(&network_data[1], 2); run_until(&network_data[2], 2); run_until(&network_gaps[2], 1); |
|
|
|
CHECK(stream_publish_finish(publisher) == STREAM_OK); |
|
|
|
CHECK(stream_publish_finish(publisher) == STREAM_OK); |
|
|
|
run_until(&network_end[1], 1); run_until(&network_end[2], 1); |
|
|
|
run_until(&network_end[1], 1); run_until(&network_end[2], 1); |
|
|
|
/* RENEW каждые 2с удерживает даже окончившуюся выдачу; затем имитируем отсутствие продлений. */ |
|
|
|
/* RENEW каждые 2с удерживает даже окончившуюся выдачу; затем имитируем отсутствие продлений. */ |
|
|
|
@ -271,7 +297,7 @@ static void test_network(void) { |
|
|
|
test_clock_run_for(ua, 1000); |
|
|
|
test_clock_run_for(ua, 1000); |
|
|
|
stream_set_event_callback(nodes[1], on_stream, NULL); stream_set_event_callback(nodes[2], NULL, NULL); |
|
|
|
stream_set_event_callback(nodes[1], on_stream, NULL); stream_set_event_callback(nodes[2], NULL, NULL); |
|
|
|
for (unsigned i = 0; i < 2; i++) topo_group_peer_close(connections[i]); |
|
|
|
for (unsigned i = 0; i < 2; i++) topo_group_peer_close(connections[i]); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "[PASS] live raw ETCP chain: common index, FEC, retained paths/LOOP, duplicate/reverse, END, renew/lease, REINIT"); |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "[PASS] live ETCP chain: common index/restart, FEC, paths/LOOP, GAP, duplicate/reverse, END, leases, REINIT"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Ошибка размера/SQLite не меняет подпись, userinfo, версию и производное Merkle-дерево. */ |
|
|
|
/* Ошибка размера/SQLite не меняет подпись, userinfo, версию и производное Merkle-дерево. */ |
|
|
|
|