]> git.meshlink.io Git - meshlink/blob - test/blacklist.c
Use a key/value store with configurable storage callbacks.
[meshlink] / test / blacklist.c
1 #define _GNU_SOURCE
2
3 #ifdef NDEBUG
4 #undef NDEBUG
5 #endif
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <sys/time.h>
14 #include <dirent.h>
15
16 #include "meshlink.h"
17 #include "devtools.h"
18 #include "utils.h"
19
20 static struct sync_flag bar_connected;
21 static struct sync_flag bar_disconnected;
22 static struct sync_flag bar_blacklisted;
23 static struct sync_flag baz_connected;
24
25 static void foo_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
26         (void)mesh;
27         (void)reachable;
28
29         if(!strcmp(node->name, "bar")) {
30                 if(reachable) {
31                         set_sync_flag(&bar_connected, true);
32                 } else {
33                         set_sync_flag(&bar_disconnected, true);
34                 }
35         }
36 }
37
38 static void baz_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
39         (void)mesh;
40         (void)reachable;
41
42         if(!strcmp(node->name, "bar")) {
43                 if(reachable) {
44                         set_sync_flag(&baz_connected, true);
45                 }
46         }
47 }
48
49 static void bar_blacklisted_cb(meshlink_handle_t *mesh, meshlink_node_t *node) {
50         (void)mesh;
51
52         if(!strcmp(node->name, "foo")) {
53                 set_sync_flag(&bar_blacklisted, true);
54         }
55 }
56
57 int main(void) {
58         init_sync_flag(&bar_connected);
59         init_sync_flag(&bar_disconnected);
60         init_sync_flag(&bar_blacklisted);
61         init_sync_flag(&baz_connected);
62
63         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
64
65         // Create three instances.
66
67         const char *name[3] = {"foo", "bar", "baz"};
68         meshlink_handle_t *mesh[3];
69         char *data[3];
70
71         for(int i = 0; i < 3; i++) {
72                 char *path = NULL;
73                 assert(asprintf(&path, "blacklist_conf.%d", i) != -1 && path);
74
75                 assert(meshlink_destroy(path));
76                 mesh[i] = meshlink_open(path, name[i], "blacklist", DEV_CLASS_BACKBONE);
77                 assert(mesh[i]);
78                 free(path);
79
80                 assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
81
82                 data[i] = meshlink_export(mesh[i]);
83                 assert(data[i]);
84
85                 // Enable default blacklist on all nodes.
86                 meshlink_set_default_blacklist(mesh[i], true);
87         }
88
89         // The first node knows the two other nodes.
90
91         for(int i = 1; i < 3; i++) {
92                 assert(meshlink_import(mesh[i], data[0]));
93                 assert(meshlink_import(mesh[0], data[i]));
94
95                 assert(meshlink_get_node(mesh[i], name[0]));
96                 assert(meshlink_get_node(mesh[0], name[i]));
97
98         }
99
100         for(int i = 0; i < 3; i++) {
101                 free(data[i]);
102         }
103
104         // Second and third node should not know each other yet.
105
106         assert(!meshlink_get_node(mesh[1], name[2]));
107         assert(!meshlink_get_node(mesh[2], name[1]));
108
109         // Check default blacklist status
110
111         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_self(mesh[0])));
112         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
113         assert(meshlink_get_node_blacklisted(mesh[1], meshlink_get_node(mesh[1], name[2])));
114         assert(meshlink_get_node_blacklisted(mesh[2], meshlink_get_node(mesh[2], name[1])));
115
116         // Generate an invitation for a node that is about to be blacklisted
117
118         char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
119         assert(invitation);
120         free(invitation);
121
122         // Whitelisting and blacklisting by name should work.
123
124         assert(meshlink_whitelist_by_name(mesh[0], "quux"));
125         assert(meshlink_blacklist_by_name(mesh[0], "xyzzy"));
126         assert(meshlink_get_node(mesh[0], "quux"));
127         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux")));
128         assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "xyzzy")));
129
130         meshlink_node_t **nodes = NULL;
131         size_t nnodes = 0;
132         nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
133         assert(nnodes == 1);
134         assert(!strcmp(nodes[0]->name, "xyzzy"));
135
136         nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
137         assert(nnodes == 4);
138         assert(!strcmp(nodes[0]->name, "bar"));
139         assert(!strcmp(nodes[1]->name, "baz"));
140         assert(!strcmp(nodes[2]->name, "foo"));
141         assert(!strcmp(nodes[3]->name, "quux"));
142
143         free(nodes);
144
145         // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
146
147         assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
148
149         DIR *dir = opendir("blacklist_conf.0");
150         assert(dir);
151         struct dirent *ent;
152
153         while((ent = readdir(dir))) {
154                 size_t len = strlen(ent->d_name);
155                 assert(len < 4 || strcmp(ent->d_name + len - 4, ".inv") != 0);
156         }
157
158         closedir(dir);
159
160         // Since these nodes now exist we should be able to forget them.
161
162         assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
163         assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
164
165         // Start the nodes.
166
167         meshlink_set_node_status_cb(mesh[0], foo_status_cb);
168         meshlink_set_node_status_cb(mesh[2], baz_status_cb);
169
170         for(int i = 0; i < 3; i++) {
171                 assert(meshlink_start(mesh[i]));
172         }
173
174         // Wait for them to connect.
175
176         assert(wait_sync_flag(&bar_connected, 5));
177
178         // Blacklist bar
179
180         meshlink_set_blacklisted_cb(mesh[1], bar_blacklisted_cb);
181
182         set_sync_flag(&bar_disconnected, false);
183         assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
184         assert(wait_sync_flag(&bar_disconnected, 5));
185         assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
186
187         assert(wait_sync_flag(&bar_blacklisted, 10));
188
189         // Whitelist bar
190
191         set_sync_flag(&bar_connected, false);
192         assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
193         assert(wait_sync_flag(&bar_connected, 15));
194         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
195
196         // Bar should not connect to baz
197
198         assert(wait_sync_flag(&baz_connected, 5) == false);
199
200         // But it should know about baz by now
201
202         meshlink_node_t *bar = meshlink_get_node(mesh[2], "bar");
203         meshlink_node_t *baz = meshlink_get_node(mesh[1], "baz");
204         assert(bar);
205         assert(baz);
206
207         // Have bar and baz whitelist each other
208
209         assert(meshlink_whitelist(mesh[1], baz));
210         assert(meshlink_whitelist(mesh[2], bar));
211         assert(!meshlink_get_node_blacklisted(mesh[1], baz));
212         assert(!meshlink_get_node_blacklisted(mesh[2], bar));
213
214         // They should connect to each other
215
216         assert(wait_sync_flag(&baz_connected, 15));
217
218         // Trying to forget an active node should fail.
219
220         assert(!meshlink_forget_node(mesh[1], baz));
221
222         // We need to re-acquire the handle to baz
223
224         baz = meshlink_get_node(mesh[1], "baz");
225         assert(baz);
226
227         // Stop the mesh.
228
229         for(int i = 0; i < 3; i++) {
230                 meshlink_stop(mesh[i]);
231         }
232
233         // Forgetting a node should work now.
234
235         assert(meshlink_forget_node(mesh[1], baz));
236
237         // Clean up.
238
239         for(int i = 0; i < 3; i++) {
240                 meshlink_close(mesh[i]);
241         }
242
243         // Check that foo has a config file for xyzzy but not quux
244         assert(access("blacklist_conf.0/xyzzy", F_OK) == 0);
245         assert(access("blacklist_conf.0/quux", F_OK) != 0 && errno == ENOENT);
246
247         // Check that bar has no config file for baz
248         assert(access("blacklist_conf.2/bar", F_OK) == 0);
249         assert(access("blacklist_conf.1/baz", F_OK) != 0 && errno == ENOENT);
250
251         // Check that we remember xyzzy but not quux after reopening the mesh
252         mesh[0] = meshlink_open("blacklist_conf.0", "foo", "blacklist", DEV_CLASS_BACKBONE);
253         assert(mesh[0]);
254         assert(meshlink_get_node(mesh[0], "xyzzy"));
255         assert(!meshlink_get_node(mesh[0], "quux"));
256
257         meshlink_close(mesh[0]);
258 }