Browse Source

Bound and safely serialize PM conversation snapshots

master
evgeny 1 day ago
parent
commit
d9eee4e520
  1. 39
      src/dm/dm_core.c

39
src/dm/dm_core.c

@ -852,12 +852,13 @@ static void json_escape(const char* src, char* dst, size_t dst_sz) {
int dm_list_conversations_json(struct UTUN_INSTANCE* inst, char* buf, size_t buf_size, size_t* out_len) {
struct dm_state* dm = dm_of(inst);
if (!buf || !out_len || !dm || !dm->db) return -1;
int off = 0;
off += snprintf(buf + off, buf_size - (size_t)off, "[");
*out_len = 0;
struct strbuf json = strbuf_new();
int failed = strbuf_addf(&json, "[") < 0;
sqlite3_stmt* st = NULL;
if (sqlite3_prepare_v2(dm->db,
"SELECT conv_id, peer_node_id, COALESCE(peer_name,''), last_ts, last_out_seq, last_in_seq"
" FROM dm_conversations ORDER BY last_ts DESC",
" FROM dm_conversations ORDER BY last_ts DESC LIMIT 200",
-1, &st, NULL) == SQLITE_OK) {
int first = 1;
while (sqlite3_step(st) == SQLITE_ROW) {
@ -875,18 +876,26 @@ int dm_list_conversations_json(struct UTUN_INSTANCE* inst, char* buf, size_t buf
}
char esc_name[512];
json_escape(name ? name : "", esc_name, sizeof(esc_name));
off += snprintf(buf + off, buf_size - (size_t)off,
if (strbuf_addf(&json,
"%s{\"conv_id\":\"%s\",\"peer_node_id\":%llu,\"peer_name\":\"%s\","
"\"last_ts\":%llu,\"out_seq\":%llu,\"in_seq\":%llu}",
first ? "" : ",", conv_id, (unsigned long long)peer,
esc_name, (unsigned long long)last_ts,
(unsigned long long)out_seq, (unsigned long long)in_seq);
(unsigned long long)out_seq, (unsigned long long)in_seq) < 0) { failed = 1; break; }
first = 0;
}
}
if (sqlite3_errcode(dm->db) != SQLITE_DONE && sqlite3_errcode(dm->db) != SQLITE_OK) failed = 1;
} else failed = 1;
if (st) sqlite3_finalize(st);
off += snprintf(buf + off, buf_size - (size_t)off, "]");
*out_len = (size_t)off;
if (strbuf_addf(&json, "]") < 0) failed = 1;
if (failed || json.len >= buf_size) {
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: conversations snapshot failed bytes=%zu capacity=%zu sql=%s", DM_ID,
json.len, buf_size, sqlite3_errmsg(dm->db));
strbuf_free(&json); return -1;
}
memcpy(buf, strbuf_str(&json), json.len + 1);
*out_len = json.len;
strbuf_free(&json);
return 0;
}
@ -1017,3 +1026,17 @@ void dm_messages_trampoline(void* arg) {
chat_event_post(inst, CHAT_EVT_DM_MESSAGES, evt, (int)(1 + cl + len));
u_free(evt);
}
void dm_conversations_trampoline(void* arg) {
struct dm_conversations_req* req = arg;
if (!req) return;
struct UTUN_INSTANCE* inst = req->inst;
u_free(req);
if (!dm_of(inst)) { DEBUG_WARN(DEBUG_CATEGORY_DM, "%s: conversations snapshot after stop", DM_ID); return; }
size_t cap = 256 * 1024, len = 0;
char* json = u_malloc(cap);
if (!json) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: conversations allocation failed", DM_ID); return; }
if (!dm_list_conversations_json(inst, json, cap, &len))
chat_event_post(inst, CHAT_EVT_DM_CONVERSATIONS, (const uint8_t*)json, (int)len);
u_free(json);
}

Loading…
Cancel
Save