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;
25 static void foo_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
29 if(!strcmp(node->name, "bar")) {
31 set_sync_flag(&bar_connected, true);
33 set_sync_flag(&bar_disconnected, true);
38 static void baz_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
42 if(!strcmp(node->name, "bar")) {
44 set_sync_flag(&baz_connected, true);
49 static void bar_blacklisted_cb(meshlink_handle_t *mesh, meshlink_node_t *node) {
52 if(!strcmp(node->name, "foo")) {
53 set_sync_flag(&bar_blacklisted, true);
58 init_sync_flag(&bar_connected);
59 init_sync_flag(&bar_disconnected);
60 init_sync_flag(&baz_connected);
62 meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
64 // Create three instances.
66 const char *name[3] = {"foo", "bar", "baz"};
67 meshlink_handle_t *mesh[3];
70 for(int i = 0; i < 3; i++) {
72 assert(asprintf(&path, "blacklist_conf.%d", i) != -1 && path);
74 assert(meshlink_destroy(path));
75 mesh[i] = meshlink_open(path, name[i], "blacklist", DEV_CLASS_BACKBONE);
79 assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
81 data[i] = meshlink_export(mesh[i]);
84 // Enable default blacklist on all nodes.
85 meshlink_set_default_blacklist(mesh[i], true);
88 // The first node knows the two other nodes.
90 for(int i = 1; i < 3; i++) {
91 assert(meshlink_import(mesh[i], data[0]));
92 assert(meshlink_import(mesh[0], data[i]));
94 assert(meshlink_get_node(mesh[i], name[0]));
95 assert(meshlink_get_node(mesh[0], name[i]));
99 for(int i = 0; i < 3; i++) {
103 // Second and third node should not know each other yet.
105 assert(!meshlink_get_node(mesh[1], name[2]));
106 assert(!meshlink_get_node(mesh[2], name[1]));
108 // Check default blacklist status
110 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_self(mesh[0])));
111 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
112 assert(meshlink_get_node_blacklisted(mesh[1], meshlink_get_node(mesh[1], name[2])));
113 assert(meshlink_get_node_blacklisted(mesh[2], meshlink_get_node(mesh[2], name[1])));
115 // Generate an invitation for a node that is about to be blacklisted
117 char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
121 // Whitelisting and blacklisting by name should work.
123 assert(meshlink_whitelist_by_name(mesh[0], "quux"));
124 assert(meshlink_blacklist_by_name(mesh[0], "xyzzy"));
125 assert(meshlink_get_node(mesh[0], "quux"));
126 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux")));
127 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "xyzzy")));
129 meshlink_node_t **nodes = NULL;
131 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
133 assert(!strcmp(nodes[0]->name, "xyzzy"));
135 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
137 assert(!strcmp(nodes[0]->name, "bar"));
138 assert(!strcmp(nodes[1]->name, "baz"));
139 assert(!strcmp(nodes[2]->name, "foo"));
140 assert(!strcmp(nodes[3]->name, "quux"));
144 // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
146 assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
148 DIR *dir = opendir("blacklist_conf.0/current/invitations");
152 while((ent = readdir(dir))) {
153 assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."));
158 // Since these nodes now exist we should be able to forget them.
160 assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
161 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
165 meshlink_set_node_status_cb(mesh[0], foo_status_cb);
166 meshlink_set_node_status_cb(mesh[2], baz_status_cb);
168 for(int i = 0; i < 3; i++) {
169 assert(meshlink_start(mesh[i]));
172 // Wait for them to connect.
174 assert(wait_sync_flag(&bar_connected, 5));
178 meshlink_set_blacklisted_cb(mesh[1], bar_blacklisted_cb);
180 set_sync_flag(&bar_disconnected, false);
181 assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
182 assert(wait_sync_flag(&bar_disconnected, 5));
183 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
185 assert(wait_sync_flag(&bar_blacklisted, 10));
189 set_sync_flag(&bar_connected, false);
190 assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
191 assert(wait_sync_flag(&bar_connected, 15));
192 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
194 // Bar should not connect to baz
196 assert(wait_sync_flag(&baz_connected, 5) == false);
198 // But it should know about baz by now
200 meshlink_node_t *bar = meshlink_get_node(mesh[2], "bar");
201 meshlink_node_t *baz = meshlink_get_node(mesh[1], "baz");
205 // Have bar and baz whitelist each other
207 assert(meshlink_whitelist(mesh[1], baz));
208 assert(meshlink_whitelist(mesh[2], bar));
209 assert(!meshlink_get_node_blacklisted(mesh[1], baz));
210 assert(!meshlink_get_node_blacklisted(mesh[2], bar));
212 // They should connect to each other
214 assert(wait_sync_flag(&baz_connected, 15));
216 // Trying to forget an active node should fail.
218 assert(!meshlink_forget_node(mesh[1], baz));
220 // We need to re-acquire the handle to baz
222 baz = meshlink_get_node(mesh[1], "baz");
227 for(int i = 0; i < 3; i++) {
228 meshlink_stop(mesh[i]);
231 // Forgetting a node should work now.
233 assert(meshlink_forget_node(mesh[1], baz));
237 for(int i = 0; i < 3; i++) {
238 meshlink_close(mesh[i]);
241 // Check that foo has a config file for xyzzy but not quux
242 assert(access("blacklist_conf.0/current/hosts/xyzzy", F_OK) == 0);
243 assert(access("blacklist_conf.0/current/hosts/quux", F_OK) != 0 && errno == ENOENT);
245 // Check that bar has no config file for baz
246 assert(access("blacklist_conf.2/current/hosts/bar", F_OK) == 0);
247 assert(access("blacklist_conf.1/current/hosts/baz", F_OK) != 0 && errno == ENOENT);
249 // Check that we remember xyzzy but not quux after reopening the mesh
250 mesh[0] = meshlink_open("blacklist_conf.0", "foo", "blacklist", DEV_CLASS_BACKBONE);
252 assert(meshlink_get_node(mesh[0], "xyzzy"));
253 assert(!meshlink_get_node(mesh[0], "quux"));
255 meshlink_close(mesh[0]);