Coverage Report

Created: 2025-10-08 19:34

/work/auto_tests/dht_nodes_response_api_test.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * This autotest creates a small local DHT and makes sure that each peer can crawl
3
 * the entire DHT using the DHT nodes request/response api functions.
4
 */
5
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
10
#include "../toxcore/tox.h"
11
#include "../toxcore/tox_private.h"
12
#include "auto_test_support.h"
13
#include "check_compat.h"
14
15
28.5k
#define NUM_TOXES 30
16
// Maximum number of iterations to wait for all nodes to be crawled. 5 should
17
// be enough. We pick 10 in case things are slow. This makes the test take
18
// less time in case it completely fails, so we can retry it.
19
4
#define MAX_ITERATIONS 10
20
21
typedef struct Dht_Node {
22
    uint8_t  public_key[TOX_DHT_NODE_PUBLIC_KEY_SIZE];
23
    char     ip[TOX_DHT_NODE_IP_STRING_SIZE];
24
    uint16_t port;
25
} Dht_Node;
26
27
typedef struct State {
28
    Dht_Node **nodes;
29
    size_t num_nodes;
30
    uint8_t **public_key_list;
31
} State;
32
33
static void free_nodes(Dht_Node **nodes, size_t num_nodes)
34
30
{
35
930
    for (size_t i = 0; i < num_nodes; ++i) {
36
900
        free(nodes[i]);
37
900
    }
38
39
30
    free(nodes);
40
30
}
41
42
static bool node_crawled(Dht_Node **nodes, size_t num_nodes, const uint8_t *public_key)
43
32.7k
{
44
484k
    for (size_t i = 0; i < num_nodes; ++i) {
45
483k
        if (memcmp(nodes[i]->public_key, public_key, TOX_DHT_NODE_PUBLIC_KEY_SIZE) == 0) {
46
31.8k
            return true;
47
31.8k
        }
48
483k
    }
49
50
900
    return false;
51
32.7k
}
52
53
static bool all_nodes_crawled(const AutoTox *autotoxes, uint32_t num_toxes, uint8_t **public_key_list)
54
4
{
55
34
    for (uint32_t i = 0; i < num_toxes; ++i) {
56
33
        const State *state = (const State *)autotoxes[i].state;
57
58
        // make sure each peer has crawled the correct number of nodes
59
33
        if (state->num_nodes < num_toxes) {
60
3
            return false;
61
3
        }
62
33
    }
63
64
31
    for (uint32_t i = 0; i < num_toxes; ++i) {
65
30
        const State *state = (const State *)autotoxes[i].state;
66
67
        // make sure each peer has the full list of public keys
68
930
        for (uint32_t j = 0; j < num_toxes; ++j) {
69
900
            if (!node_crawled(state->nodes, state->num_nodes, public_key_list[j])) {
70
0
                return false;
71
0
            }
72
900
        }
73
30
    }
74
75
1
    return true;
76
1
}
77
78
static void nodes_response_cb(const Tox_Event_Dht_Nodes_Response *event, void *user_data)
79
31.8k
{
80
31.8k
    ck_assert(user_data != nullptr);
81
82
31.8k
    AutoTox *autotox = (AutoTox *)user_data;
83
31.8k
    State *state = (State *)autotox->state;
84
85
31.8k
    const uint8_t *public_key = tox_event_dht_nodes_response_get_public_key(event);
86
31.8k
    const char *ip = (const char *)tox_event_dht_nodes_response_get_ip(event);
87
31.8k
    const uint16_t port = tox_event_dht_nodes_response_get_port(event);
88
89
31.8k
    if (node_crawled(state->nodes, state->num_nodes, public_key)) {
90
30.9k
        return;
91
30.9k
    }
92
93
900
    ck_assert(state->num_nodes < NUM_TOXES);
94
95
900
    Dht_Node *node = (Dht_Node *)calloc(1, sizeof(Dht_Node));
96
900
    ck_assert(node != nullptr);
97
98
900
    memcpy(node->public_key, public_key, TOX_DHT_NODE_PUBLIC_KEY_SIZE);
99
900
    snprintf(node->ip, sizeof(node->ip), "%s", ip);
100
900
    node->port = port;
101
102
900
    state->nodes[state->num_nodes] = node;
103
900
    ++state->num_nodes;
104
105
    // ask new node to give us their close nodes to every public key
106
27.9k
    for (size_t i = 0; i < NUM_TOXES; ++i) {
107
27.0k
        tox_dht_send_nodes_request(autotox->tox, public_key, ip, port, state->public_key_list[i], nullptr);
108
27.0k
    }
109
900
}
110
111
static void test_dht_nodes_request(AutoTox *autotoxes)
112
1
{
113
1
    ck_assert(NUM_TOXES >= 2);
114
115
1
    uint8_t **public_key_list = (uint8_t **)calloc(NUM_TOXES, sizeof(uint8_t *));
116
1
    ck_assert(public_key_list != nullptr);
117
118
31
    for (size_t i = 0; i < NUM_TOXES; ++i) {
119
30
        State *state = (State *)autotoxes[i].state;
120
121
30
        state->nodes = (Dht_Node **)calloc(NUM_TOXES, sizeof(Dht_Node *));
122
30
        ck_assert(state->nodes != nullptr);
123
124
30
        state->num_nodes = 0;
125
30
        state->public_key_list = public_key_list;
126
127
30
        public_key_list[i] = (uint8_t *)malloc(sizeof(uint8_t) * TOX_PUBLIC_KEY_SIZE);
128
30
        ck_assert(public_key_list[i] != nullptr);
129
130
30
        tox_self_get_dht_id(autotoxes[i].tox, public_key_list[i]);
131
30
        tox_events_callback_dht_nodes_response(autotoxes[i].dispatch, nodes_response_cb);
132
133
30
        printf("Peer %zu dht closenode count total/announce-capable: %d/%d\n",
134
30
               i,
135
30
               tox_dht_get_num_closelist(autotoxes[i].tox),
136
30
               tox_dht_get_num_closelist_announce_capable(autotoxes[i].tox));
137
30
    }
138
139
1
    bool success = false;
140
4
    for (size_t i = 0; i < MAX_ITERATIONS; ++i) {
141
4
        if (all_nodes_crawled(autotoxes, NUM_TOXES, public_key_list)) {
142
1
            success = true;
143
1
            break;
144
1
        }
145
3
        iterate_all_wait(autotoxes, NUM_TOXES, ITERATION_INTERVAL);
146
3
    }
147
1
    ck_assert_msg(success, "Failed to crawl all nodes within %d iterations", MAX_ITERATIONS);
148
149
31
    for (size_t i = 0; i < NUM_TOXES; ++i) {
150
30
        State *state = (State *)autotoxes[i].state;
151
30
        free_nodes(state->nodes, state->num_nodes);
152
30
        free(public_key_list[i]);
153
30
    }
154
155
1
    free(public_key_list);
156
1
}
157
158
int main(void)
159
545
{
160
545
    setvbuf(stdout, nullptr, _IONBF, 0);
161
162
545
    Run_Auto_Options options = default_run_auto_options();
163
545
    options.graph = GRAPH_LINEAR;
164
165
545
    run_auto_test(nullptr, NUM_TOXES, test_dht_nodes_request, sizeof(State), &options);
166
167
545
    return 0;
168
545
}
169
170
#undef NUM_TOXES