16 #include "meshlink-tiny.h"
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 // Whitelisting and blacklisting by name should work.
118 assert(meshlink_whitelist_by_name(mesh[0], "quux"));
119 assert(meshlink_blacklist_by_name(mesh[0], "xyzzy"));
120 assert(meshlink_get_node(mesh[0], "quux"));
121 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux")));
122 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "xyzzy")));
124 meshlink_node_t **nodes = NULL;
126 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
128 assert(!strcmp(nodes[0]->name, "xyzzy"));
130 nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
132 assert(!strcmp(nodes[0]->name, "bar"));
133 assert(!strcmp(nodes[1]->name, "baz"));
134 assert(!strcmp(nodes[2]->name, "foo"));
135 assert(!strcmp(nodes[3]->name, "quux"));
139 // Since these nodes now exist we should be able to forget them.
141 assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
142 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
146 meshlink_set_node_status_cb(mesh[0], foo_status_cb);
147 meshlink_set_node_status_cb(mesh[2], baz_status_cb);
149 for(int i = 0; i < 3; i++) {
150 assert(meshlink_start(mesh[i]));
153 // Wait for them to connect.
155 assert(wait_sync_flag(&bar_connected, 5));
159 meshlink_set_blacklisted_cb(mesh[1], bar_blacklisted_cb);
161 set_sync_flag(&bar_disconnected, false);
162 assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
163 assert(wait_sync_flag(&bar_disconnected, 5));
164 assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
166 assert(wait_sync_flag(&bar_blacklisted, 10));
170 set_sync_flag(&bar_connected, false);
171 assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
172 assert(wait_sync_flag(&bar_connected, 15));
173 assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
175 // Bar should not connect to baz
177 assert(wait_sync_flag(&baz_connected, 5) == false);
179 // But it should know about baz by now
181 meshlink_node_t *bar = meshlink_get_node(mesh[2], "bar");
182 meshlink_node_t *baz = meshlink_get_node(mesh[1], "baz");
186 // Have bar and baz whitelist each other
188 assert(meshlink_whitelist(mesh[1], baz));
189 assert(meshlink_whitelist(mesh[2], bar));
190 assert(!meshlink_get_node_blacklisted(mesh[1], baz));
191 assert(!meshlink_get_node_blacklisted(mesh[2], bar));
193 // They should connect to each other
195 assert(wait_sync_flag(&baz_connected, 15));
197 // Trying to forget an active node should fail.
199 assert(!meshlink_forget_node(mesh[1], baz));
201 // We need to re-acquire the handle to baz
203 baz = meshlink_get_node(mesh[1], "baz");
208 for(int i = 0; i < 3; i++) {
209 meshlink_stop(mesh[i]);
212 // Forgetting a node should work now.
214 assert(meshlink_forget_node(mesh[1], baz));
218 for(int i = 0; i < 3; i++) {
219 meshlink_close(mesh[i]);
222 // Check that foo has a config file for xyzzy but not quux
223 assert(access("blacklist_conf.0/current/hosts/xyzzy", F_OK) == 0);
224 assert(access("blacklist_conf.0/current/hosts/quux", F_OK) != 0 && errno == ENOENT);
226 // Check that bar has no config file for baz
227 assert(access("blacklist_conf.2/current/hosts/bar", F_OK) == 0);
228 assert(access("blacklist_conf.1/current/hosts/baz", F_OK) != 0 && errno == ENOENT);
230 // Check that we remember xyzzy but not quux after reopening the mesh
231 mesh[0] = meshlink_open("blacklist_conf.0", "foo", "blacklist", DEV_CLASS_BACKBONE);
233 assert(meshlink_get_node(mesh[0], "xyzzy"));
234 assert(!meshlink_get_node(mesh[0], "quux"));
236 meshlink_close(mesh[0]);