diff --git a/doc/stream.txt b/doc/stream.txt index 15aa0088..3f9b4bec 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -216,6 +216,10 @@ RENEW создаёт только продление существующей в Поколения пиров согласуются при прямом INFO-обмене до SUBSCRIBE. При DOWN, REINIT или закрытии старое поколение инвалидируется вместе с его выдачами. Поздние ACCEPT/DATA/routed CLOSED не восстанавливают их. ETCP_CONN может пережить REINIT, его адрес не является ID сессии. +При REINIT или смене удалённой эпохи исходящий запрос CONNECTING/INFO без SUBSCRIBE-handle сохраняется: +его INFO-состояние и nonce очищаются, согласование продолжается с новым nonce и исходным сроком попытки. +При DOWN, окончательном закрытии транспорта или ошибке отправки такой запрос отменяется. +Сохранённый запрос с истёкшим сроком закрывается; повторные REINIT не продлевают его ожидание. Управляющие поля и размеры списков имеют явный byte order и пределы. ACCEPT содержит handle, фактический начальный индекс, границы кольца и путь субпотока. diff --git a/tests/test_stream_service.c b/tests/test_stream_service.c index 676a4a6b..5aaf2e8a 100644 --- a/tests/test_stream_service.c +++ b/tests/test_stream_service.c @@ -351,6 +351,8 @@ static void bootstrap_event(struct UTUN_INSTANCE *inst, const struct stream_even /* Холодное подключение, запоздалый ответ, ограниченный срок запроса и настоящий DOWN/DELETE. */ static void test_bootstrap(void) { + debug_level_t transport_level = g_debug_config.category_levels[DEBUG_CATEGORY_ETCP]; + debug_set_category_level(DEBUG_CATEGORY_ETCP, DEBUG_LEVEL_INFO); struct STREAM_HANDLE *publisher = NULL, *subscriber = NULL; struct stream_parameters parameters = {.n = 1, .r = 0, .block_size = STREAM_RS_DEFAULT_SIZE}; CHECK(stream_publish_open(nodes[3], GROUP1, ¶meters, &publisher) == STREAM_OK); @@ -368,6 +370,9 @@ static void test_bootstrap(void) { CHECK(stream_subscribe_open(nodes[1], GROUP1, nodes[3]->node_id, &subscriber) == STREAM_OK); run_until(&bootstrap.data, 1); struct stream_selection_info selected; CHECK(stream_selection_get_info(subscriber, &selected) == STREAM_OK); + DEBUG_INFO(DEBUG_CATEGORY_STREAM, "bootstrap result REINIT=%u probes=%llu subflows=%u failures=%llu", + bootstrap.reinits, (unsigned long long)selected.probes_started, selected.subflows, + (unsigned long long)selected.failures); CHECK(bootstrap.reinits == 1 && selected.probes_started == 1 && selected.subflows == 1 && !selected.failures); CHECK(get_time_tb() - started < 100000); DEBUG_INFO(DEBUG_CATEGORY_STREAM, "[PASS] first automatic subscription survives initial REINIT: elapsed_ms=%llu probes=%llu", @@ -427,6 +432,7 @@ static void test_bootstrap(void) { CHECK(etcp_bind(nodes[1], ETCP_ID_STREAM, bootstrap.receive) == 0); etcp_remove_conn_status_cbk(nodes[1], bootstrap_status, NULL); stream_set_event_callback(nodes[1], on_stream, NULL); + debug_set_category_level(DEBUG_CATEGORY_ETCP, transport_level); DEBUG_INFO(DEBUG_CATEGORY_STREAM, "[PASS] transport DOWN/DELETE still cancels pending request"); } @@ -1007,8 +1013,11 @@ int main(void) { char priv[65], pub[65], config[1600]; hex(keys.private_key, priv); hex(keys.public_key, pub); unsigned type = i == 0 || i == 2 ? CLIENT_TYPE_MOBILE : CLIENT_TYPE_DESKTOP; snprintf(config, sizeof(config), "[global]\nmy_private_key=%s\nmy_public_key=%s\ndb_path=%s/node%u\nclient_type=%u\n" - "[server:udp]\naddr=127.0.0.1:0\ntype=public\n[allowed_keys]\nallow_all=1\n" - "[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\nmember_files_enabled=0\n", priv, pub, directory, i, type); + "[server:direct]\naddr=127.0.0.1:0\ntype=public\ntransport=%s\n" + "%s[allowed_keys]\nallow_all=1\n" + "[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\nmember_files_enabled=0\n", + priv, pub, directory, i, type, i == 3 ? "tcp" : "udp", + i == 3 ? "" : "[server:tcp]\naddr=127.0.0.1:0\ntype=public\ntransport=tcp\n"); nodes[i] = utun_instance_create_from_str(ua, config); CHECK(nodes[i] != NULL); snprintf(nodes[i]->name, sizeof(nodes[i]->name), "node%u", i); CHECK(utun_core_start(nodes[i]) == 0 && chat_service_start(nodes[i]) == 0 && nodes[i]->stream);