20 static struct sync_flag bar_connected;
21 static struct sync_flag bar_disconnected;
22 static struct sync_flag baz_connected;
24 static void foo_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
28 if(!strcmp(node->name, "bar")) {
30 set_sync_flag(&bar_connected, true);
32 set_sync_flag(&bar_disconnected, true);
37 static void baz_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
41 if(!strcmp(node->name, "bar")) {
43 set_sync_flag(&baz_connected, true);
49 init_sync_flag(&bar_connected);
50 init_sync_flag(&bar_disconnected);
51 init_sync_flag(&baz_connected);
53 meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
55 // Create three instances.
57 const char *name[3] = {"foo", "bar", "baz"};
58 meshlink_handle_t *mesh[3];
61 for(int i = 0; i < 3; i++) {
63 assert(asprintf(&path, "blacklist_conf.%d", i) != -1 && path);
65 assert(meshlink_destroy(path));
66 mesh[i] = meshlink_open(path, name[i], "blacklist", DEV_CLASS_BACKBONE);
70 assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
72 data[i] = meshlink_export(mesh[i]);
75 // Enable default blacklist on all nodes.
76 meshlink_set_default_blacklist(mesh[i], true);
79 // The first node knows the two other nodes.
81 for(int i = 1; i < 3; i++) {
82 assert(meshlink_import(mesh[i], data[0]));
83 assert(meshlink_import(mesh[0], data[i]));
85 assert(meshlink_get_node(mesh[i], name[0]));
86 assert(meshlink_get_node(mesh[0], name[i]));
90 for(int i = 0; i < 3; i++) {
94 // Second and third node should not know each other yet.
96 assert(!meshlink_get_node(mesh[1], name[2]));
97 assert(!meshlink_get_node(mesh[2], name[1]));
99 // Check default blacklist status
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])));
106 // Generate an invitation for a node that is about to be blacklisted
108 char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
112 // Whitelisting and blacklisting by name should work.
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")));
120 meshlink_node_t **nodes = NULL;
122 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
124 assert(!strcmp(nodes[0]->name, "xyzzy"));
126 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
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"));
135 // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
137 assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
139 DIR *dir = opendir("blacklist_conf.0/current/invitations");
143 while((ent = readdir(dir))) {
144 assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."));
149 // Since these nodes now exist we should be able to forget them.
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
156 meshlink_set_node_status_cb(mesh[0], foo_status_cb);
157 meshlink_set_node_status_cb(mesh[2], baz_status_cb);
159 for(int i = 0; i < 3; i++) {
160 assert(meshlink_start(mesh[i]));
163 // Wait for them to connect.
165 assert(wait_sync_flag(&bar_connected, 5));
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])));
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])));
181 // Bar should not connect to baz
183 assert(wait_sync_flag(&baz_connected, 5) == false);
185 // But it should know about baz by now
187 meshlink_node_t *bar = meshlink_get_node(mesh[2], "bar");
188 meshlink_node_t *baz = meshlink_get_node(mesh[1], "baz");
192 // Have bar and baz whitelist each other
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));
199 // They should connect to each other
201 assert(wait_sync_flag(&baz_connected, 15));
203 // Trying to forget an active node should fail.
205 assert(!meshlink_forget_node(mesh[1], baz));
207 // We need to re-acquire the handle to baz
209 baz = meshlink_get_node(mesh[1], "baz");
214 for(int i = 0; i < 3; i++) {
215 meshlink_stop(mesh[i]);
218 // Forgetting a node should work now.
220 assert(meshlink_forget_node(mesh[1], baz));
224 for(int i = 0; i < 3; i++) {
225 meshlink_close(mesh[i]);
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);
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);
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);
239 assert(meshlink_get_node(mesh[0], "xyzzy"));
240 assert(!meshlink_get_node(mesh[0], "quux"));
242 meshlink_close(mesh[0]);