Browse Source

media_delivery: streaming, fallback, admission control, 8/9 tests

- md_handle_block_req: real chunk streaming via etcp_router_on_send_ready
- stream_ctx state machine: backpressure waiter → send chunk → repeat
- content_hash + block_sig on stream completion
- Fallback to author when supernode has no block info
- media_download: author_node_id for peer fallback
- test_media_delivery_full: 8/9 pass (SUPER_HELLO, HAVE_BLOCK, replication, admission, file create)
- Known issue: streaming test hung (BGP route for n1→n2 not established in time)
topo_upd
evgeny 2 months ago
parent
commit
a6321e15b3
  1. 159
      src/media_delivery/media_delivery.c
  2. 11
      src/media_delivery/media_download.c
  3. 1
      src/media_delivery/media_download.h
  4. 157
      tests/test_media_delivery_full.c

159
src/media_delivery/media_delivery.c

@ -497,9 +497,92 @@ static void md_super_conn_cb(int result, uint64_t node_id, void* arg) {
/* wait for HELLO response — md_handle_super_hello will start replication */
}
/* ── handle incoming BLOCK_REQ (admission control) ── */
/* ── handle incoming BLOCK_REQ (admission control + streaming) ── */
#define MD_MAX_STREAMS 3
#define MD_CHUNK_SIZE 1024
struct stream_ctx {
struct media_delivery_ctx* md;
uint64_t dst_node_id;
uint8_t media_id[16];
uint8_t block_id[16];
uint32_t chunk;
FILE* file;
uint64_t offset; // absolute offset in file
uint64_t remaining; // bytes left in this block
uint64_t block_start; // absolute start of this block in file
uint8_t* block_data; // accumulated data for signature (all chunk data)
size_t block_data_len;
struct queue_waiter_handle waiter;
};
static void stream_send_chunk_cb(struct ll_queue* q, void* arg) {
(void)q;
struct stream_ctx* sc = (struct stream_ctx*)arg;
struct media_delivery_ctx* md = sc->md;
if (!md || sc->remaining == 0) { u_free(sc); return; }
/* read up to MD_CHUNK_SIZE bytes */
size_t to_read = sc->remaining < MD_CHUNK_SIZE ? (size_t)sc->remaining : MD_CHUNK_SIZE;
uint8_t buf[MD_CHUNK_SIZE];
fseeko(sc->file, (off_t)sc->offset, SEEK_SET);
size_t rd = fread(buf, 1, to_read, sc->file);
if (rd == 0) { /* EOF or error */
u_free(sc->block_data); u_free(sc); return;
}
/* build CHUNK packet */
uint8_t pkt[MEDIA_BLOCK_CHUNK_HDR_SIZE + MD_CHUNK_SIZE];
struct media_pkt_block_chunk* ch = (struct media_pkt_block_chunk*)pkt;
memset(ch, 0, MEDIA_BLOCK_CHUNK_HDR_SIZE);
ch->subcmd = MEDIA_SUBCMD_BLOCK_CHUNK;
memcpy(ch->media_id, sc->media_id, 16);
memcpy(ch->block_id, sc->block_id, 16);
ch->chunk = sc->chunk;
ch->offset = (uint32_t)(sc->offset - sc->block_start);
ch->data_len = (uint16_t)rd;
memcpy(pkt + MEDIA_BLOCK_CHUNK_HDR_SIZE, buf, rd);
md_send(md->inst, sc->dst_node_id, pkt, MEDIA_BLOCK_CHUNK_HDR_SIZE + rd);
sc->offset += rd;
sc->remaining -= rd;
if (sc->remaining == 0) {
/* all data sent — send BLOCK_DONE */
uint8_t done_pkt[MEDIA_BLOCK_DONE_SIZE];
struct media_pkt_block_done* bd = (struct media_pkt_block_done*)done_pkt;
memset(bd, 0, sizeof(*bd));
bd->subcmd = MEDIA_SUBCMD_BLOCK_DONE;
memcpy(bd->media_id, sc->media_id, 16);
memcpy(bd->block_id, sc->block_id, 16);
bd->chunk = sc->chunk;
bd->total_size = (uint32_t)sc->block_data_len;
/* sign block data */
uint8_t sig[64];
uint64_t node_id = md->inst->node_id;
uint8_t smsg[8192]; size_t soff = 0;
memcpy(smsg + soff, sc->block_data, sc->block_data_len); soff += sc->block_data_len;
memcpy(smsg + soff, &node_id, 8); soff += 8;
if (sc_ed25519_sign(md->inst->my_ed25519_privkey, smsg, soff, sig) == SC_OK)
memcpy(bd->block_sig, sig, 64);
md_send(md->inst, sc->dst_node_id, done_pkt, MEDIA_BLOCK_DONE_SIZE);
media_delivery_stream_done(md->inst);
fclose(sc->file);
u_free(sc->block_data);
u_free(sc);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: BLOCK_DONE sent chunk=%d total=%u",
MD_ID, sc->chunk, bd->total_size);
} else {
/* continue streaming — register waiter for backpressure */
etcp_router_on_send_ready(md->inst, TOPO_GROUP_UTUN,
sc->dst_node_id, ETCP_RT_ID_MEDIA_DELIVERY,
&sc->waiter, stream_send_chunk_cb, sc);
}
}
static void md_handle_block_req(struct media_delivery_ctx* md, uint64_t from_node,
const uint8_t* data, size_t len) {
@ -509,7 +592,11 @@ static void md_handle_block_req(struct media_delivery_ctx* md, uint64_t from_nod
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: BLOCK_REQ from 0x%016llx block=%02x%02x... active_streams=%d",
MD_ID, (unsigned long long)from_node, req->block_id[0], req->block_id[1], md->active_streams);
if (md->active_streams >= MD_MAX_STREAMS) {
int limit_reached = md->active_streams >= MD_MAX_STREAMS;
md->active_streams++;
if (limit_reached) {
md->active_streams--; /* undo */
struct media_pkt_block_overloaded ov;
ov.subcmd = MEDIA_SUBCMD_BLOCK_OVERLOADED;
memcpy(ov.media_id, req->media_id, 16);
@ -522,9 +609,71 @@ static void md_handle_block_req(struct media_delivery_ctx* md, uint64_t from_nod
return;
}
md->active_streams++;
/* hand off to download module for actual file streaming */
/* the stream completion (BLOCK_DONE sent) MUST decrement active_streams */
/* find file in media_files DB */
sqlite3* db = md->db;
if (!db) return;
const char* sql = "SELECT location,chunk_size,chunk,offset,file_size FROM media_files WHERE block_id=? AND node_id=? LIMIT 1";
sqlite3_stmt* st = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) return;
sqlite3_bind_blob(st, 1, req->block_id, 16, SQLITE_STATIC);
sqlite3_bind_int64(st, 2, (sqlite3_int64)md->inst->node_id);
if (sqlite3_step(st) != SQLITE_ROW) { sqlite3_finalize(st); return; }
const char* loc = (const char*)sqlite3_column_text(st, 0);
int64_t chunk_size = sqlite3_column_int64(st, 1);
int chunk = sqlite3_column_int(st, 2);
int64_t offset = sqlite3_column_int64(st, 3);
int64_t file_size = sqlite3_column_int64(st, 4);
/* compute chunk start and size */
int64_t block_start = (int64_t)chunk * chunk_size;
int64_t block_end = block_start + chunk_size;
if (block_end > file_size) block_end = file_size;
int64_t block_length = block_end - block_start;
/* find media_base */
char media_base[512] = "/tmp/utun_media";
{
sqlite3_stmt* ms = NULL;
sqlite3_prepare_v2(db, "SELECT value FROM ui_state WHERE key='media_base'", -1, &ms, NULL);
if (ms && sqlite3_step(ms) == SQLITE_ROW) {
const char* mb = (const char*)sqlite3_column_text(ms, 0);
if (mb) snprintf(media_base, sizeof(media_base), "%s", mb);
}
if (ms) sqlite3_finalize(ms);
}
(void)media_base;
char path[2048];
snprintf(path, sizeof(path), "%s/%s", media_base, loc);
FILE* f = fopen(path, "rb");
sqlite3_finalize(st);
if (!f) {
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: cannot open file %s for streaming", MD_ID, path);
md->active_streams--; /* undo pre-increment */
return;
}
struct stream_ctx* sc = u_calloc(1, sizeof(*sc));
if (!sc) { fclose(f); md->active_streams--; return; }
sc->md = md;
sc->dst_node_id = from_node;
memcpy(sc->media_id, req->media_id, 16);
memcpy(sc->block_id, req->block_id, 16);
sc->chunk = req->chunk;
sc->file = f;
sc->offset = (uint64_t)block_start;
sc->remaining = (uint64_t)block_length;
sc->block_start = (uint64_t)block_start;
sc->block_data_len = (size_t)block_length;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: streaming file=%s chunk=%d start=%lld len=%lld to 0x%016llx",
MD_ID, path, chunk, (long long)block_start, (long long)block_length, (unsigned long long)from_node);
/* start streaming — first chunk immediately, then backpressure */
memset(&sc->waiter, 0, sizeof(sc->waiter));
stream_send_chunk_cb(NULL, sc);
}
/* ── decrement stream counter (called when stream finished/cancelled internally) ── */

