|
|
|
|
@ -55,14 +55,14 @@ static int automatic_drop_tail;
|
|
|
|
|
static etcp_recv_fn automatic_handlers[4]; |
|
|
|
|
static uint8_t automatic_request[STREAM_WIRE_HEADER + 1]; |
|
|
|
|
static etcp_recv_fn relay_raw_handlers[4], relay_route_handler, relay_status_handler; |
|
|
|
|
static unsigned relay_data[3], relay_ends[3], relay_requests_seen, relay_statuses_seen; |
|
|
|
|
static unsigned relay_data[3], relay_ends[3], relay_requests_seen, relay_statuses_seen, relay_cancels_seen; |
|
|
|
|
static int relay_drop_source; |
|
|
|
|
static uint8_t relay_request_wire[STREAM_WIRE_HEADER]; |
|
|
|
|
static struct { |
|
|
|
|
int hold_info, hold_request, check_starts; |
|
|
|
|
int hold_info, hold_request, hold_ready, check_starts; |
|
|
|
|
uint8_t info[STREAM_WIRE_HEADER + STREAM_INFO_SIZE + STREAM_PATH_MAX * 8]; |
|
|
|
|
size_t info_length; |
|
|
|
|
unsigned source_subscribes, helper_subscribes, accepted; |
|
|
|
|
unsigned source_subscribes, helper_subscribes, accepted, ready_held; |
|
|
|
|
uint64_t request_tb, start; |
|
|
|
|
} relay_race; |
|
|
|
|
static struct { |
|
|
|
|
@ -1045,6 +1045,8 @@ static void relay_test_raw(struct ETCP_CONN *conn, struct ll_entry *entry) {
|
|
|
|
|
|
|
|
|
|
/* Сохраняем реальный подписанный routed-запрос для проверки позднего повтора после освобождения буфера. */ |
|
|
|
|
static void relay_test_routed(struct ETCP_CONN *conn, struct ll_entry *entry) { |
|
|
|
|
if (entry->len >= ROUTER_SVC_PAYLOAD_OFF + STREAM_WIRE_HEADER |
|
|
|
|
&& entry->dgram[ROUTER_SVC_PAYLOAD_OFF + 2] == STREAM_CMD_RELAY_CANCEL) relay_cancels_seen++; |
|
|
|
|
if (entry->len >= ROUTER_SVC_PAYLOAD_OFF + STREAM_WIRE_HEADER |
|
|
|
|
&& entry->dgram[ROUTER_SVC_PAYLOAD_OFF + 2] == STREAM_CMD_RELAY_REQUEST) { |
|
|
|
|
memcpy(relay_request_wire, entry->dgram + ROUTER_SVC_PAYLOAD_OFF, STREAM_WIRE_HEADER); relay_requests_seen++; |
|
|
|
|
@ -1057,7 +1059,15 @@ static void relay_test_routed(struct ETCP_CONN *conn, struct ll_entry *entry) {
|
|
|
|
|
/* Счётчик STATUS выявляет ответы на дубликаты, не меняя подписанное управление и его порядок. */ |
|
|
|
|
static void relay_test_status(struct ETCP_CONN *conn, struct ll_entry *entry) { |
|
|
|
|
if (entry->len >= ROUTER_SVC_PAYLOAD_OFF + STREAM_WIRE_HEADER |
|
|
|
|
&& entry->dgram[ROUTER_SVC_PAYLOAD_OFF + 2] == STREAM_CMD_RELAY_STATUS) relay_statuses_seen++; |
|
|
|
|
&& entry->dgram[ROUTER_SVC_PAYLOAD_OFF + 2] == STREAM_CMD_RELAY_STATUS) { |
|
|
|
|
relay_statuses_seen++; |
|
|
|
|
size_t payload = ROUTER_SVC_PAYLOAD_OFF + STREAM_WIRE_HEADER; |
|
|
|
|
if (relay_race.hold_ready && entry->len > payload && entry->dgram[payload] == STREAM_RELAY_READY) { |
|
|
|
|
relay_race.ready_held++; |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "bootstrap test holds READY ordinal=%u", relay_race.ready_held); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
relay_status_handler(conn, entry); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -1150,19 +1160,33 @@ static void test_supernode_relay(void) {
|
|
|
|
|
CHECK(stream_subscribe_open(nodes[2], GROUP2, nodes[3]->node_id, &viewers[2]) == STREAM_OK); |
|
|
|
|
test_clock_run_for(ua, 500); stream_close(viewers[2]); viewers[2] = NULL; |
|
|
|
|
test_clock_run_for(ua, 2000); CHECK(relay_requests_seen == requests_before); |
|
|
|
|
memset(&relay_race, 0, sizeof(relay_race)); relay_race.hold_info = relay_race.check_starts = 1; |
|
|
|
|
/* Merkle объявляет буфер помощника раньше STATUS READY: выбранная выдача должна удержать STARTING-запрос. */ |
|
|
|
|
memset(&relay_race, 0, sizeof(relay_race)); relay_race.hold_ready = 1; |
|
|
|
|
relay_drop_source = 1; |
|
|
|
|
unsigned cancellations_before = relay_cancels_seen; |
|
|
|
|
unsigned expected_data = relay_data[2] + 1; |
|
|
|
|
CHECK(stream_subscribe_open(nodes[2], GROUP2, nodes[3]->node_id, &viewers[2]) == STREAM_OK); |
|
|
|
|
deadline = get_time_tb() + 40000; |
|
|
|
|
while (relay_data[2] < expected_data && relay_cancels_seen == cancellations_before && get_time_tb() < deadline) |
|
|
|
|
test_clock_poll(ua, 100); |
|
|
|
|
CHECK(relay_race.ready_held && relay_cancels_seen == cancellations_before); |
|
|
|
|
CHECK(relay_data[2] == expected_data && relay_race.helper_subscribes); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "[PASS] helper INFO before delayed READY keeps selected pending issuance; no premature CANCEL"); |
|
|
|
|
stream_close(viewers[2]); viewers[2] = NULL; test_clock_run_for(ua, 40000); |
|
|
|
|
CHECK(stream_local_get(nodes[1], &origin.descriptor, &local) == STREAM_WAIT); |
|
|
|
|
memset(&relay_race, 0, sizeof(relay_race)); relay_race.hold_info = relay_race.check_starts = 1; |
|
|
|
|
started = get_time_tb(); |
|
|
|
|
expected_data = relay_data[2] + 1; |
|
|
|
|
CHECK(stream_subscribe_open(nodes[2], GROUP2, nodes[3]->node_id, &viewers[2]) == STREAM_OK); |
|
|
|
|
deadline = get_time_tb() + 300000; |
|
|
|
|
while (relay_data[2] < 3 && get_time_tb() < deadline) test_clock_poll(ua, 100); |
|
|
|
|
CHECK(relay_data[2] == 3 && relay_requests_seen && !relay_data[1]); |
|
|
|
|
while (relay_data[2] < expected_data && get_time_tb() < deadline) test_clock_poll(ua, 100); |
|
|
|
|
CHECK(relay_data[2] == expected_data && relay_requests_seen && !relay_data[1]); |
|
|
|
|
CHECK(get_time_tb() - started < 10000 && relay_race.request_tb - started >= 990); |
|
|
|
|
uint64_t connected_ms = (get_time_tb() - started) / 10; |
|
|
|
|
test_clock_run_for(ua, 1000); CHECK(relay_race.accepted == 255); |
|
|
|
|
CHECK(relay_race.helper_subscribes && !relay_race.source_subscribes); |
|
|
|
|
relay_release_info(); test_clock_run_for(ua, 1000); |
|
|
|
|
CHECK(!relay_race.source_subscribes && relay_data[2] == 3); |
|
|
|
|
CHECK(!relay_race.source_subscribes && relay_data[2] == expected_data); |
|
|
|
|
struct stream_message duplicate; CHECK(stream_wire_parse(relay_request_wire, sizeof(relay_request_wire), &duplicate) == STREAM_OK); |
|
|
|
|
CHECK(duplicate.receiver_epoch); |
|
|
|
|
unsigned statuses_before = relay_statuses_seen; |
|
|
|
|
|