|
|
|
|
@ -278,6 +278,19 @@ static int protocol_checks(struct UTUN_INSTANCE* A, struct UTUN_INSTANCE* B) {
|
|
|
|
|
dm_accept_receipt(A, receipt) == 0 || outbox_count(A) != 1) return -1; |
|
|
|
|
receipt[DM_RECEIPT_SIZE - 1] ^= 1; |
|
|
|
|
if (dm_accept_receipt(A, receipt) == 0 || outbox_count(A) != 1) return -1; |
|
|
|
|
/* Ошибка durable outbox откатывает одновременно историю и seq отправителя. */ |
|
|
|
|
if (sqlite3_exec(A->topo_sqlite_db, "CREATE TEMP TRIGGER dm_outbox_fail BEFORE INSERT ON dm_outbox" |
|
|
|
|
" BEGIN SELECT RAISE(ABORT,'test outbox failure'); END", NULL, NULL, NULL) != SQLITE_OK) return -1; |
|
|
|
|
if (dm_send(A, g_sh.conv_id, "text", (const uint8_t*)"must-not-commit", 15) == 0 || outbox_count(A) != 1) return -1; |
|
|
|
|
if (sqlite3_exec(A->topo_sqlite_db, "DROP TRIGGER dm_outbox_fail", NULL, NULL, NULL) != SQLITE_OK || |
|
|
|
|
dm_msg_has(A, "must-not-commit")) return -1; |
|
|
|
|
sqlite3_stmt* st = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(A->topo_sqlite_db, "SELECT last_out_seq FROM dm_conversations WHERE conv_id=?", -1, &st, NULL) != SQLITE_OK) |
|
|
|
|
return -1; |
|
|
|
|
sqlite3_bind_text(st, 1, g_sh.conv_id, -1, SQLITE_STATIC); |
|
|
|
|
int seq_unchanged = sqlite3_step(st) == SQLITE_ROW && sqlite3_column_int64(st, 0) == 1; |
|
|
|
|
sqlite3_finalize(st); |
|
|
|
|
if (!seq_unchanged) return -1; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DM, "protocol checks passed: reorder, dedup, tamper, DB rollback, exact receipt"); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|