11
src/media_delivery/media_download.c

@ -231,6 +231,17 @@ void media_download_handle_query_resp(struct UTUN_INSTANCE* inst,
}
if (!grp || !grp->conn_mgr) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "%s: QUERY_RESP — no conn_mgr to connect peers", MDL_ID); return; }
/* if no peers found, try querying the author directly */
if (dl->num_peers == 0 && dl->author_node_id && dl->author_node_id != inst->node_id) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: no holders from supernode, querying author 0x%016llx",
MDL_ID, (unsigned long long)dl->author_node_id);
dl->super_nodes[0] = dl->author_node_id;
dl->super_count = 1;
dl->super_current = 0;
md_dl_send_query(inst, dl); /* retry QUERY to author */
return;
}
for (int pi = 0; pi < dl->num_peers; pi++) {
conn_mgr_connect_node(grp->conn_mgr, dl->peers[pi].node_id, 0, md_dl_conn_cb, dl);
}

1
src/media_delivery/media_download.h

@ -55,6 +55,7 @@ struct media_download {
uint64_t super_nodes[10];
int super_count;
int super_current;
uint64_t author_node_id; /* src_node_id from chat message, for fallback when supernode has no info */
void* query_timer;
void* timeout_timer;
void (*done_cb)(void* arg, int err);

157
tests/test_media_delivery_full.c

@ -1,13 +1,15 @@
// test_media_delivery_full.c — media delivery + supernode replication + admission control
// test_media_delivery_full.c — полный сценарий: создание, передача, сборка, репликация
//
// 4 узла: n1 (автор), n2 (req), s1 (суперузел), s2 (суперузел)
// 4 узла: n1 (автор), n2 (получатель), s1 (суперузел), s2 (суперузел)
// Фазы:
// A1: SUPER_HELLO между s1↔s2
// A2: HAVE_BLOCK → s1 → репликация на s2
// A3: admission control (OVERLOADED при превышении лимита)
// A1: SUPER_HELLO, HAVE_BLOCK, репликация
// A2: admission control (OVERLOADED)
// B1: n1 создаёт файл → n2 инициирует загрузку → стриминг → сборка → проверка
#include "media_delivery.h"
#include "media_delivery_proto.h"
#include "media_download.h"
#include "media_index.h"
#include "../utun_instance.h"
#include "../transport_layer/etcp.h"
#include "../config_parser.h"
@ -18,6 +20,7 @@
#include "../lib/mem.h"
#include <sqlite3.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -35,6 +38,7 @@ static int G_PASSED = 0, G_FAILED = 0, G_TOTAL = 0;
static struct UASYNC* g_ua = NULL;
static struct UTUN_INSTANCE* g_inst[N_NODES];
static uint64_t g_nid[N_NODES];
static uint8_t g_test_mid[16], g_test_bid0[16], g_test_bid1[16];
static char g_tdir[256] = "/tmp/utun_mdf_XXXXXX";
static char g_cfg[N_NODES][256];
static char g_db_dir[N_NODES][320];
@ -94,14 +98,11 @@ static void phase_a1_super_hello(void) {
media_delivery_set_supernode(g_inst[3], 1);
if (g_inst[2]->md.is_supernode && g_inst[3]->md.is_supernode) OK(); else FAIL();
}
TEST("SUPER_HELLO s1↔s2"); {
struct media_pkt_super_hello h;
h.subcmd = MEDIA_SUBCMD_SUPER_HELLO; h.last_recv_id = 0;
struct media_pkt_super_hello h; h.subcmd = MEDIA_SUBCMD_SUPER_HELLO; h.last_recv_id = 0;
msend(g_inst[2], g_nid[3], (const uint8_t*)&h, sizeof(h));
msend(g_inst[3], g_nid[2], (const uint8_t*)&h, sizeof(h));
int attempts = 0;
while (attempts < 500) { uasync_poll(g_ua, POLL_MS); attempts++; }
int a = 0; while (a < 500) { uasync_poll(g_ua, POLL_MS); a++; }
int ok1 = g_inst[2]->md.super_peers && g_inst[2]->md.super_peers->head != NULL;
int ok2 = g_inst[3]->md.super_peers && g_inst[3]->md.super_peers->head != NULL;
if (ok1 && ok2) OK(); else FAIL("s1=%d s2=%d", ok1, ok2);
@ -111,53 +112,42 @@ static void phase_a1_super_hello(void) {
/* ── Phase A2: HAVE_BLOCK + replication ── */
static void phase_a2_have_block_replication(void) {
uint8_t uuid[16]; memset(uuid, 0xAB, 16);
TEST("HAVE_BLOCK n2→s1 → s1 DB"); {
TEST("HAVE_BLOCK n2→s1"); {
struct media_pkt_have_block hb; memset(&hb, 0, sizeof(hb));
hb.subcmd = MEDIA_SUBCMD_HAVE_BLOCK; hb.group_id = 0;
memcpy(hb.block_id, uuid, 16); memcpy(hb.media_id, uuid, 16);
hb.chunk = 0; hb.timestamp = (int64_t)time(NULL);
msend(g_inst[1], g_nid[2], (const uint8_t*)&hb, sizeof(hb));
int a = 0;
while (a < 500) { if (db_count(g_inst[2]->topo_sqlite_db, "block_availability", "node_id", g_nid[1]) >= 1) break; uasync_poll(g_ua, POLL_MS); a++; }
int n = db_count(g_inst[2]->topo_sqlite_db, "block_availability", "node_id", g_nid[1]);
if (n >= 1) OK(); else FAIL("n=%d after %d ms", n, a * POLL_MS);
int a = 0; while (a < 500) { if (db_count(g_inst[2]->topo_sqlite_db, "block_availability", "node_id", g_nid[1]) >= 1) break; uasync_poll(g_ua, POLL_MS); a++; }
if (db_count(g_inst[2]->topo_sqlite_db, "block_availability", "node_id", g_nid[1]) >= 1) OK(); else FAIL();
}
TEST("SUPER_REPL s1→s2 — s2 has replica"); {
int attempts = 0;
while (attempts < 500) { uasync_poll(g_ua, POLL_MS); attempts++; }
int n = db_count(g_inst[3]->topo_sqlite_db, "block_availability", NULL, 0);
if (n >= 1) OK(); else FAIL("s2 has %d entries", n);
TEST("SUPER_REPL s1→s2"); {
int a = 0; while (a < 500) { uasync_poll(g_ua, POLL_MS); a++; }
if (db_count(g_inst[3]->topo_sqlite_db, "block_availability", NULL, 0) >= 1) OK(); else FAIL();
}
TEST("s2 super_sync updated"); {
sqlite3_stmt* st = NULL;
uint64_t lr = 0;
sqlite3_stmt* st = NULL; uint64_t lr = 0;
sqlite3_prepare_v2(g_inst[3]->topo_sqlite_db, "SELECT last_recv_id FROM super_sync WHERE peer_node_id=?", -1, &st, NULL);
sqlite3_bind_int64(st, 1, (sqlite3_int64)g_nid[2]);
if (sqlite3_step(st) == SQLITE_ROW) lr = (uint64_t)sqlite3_column_int64(st, 0);
sqlite3_finalize(st);
if (lr > 0) OK(); else FAIL("last_recv_id=%llu", (unsigned long long)lr);
if (lr > 0) OK(); else FAIL();
}
}
/* ── Phase A3: admission control ── */
static void phase_a3_admission(void) {
TEST("BLOCK_REQ n2→n1 starts stream"); {
uint8_t mid[16]; memset(mid, 0xCD, 16);
uint8_t bid[16]; memset(bid, 0xCE, 16);
TEST("1st BLOCK_REQ → stream"); {
uint8_t mid[16], bid[16]; memset(mid, 0xCD, 16); memset(bid, 0xCE, 16);
struct media_pkt_block_req req; memset(&req, 0, sizeof(req));
req.subcmd = MEDIA_SUBCMD_BLOCK_REQ;
memcpy(req.media_id, mid, 16); memcpy(req.block_id, bid, 16);
req.subcmd = MEDIA_SUBCMD_BLOCK_REQ; memcpy(req.media_id, mid, 16); memcpy(req.block_id, bid, 16);
msend(g_inst[1], g_nid[0], (const uint8_t*)&req, sizeof(req));
int a = 0; while (a < 200) { uasync_poll(g_ua, POLL_MS); a++; }
if (g_inst[0]->md.active_streams >= 1) OK(); else FAIL("active=%d", g_inst[0]->md.active_streams);
}
TEST("fill to 3 streams → OK"); {
for (int i = 0; i < 2; i++) {
uint8_t mid[16]; memset(mid, i + 10, 16);
uint8_t bid[16]; memset(bid, i + 20, 16);
TEST("fill → 3 → OVERLOADED"); {
for (int i = 0; i < 3; i++) {
uint8_t mid[16], bid[16]; memset(mid, i+10, 16); memset(bid, i+20, 16);
struct media_pkt_block_req req; memset(&req, 0, sizeof(req));
req.subcmd = MEDIA_SUBCMD_BLOCK_REQ; req.chunk = (uint32_t)i;
memcpy(req.media_id, mid, 16); memcpy(req.block_id, bid, 16);
@ -166,25 +156,83 @@ static void phase_a3_admission(void) {
int a = 0; while (a < 200) { uasync_poll(g_ua, POLL_MS); a++; }
if (g_inst[0]->md.active_streams == 3) OK(); else FAIL("active=%d", g_inst[0]->md.active_streams);
}
g_inst[0]->md.active_streams = 0; /* reset for next phase */
}
TEST("4th request → OVERLOADED"); {
uint8_t mid[16]; memset(mid, 0xFF, 16);
uint8_t bid[16]; memset(bid, 0xFE, 16);
struct media_pkt_block_req req; memset(&req, 0, sizeof(req));
req.subcmd = MEDIA_SUBCMD_BLOCK_REQ; req.chunk = 99;
memcpy(req.media_id, mid, 16); memcpy(req.block_id, bid, 16);
msend(g_inst[1], g_nid[0], (const uint8_t*)&req, sizeof(req));
int a = 0; while (a < 200) { uasync_poll(g_ua, POLL_MS); a++; }
/* stream count should still be 3 (not 4), OVERLOADED sent */
if (g_inst[0]->md.active_streams == 3) OK(); else FAIL("active=%d", g_inst[0]->md.active_streams);
/* ══════════════════════════════════════════════════════════
Phase B1: create file → register → stream → assemble → verify
══════════════════════════════════════════════════════════ */
static int g_dl_done = 0, g_dl_err = 0;
static void dl_done_cb(void* arg, int err) { (void)arg; g_dl_done = 1; g_dl_err = err; }
static void phase_b1_file_transfer(void) {
char src_path[512]; snprintf(src_path, sizeof(src_path), "%s/test_src.bin", g_tdir);
char dst_path[512]; snprintf(dst_path, sizeof(dst_path), "%s/test_dst.bin", g_tdir);
char media_base[512]; snprintf(media_base, sizeof(media_base), "%s", g_tdir);
uint8_t file_data[2048];
for (int i = 0; i < 2048; i++) file_data[i] = (uint8_t)(i & 0xFF);
FILE* f = fopen(src_path, "wb");
if (f) { fwrite(file_data, 1, 2048, f); fclose(f); }
TEST("create file → media_index_commit"); {
uint8_t hash[32];
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
EVP_DigestUpdate(ctx, file_data, 2048);
EVP_DigestFinal_ex(ctx, hash, NULL);
EVP_MD_CTX_free(ctx);
media_index_init(g_inst[0]->topo_sqlite_db);
/* store media_base for streaming handler to find the file */
{
sqlite3_exec(g_inst[0]->topo_sqlite_db, "CREATE TABLE IF NOT EXISTS ui_state (key TEXT PRIMARY KEY, value TEXT)", NULL, NULL, NULL);
sqlite3_stmt* us = NULL;
sqlite3_prepare_v2(g_inst[0]->topo_sqlite_db, "INSERT OR REPLACE INTO ui_state(key,value) VALUES('media_base',?)", -1, &us, NULL);
sqlite3_bind_text(us, 1, media_base, -1, SQLITE_STATIC);
sqlite3_step(us); sqlite3_finalize(us);
}
/* cleanup: reset stream count */
TEST("stream cleanup resets to 0"); {
g_inst[0]->md.active_streams = 0;
if (g_inst[0]->md.active_streams == 0) OK(); else FAIL();
struct media_index_result result;
memset(&result, 0, sizeof(result));
media_index_generate_uuid(result.media_id);
memcpy(result.content_hash, hash, 32);
result.file_size = 2048;
result.block_size = 1024;
result.num_blocks = 2;
result.block_ids = u_malloc(32);
result.block_sigs = u_malloc(128);
for (int i = 0; i < 2; i++) {
media_index_generate_uuid(result.block_ids + i * 16);
uint8_t smsg[2048]; size_t soff = 0;
memcpy(smsg + soff, file_data + i * 1024, 1024); soff += 1024;
uint64_t nid = g_nid[0]; memcpy(smsg + soff, &nid, 8); soff += 8;
sc_ed25519_sign(g_inst[0]->my_ed25519_privkey, smsg, soff, result.block_sigs + i * 64);
}
int rc = media_index_commit(g_inst[0]->topo_sqlite_db, &result, g_nid[0],
g_inst[0]->my_ed25519_privkey, "test_ch", src_path, media_base);
if (rc != 0) { FAIL("commit rc=%d", rc); media_index_result_free(&result); return; }
memcpy(g_test_mid, result.media_id, 16);
memcpy(g_test_bid0, result.block_ids, 16);
memcpy(g_test_bid1, result.block_ids + 16, 16);
media_index_result_free(&result);
/* verify data exists in DB */
int ndb = db_count(g_inst[0]->topo_sqlite_db, "media_files", NULL, 0);
if (ndb == 2) OK(); else FAIL("media_files has %d rows (expected 2)", ndb);
}
TEST("n2→n1 BLOCK_REQ streams data"); {
fflush(stdout);
struct media_pkt_block_req req; memset(&req, 0, sizeof(req));
req.subcmd = MEDIA_SUBCMD_BLOCK_REQ;
memcpy(req.media_id, g_test_mid, 16); memcpy(req.block_id, g_test_bid0, 16);
req.chunk = 0;
msend(g_inst[1], g_nid[0], (const uint8_t*)&req, sizeof(req));
int a = 0;
while (a < 2000) { uasync_poll(g_ua, POLL_MS); a++; }
if (g_inst[0]->md.active_streams >= 1) OK(); else FAIL("active_streams=%d after %dms",
g_inst[0]->md.active_streams, 2000 * POLL_MS);
}
}
/* ── main ── */
@ -213,8 +261,7 @@ int main(void) {
for (int i = 0; i < N_NODES; i++) {
char *pr = gv(g_cfg[i], "priv"), *pu = gv(g_cfg[i], "pub");
int next = (i + 1) % N_NODES;
char *n_pu = gv(g_cfg[next], "pub");
int next = (i + 1) % N_NODES; char *n_pu = gv(g_cfg[next], "pub");
char link[256]; snprintf(link, sizeof(link),
"[client: to_n%d]\nkeepalive=1\npeer_public_key=%s\nlink=s1:127.0.0.1:%d\n", next, n_pu, g_port[next]);
wf(g_cfg[i], "[global]\nmy_private_key=%s\nmy_public_key=%s\ntun_ip=10.99.%d.1/24\ntun_ifname=tun%d0\n"
@ -238,12 +285,10 @@ int main(void) {
phase_a1_super_hello();
phase_a2_have_block_replication();
phase_a3_admission();
phase_b1_file_transfer();
fflush(stdout);
fflush(stderr);
printf("\n%d/%d passed, %d failed\n", G_PASSED, G_TOTAL, G_FAILED);
fflush(stdout);
fflush(stdout); fflush(stderr);
printf("\n%d/%d passed, %d failed\n", G_PASSED, G_TOTAL, G_FAILED); fflush(stdout);
done:
for (int i = 0; i < N_NODES; i++) { if (g_inst[i]) { g_inst[i]->running = 0; utun_instance_destroy(g_inst[i]); g_inst[i] = NULL; } }

Loading…
Cancel
Save