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(&bar_blacklisted);
61 init_sync_flag(&baz_connected);
63 meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
65 // Create three instances.
67 const char *name[3] = {"foo", "bar", "baz"};
68 meshlink_handle_t *mesh[3];
71 for(int i = 0; i < 3; i++) {
73 assert(asprintf(&path, "blacklist_conf.%d", i) != -1 && path);
75 assert(meshlink_destroy(path));
76 mesh[i] = meshlink_open(path, name[i], "blacklist", DEV_CLASS_BACKBONE);
80 assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
82 data[i] = meshlink_export(mesh[i]);
85 // Enable default blacklist on all nodes.
86 meshlink_set_default_blacklist(mesh[i], true);
89 // The first node knows the two other nodes.
91 for(int i = 1; i < 3; i++) {
92 assert(meshlink_import(mesh[i], data[0]));
93 assert(meshlink_import(mesh[0], data[i]));
95 assert(meshlink_get_node(mesh[i], name[0]));
96 assert(meshlink_get_node(mesh[0], name[i]));
100 for(int i = 0; i < 3; i++) {
104 // Second and third node should not know each other yet.
106 assert(!meshlink_get_node(mesh[1], name[2]));
107 assert(!meshlink_get_node(mesh[2], name[1]));
109 // Check default blacklist status
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])));
116 // Generate an invitation for a node that is about to be blacklisted
118 char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
122 // Whitelisting and blacklisting by name should work.
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")));
130 meshlink_node_t **nodes = NULL;
132 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
134 assert(!strcmp(nodes[0]->name, "xyzzy"));
136 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
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"));
145 // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
147 assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
149 DIR *dir = opendir("blacklist_conf.0/current/invitations");
153 while((ent = readdir(dir))) {
154 assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."));
159 // Since these nodes now exist we should be able to forget them.
161 assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
162 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
166 meshlink_set_node_status_cb(mesh[0], foo_status_cb);
167 meshlink_set_node_status_cb(mesh[2], baz_status_cb);
169 for(int i = 0; i < 3; i++) {
170 assert(meshlink_start(mesh[i]));
173 // Wait for them to connect.
175 assert(wait_sync_flag(&bar_connected, 5));
179 meshlink_set_blacklisted_cb(mesh[1], bar_blacklisted_cb);
181 set_sync_flag(&bar_disconnected, false);
182 assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
183 assert(wait_sync_flag(&bar_disconnected, 5));
184 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
186 assert(wait_sync_flag(&bar_blacklisted, 10));
190 set_sync_flag(&bar_connected, false);
191 assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
192 assert(wait_sync_flag(&bar_connected, 15));
193 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
195 // Bar should not connect to baz
197 assert(wait_sync_flag(&baz_connected, 5) == false);
199 // But it should know about baz by now
201 meshlink_node_t *bar = meshlink_get_node(mesh[2], "bar");
202 meshlink_node_t *baz = meshlink_get_node(mesh[1], "baz");
206 // Have bar and baz whitelist each other
208 assert(meshlink_whitelist(mesh[1], baz));
209 assert(meshlink_whitelist(mesh[2], bar));
210 assert(!meshlink_get_node_blacklisted(mesh[1], baz));
211 assert(!meshlink_get_node_blacklisted(mesh[2], bar));
213 // They should connect to each other
215 assert(wait_sync_flag(&baz_connected, 15));
217 // Trying to forget an active node should fail.
219 assert(!meshlink_forget_node(mesh[1], baz));
221 // We need to re-acquire the handle to baz
223 baz = meshlink_get_node(mesh[1], "baz");
228 for(int i = 0; i < 3; i++) {
229 meshlink_stop(mesh[i]);
232 // Forgetting a node should work now.
234 assert(meshlink_forget_node(mesh[1], baz));
238 for(int i = 0; i < 3; i++) {
239 meshlink_close(mesh[i]);
242 // Check that foo has a config file for xyzzy but not quux
243 assert(access("blacklist_conf.0/current/hosts/xyzzy", F_OK) == 0);
244 assert(access("blacklist_conf.0/current/hosts/quux", F_OK) != 0 && errno == ENOENT);
246 // Check that bar has no config file for baz
247 assert(access("blacklist_conf.2/current/hosts/bar", F_OK) == 0);
248 assert(access("blacklist_conf.1/current/hosts/baz", F_OK) != 0 && errno == ENOENT);
250 // Check that we remember xyzzy but not quux after reopening the mesh
251 mesh[0] = meshlink_open("blacklist_conf.0", "foo", "blacklist", DEV_CLASS_BACKBONE);
253 assert(meshlink_get_node(mesh[0], "xyzzy"));
254 assert(!meshlink_get_node(mesh[0], "quux"));
256 meshlink_close(mesh[0]);