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