|
|
|
|
@ -1463,19 +1463,9 @@ int media_delivery_bind(struct UTUN_INSTANCE* inst) {
|
|
|
|
|
return media_delivery_init(inst); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void media_delivery_announce_media(struct UTUN_INSTANCE* inst, uint64_t group_id, |
|
|
|
|
const uint8_t* media_id, const uint8_t* block_ids, |
|
|
|
|
int num_blocks) { |
|
|
|
|
if (!inst || !media_id || !block_ids || num_blocks <= 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: announce invalid args inst=%p media=%p blocks=%p n=%d", |
|
|
|
|
MD_ID, (void*)inst, (void*)media_id, (void*)block_ids, num_blocks); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
struct media_delivery_ctx* md = &inst->md; |
|
|
|
|
if (!md->initialized) return; |
|
|
|
|
|
|
|
|
|
/* собрать суперузлы всех CHAT-групп (node_type=4, не сам) — как md_dl_collect_supernodes */ |
|
|
|
|
uint64_t supers[10]; int nsup = 0; |
|
|
|
|
/* Собирает уникальных суперузлов (node_type=4, не сам) всех CHAT-групп. */ |
|
|
|
|
static int md_collect_supernodes(struct UTUN_INSTANCE* inst, uint64_t supers[10]) { |
|
|
|
|
int nsup = 0; |
|
|
|
|
struct ll_entry* gle = inst->topo_groups ? inst->topo_groups->group_list->head : NULL; |
|
|
|
|
while (gle) { |
|
|
|
|
struct TOPO_GROUP* g = (struct TOPO_GROUP*)gle; |
|
|
|
|
@ -1485,47 +1475,110 @@ void media_delivery_announce_media(struct UTUN_INSTANCE* inst, uint64_t group_id
|
|
|
|
|
g->channel_id, (unsigned long long)inst->node_id); |
|
|
|
|
sqlite3_stmt* st = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(inst->topo_sqlite_db, sql, -1, &st, NULL) == SQLITE_OK) { |
|
|
|
|
while (sqlite3_step(st) == SQLITE_ROW && nsup < 10) |
|
|
|
|
supers[nsup++] = (uint64_t)sqlite3_column_int64(st, 0); |
|
|
|
|
while (sqlite3_step(st) == SQLITE_ROW && nsup < 10) { |
|
|
|
|
uint64_t nid = (uint64_t)sqlite3_column_int64(st, 0); |
|
|
|
|
int dup = 0; |
|
|
|
|
for (int i = 0; i < nsup; i++) if (supers[i] == nid) { dup = 1; break; } |
|
|
|
|
if (!dup) supers[nsup++] = nid; |
|
|
|
|
} |
|
|
|
|
sqlite3_finalize(st); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
gle = gle->next; |
|
|
|
|
} |
|
|
|
|
return nsup; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void media_delivery_send_have_block(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst_node_id, |
|
|
|
|
const uint8_t* media_id, const uint8_t* block_id, uint32_t chunk) { |
|
|
|
|
if (!inst || !media_id || !block_id) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: send_have_block invalid args inst=%p media=%p block=%p", |
|
|
|
|
MD_ID, (void*)inst, (void*)media_id, (void*)block_id); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
struct media_pkt_have_block hb; |
|
|
|
|
memset(&hb, 0, sizeof(hb)); |
|
|
|
|
hb.subcmd = MEDIA_SUBCMD_HAVE_BLOCK; |
|
|
|
|
hb.group_id = group_id; |
|
|
|
|
memcpy(hb.media_id, media_id, 16); |
|
|
|
|
memcpy(hb.block_id, block_id, 16); |
|
|
|
|
hb.chunk = chunk; |
|
|
|
|
hb.timestamp = (int64_t)time(NULL); |
|
|
|
|
|
|
|
|
|
uint8_t smsg[64]; size_t soff = 0; |
|
|
|
|
memcpy(smsg + soff, hb.block_id, 16); soff += 16; |
|
|
|
|
memcpy(smsg + soff, &hb.chunk, 4); soff += 4; |
|
|
|
|
memcpy(smsg + soff, &hb.timestamp, 8); soff += 8; |
|
|
|
|
uint64_t self = inst->node_id; memcpy(smsg + soff, &self, 8); soff += 8; |
|
|
|
|
if (sc_ed25519_sign(inst->my_ed25519_privkey, smsg, soff, hb.node_sign) != SC_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: Ed25519 sign failed for HAVE_BLOCK", MD_ID); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
md_send(inst, group_id, dst_node_id, (const uint8_t*)&hb, sizeof(hb)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void media_delivery_announce_media(struct UTUN_INSTANCE* inst, uint64_t group_id, |
|
|
|
|
const uint8_t* media_id, const uint8_t* block_ids, |
|
|
|
|
int num_blocks) { |
|
|
|
|
if (!inst || !media_id || !block_ids || num_blocks <= 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: announce invalid args inst=%p media=%p blocks=%p n=%d", |
|
|
|
|
MD_ID, (void*)inst, (void*)media_id, (void*)block_ids, num_blocks); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
struct media_delivery_ctx* md = &inst->md; |
|
|
|
|
if (!md->initialized) return; |
|
|
|
|
|
|
|
|
|
uint64_t supers[10]; int nsup = md_collect_supernodes(inst, supers); |
|
|
|
|
if (nsup == 0) { |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "%s: announce — no supernodes for group 0x%016llx", |
|
|
|
|
MD_ID, (unsigned long long)group_id); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int64_t ts = (int64_t)time(NULL); |
|
|
|
|
for (int s = 0; s < nsup; s++) { |
|
|
|
|
for (int n = 0; n < num_blocks; n++) { |
|
|
|
|
struct media_pkt_have_block hb; |
|
|
|
|
memset(&hb, 0, sizeof(hb)); |
|
|
|
|
hb.subcmd = MEDIA_SUBCMD_HAVE_BLOCK; |
|
|
|
|
hb.group_id = group_id; |
|
|
|
|
memcpy(hb.media_id, media_id, 16); |
|
|
|
|
memcpy(hb.block_id, block_ids + (size_t)n * 16, 16); |
|
|
|
|
hb.chunk = (uint32_t)n; |
|
|
|
|
hb.timestamp = ts; |
|
|
|
|
|
|
|
|
|
uint8_t smsg[64]; size_t soff = 0; |
|
|
|
|
memcpy(smsg + soff, hb.block_id, 16); soff += 16; |
|
|
|
|
memcpy(smsg + soff, &hb.chunk, 4); soff += 4; |
|
|
|
|
memcpy(smsg + soff, &hb.timestamp, 8); soff += 8; |
|
|
|
|
uint64_t self = inst->node_id; memcpy(smsg + soff, &self, 8); soff += 8; |
|
|
|
|
if (sc_ed25519_sign(inst->my_ed25519_privkey, smsg, soff, hb.node_sign) != SC_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: announce Ed25519 sign failed block=%d", MD_ID, n); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
md_send(inst, group_id, supers[s], (const uint8_t*)&hb, sizeof(hb)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for (int s = 0; s < nsup; s++) |
|
|
|
|
for (int n = 0; n < num_blocks; n++) |
|
|
|
|
media_delivery_send_have_block(inst, group_id, supers[s], media_id, |
|
|
|
|
block_ids + (size_t)n * 16, (uint32_t)n); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "%s: announce media=%02x%02x... blocks=%d supers=%d", |
|
|
|
|
MD_ID, media_id[0], media_id[1], num_blocks, nsup); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void media_delivery_announce_local_blocks(struct UTUN_INSTANCE* inst) { |
|
|
|
|
if (!inst) return; |
|
|
|
|
struct media_delivery_ctx* md = &inst->md; |
|
|
|
|
if (!md->initialized) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "%s: announce_local_blocks — media_delivery not initialized", MD_ID); return; } |
|
|
|
|
sqlite3* db = inst->topo_sqlite_db; |
|
|
|
|
if (!db) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "%s: announce_local_blocks — no DB", MD_ID); return; } |
|
|
|
|
|
|
|
|
|
uint64_t supers[10]; int nsup = md_collect_supernodes(inst, supers); |
|
|
|
|
if (nsup == 0) { DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "%s: announce_local_blocks — no supernodes", MD_ID); return; } |
|
|
|
|
|
|
|
|
|
sqlite3_stmt* st = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(db, "SELECT media_id, block_id, chunk, chat_id FROM media_files WHERE node_id=?", |
|
|
|
|
-1, &st, NULL) != SQLITE_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: announce_local_blocks prepare failed: %s", MD_ID, sqlite3_errmsg(db)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
sqlite3_bind_int64(st, 1, (sqlite3_int64)inst->node_id); |
|
|
|
|
|
|
|
|
|
int announced = 0; |
|
|
|
|
while (sqlite3_step(st) == SQLITE_ROW) { |
|
|
|
|
const uint8_t* media_id = (const uint8_t*)sqlite3_column_blob(st, 0); |
|
|
|
|
const uint8_t* block_id = (const uint8_t*)sqlite3_column_blob(st, 1); |
|
|
|
|
uint32_t chunk = (uint32_t)sqlite3_column_int(st, 2); |
|
|
|
|
const char* chat_id = (const char*)sqlite3_column_text(st, 3); |
|
|
|
|
if (!media_id || !block_id || !chat_id || !chat_id[0]) continue; |
|
|
|
|
uint64_t gid = strtoull(chat_id, NULL, 10); |
|
|
|
|
if (gid == 0) continue; |
|
|
|
|
for (int s = 0; s < nsup; s++) |
|
|
|
|
media_delivery_send_have_block(inst, gid, supers[s], media_id, block_id, chunk); |
|
|
|
|
announced++; |
|
|
|
|
} |
|
|
|
|
sqlite3_finalize(st); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "%s: announce_local_blocks done, blocks=%d supers=%d", |
|
|
|
|
MD_ID, announced, nsup); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void media_delivery_set_supernode(struct UTUN_INSTANCE* inst, int is_supernode) { |
|
|
|
|
if (!inst) return; |
|
|
|
|
struct media_delivery_ctx* md = &inst->md; |
|
|
|
|
|