Coverage Report

Created: 2024-01-26 01:52

/work/auto_tests/dht_getnodes_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 getnodes api functions.
4
 */
5
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <time.h>
10
11
#include "../toxcore/tox.h"
12
#include "../toxcore/tox_private.h"
13
#include "auto_test_support.h"
14
#include "check_compat.h"
15
16
28.7k
#define NUM_TOXES 30
17
18
typedef struct Dht_Node {
19
    uint8_t  public_key[TOX_DHT_NODE_PUBLIC_KEY_SIZE];
20
    char     ip[TOX_DHT_NODE_IP_STRING_SIZE];
21
    uint16_t port;
22
} Dht_Node;
23
24
typedef struct State {
25
    Dht_Node **nodes;
26
    size_t num_nodes;
27
    uint8_t **public_key_list;
28
} State;
29
30
static void free_nodes(Dht_Node **nodes, size_t num_nodes)
31
30
{
32
930
    for (size_t i = 0; i < num_nodes; ++i) {
33
900
        free(nodes[i]);
34
900
    }
35
36
30
    free(nodes);
37
30
}
38
39
static bool node_crawled(Dht_Node **nodes, size_t num_nodes, const uint8_t *public_key)
40
43.4k
{
41
653k
    for (size_t i = 0; i < num_nodes; ++i) {
42
652k
        if (memcmp(nodes[i]->public_key, public_key, TOX_DHT_NODE_PUBLIC_KEY_SIZE) == 0) {
43
42.5k
            return true;
44
42.5k
        }
45
652k
    }
46
47
900
    return false;
48
43.4k
}
49
50
static bool all_nodes_crawled(const AutoTox *autotoxes, uint32_t num_toxes, uint8_t **public_key_list)
51
5
{
52
64
    for (uint32_t i = 0; i < num_toxes; ++i) {
53
63
        const State *state = (const State *)autotoxes[i].state;
54
55
        // make sure each peer has crawled the correct number of nodes
56
63
        if (state->num_nodes < num_toxes) {
57
4
            return false;
58
4
        }
59
63
    }
60
61
31
    for (uint32_t i = 0; i < num_toxes; ++i) {
62
30
        const State *state = (const State *)autotoxes[i].state;
63
64
        // make sure each peer has the full list of public keys
65
930
        for (uint32_t j = 0; j < num_toxes; ++j) {
66
900
            if (!node_crawled(state->nodes, state->num_nodes, public_key_list[j])) {
67
0
                return false;
68
0
            }
69
900
        }
70
30
    }
71
72
1
    return true;
73
1
}
74
75
static void getnodes_response_cb(Tox *tox, const Tox_Event_Dht_Get_Nodes_Response *event, void *user_data)
76
42.5k
{
77
42.5k
    ck_assert(user_data != nullptr);
78
79
42.5k
    AutoTox *autotoxes = (AutoTox *)user_data;
80
42.5k
    State *state = (State *)autotoxes->state;
81
82
42.5k
    const uint8_t *public_key = tox_event_dht_get_nodes_response_get_public_key(event);
83
42.5k
    const char *ip = (const char *)tox_event_dht_get_nodes_response_get_ip(event);
84
42.5k
    const uint16_t port = tox_event_dht_get_nodes_response_get_port(event);
85
86
42.5k
    if (node_crawled(state->nodes, state->num_nodes, public_key)) {
87
41.6k
        return;
88
41.6k
    }
89
90
900
    ck_assert(state->num_nodes < NUM_TOXES);
91
92
900
    Dht_Node *node = (Dht_Node *)calloc(1, sizeof(Dht_Node));
93
900
    ck_assert(node != nullptr);
94
95
900
    memcpy(node->public_key, public_key, TOX_DHT_NODE_PUBLIC_KEY_SIZE);
96
900
    snprintf(node->ip, sizeof(node->ip), "%s", ip);
97
900
    node->port = port;
98
99
900
    state->nodes[state->num_nodes] = node;
100
900
    ++state->num_nodes;
101
102
    // ask new node to give us their close nodes to every public key
103
27.9k
    for (size_t i = 0; i < NUM_TOXES; ++i) {
104
27.0k
        tox_dht_get_nodes(tox, public_key, ip, port, state->public_key_list[i], nullptr);
105
27.0k
    }
106
900
}
107
108
static void test_dht_getnodes(AutoTox *autotoxes)
109
1
{
110
1
    ck_assert(NUM_TOXES >= 2);
111
112
1
    uint8_t **public_key_list = (uint8_t **)calloc(NUM_TOXES, sizeof(uint8_t *));
113
1
    ck_assert(public_key_list != nullptr);
114
115
31
    for (size_t i = 0; i < NUM_TOXES; ++i) {
116
30
        State *state = (State *)autotoxes[i].state;
117
118
30
        state->nodes = (Dht_Node **)calloc(NUM_TOXES, sizeof(Dht_Node *));
119
30
        ck_assert(state->nodes != nullptr);
120
121
30
        state->num_nodes = 0;
122
30
        state->public_key_list = public_key_list;
123
124
30
        public_key_list[i] = (uint8_t *)malloc(sizeof(uint8_t) * TOX_PUBLIC_KEY_SIZE);
125
30
        ck_assert(public_key_list[i] != nullptr);
126
127
30
        tox_self_get_dht_id(autotoxes[i].tox, public_key_list[i]);
128
30
        tox_events_callback_dht_get_nodes_response(autotoxes[i].dispatch, getnodes_response_cb);
129
130
30
        printf("Peer %zu dht closenode count total/announce-capable: %d/%d\n",
131
30
            i,
132
30
            tox_dht_get_num_closelist(autotoxes[i].tox),
133
30
            tox_dht_get_num_closelist_announce_capable(autotoxes[i].tox)
134
30
        );
135
30
    }
136
137
5
    while (!all_nodes_crawled(autotoxes, NUM_TOXES, public_key_list)) {
138
4
        iterate_all_wait(autotoxes, NUM_TOXES, ITERATION_INTERVAL);
139
4
    }
140
141
31
    for (size_t i = 0; i < NUM_TOXES; ++i) {
142
30
        State *state = (State *)autotoxes[i].state;
143
30
        free_nodes(state->nodes, state->num_nodes);
144
30
        free(public_key_list[i]);
145
30
    }
146
147
1
    free(public_key_list);
148
1
}
149
150
int main(void)
151
721
{
152
721
    setvbuf(stdout, nullptr, _IONBF, 0);
153
154
721
    Run_Auto_Options options = default_run_auto_options();
155
721
    options.graph = GRAPH_LINEAR;
156
157
721
    run_auto_test(nullptr, NUM_TOXES, test_dht_getnodes, sizeof(State), &options);
158
159
721
    return 0;
160
721
}
161
162
#undef NUM_TOXES