]> git.meshlink.io Git - meshlink/blob - test/invite-join.c
Have nodes remember in which submesh they live.
[meshlink] / test / invite-join.c
1 #ifdef NDEBUG
2 #undef NDEBUG
3 #endif
4
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/time.h>
10 #include <assert.h>
11
12 #include "meshlink.h"
13 #include "utils.h"
14
15 static struct sync_flag baz_reachable;
16
17 static void status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
18         (void)mesh;
19
20         if(reachable && !strcmp(node->name, "baz")) {
21                 set_sync_flag(&baz_reachable, true);
22         }
23 }
24
25 int main() {
26         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
27
28         assert(meshlink_destroy("invite_join_conf.1"));
29         assert(meshlink_destroy("invite_join_conf.2"));
30         assert(meshlink_destroy("invite_join_conf.3"));
31         assert(meshlink_destroy("invite_join_conf.4"));
32         assert(meshlink_destroy("invite_join_conf.5"));
33         assert(meshlink_destroy("invite_join_conf.6"));
34
35         // Open thee new meshlink instance.
36
37         meshlink_handle_t *mesh1 = meshlink_open("invite_join_conf.1", "foo", "invite-join", DEV_CLASS_BACKBONE);
38         assert(mesh1);
39
40         meshlink_handle_t *mesh2 = meshlink_open("invite_join_conf.2", "bar", "invite-join", DEV_CLASS_BACKBONE);
41         assert(mesh2);
42
43         meshlink_handle_t *mesh3 = meshlink_open("invite_join_conf.3", "quux", "invite-join", DEV_CLASS_BACKBONE);
44         assert(mesh3);
45
46         // Disable local discovery.
47
48         meshlink_enable_discovery(mesh1, false);
49         meshlink_enable_discovery(mesh2, false);
50         meshlink_enable_discovery(mesh3, false);
51
52         // Have the first instance generate invitations.
53
54         meshlink_set_node_status_cb(mesh1, status_cb);
55
56         assert(meshlink_set_canonical_address(mesh1, meshlink_get_self(mesh1), "localhost", NULL));
57
58         char *baz_url = meshlink_invite(mesh1, NULL, "baz");
59         assert(baz_url);
60
61         char *quux_url = meshlink_invite(mesh1, NULL, "quux");
62         assert(quux_url);
63
64         // Have the second instance join the first.
65
66         assert(meshlink_start(mesh1));
67
68         assert(meshlink_join(mesh2, baz_url));
69         assert(meshlink_start(mesh2));
70
71         // Wait for the two to connect.
72
73         assert(wait_sync_flag(&baz_reachable, 20));
74
75         // Wait for UDP communication to become possible.
76
77         int pmtu = meshlink_get_pmtu(mesh1, meshlink_get_node(mesh1, "baz"));
78
79         for(int i = 0; i < 10 && !pmtu; i++) {
80                 sleep(1);
81                 pmtu = meshlink_get_pmtu(mesh1, meshlink_get_node(mesh1, "baz"));
82         }
83
84         assert(pmtu);
85
86         // Check that an invitation cannot be used twice
87
88         assert(!meshlink_join(mesh3, baz_url));
89         free(baz_url);
90
91         // Check that nodes cannot join with expired invitations
92
93         meshlink_set_invitation_timeout(mesh1, 0);
94
95         assert(!meshlink_join(mesh3, quux_url));
96         free(quux_url);
97
98         // Check that existing nodes cannot join another mesh
99
100         char *corge_url = meshlink_invite(mesh3, NULL, "corge");
101         assert(corge_url);
102
103         assert(meshlink_start(mesh3));
104
105         meshlink_stop(mesh2);
106
107         assert(!meshlink_join(mesh2, corge_url));
108         free(corge_url);
109
110         // Check that invitations work correctly after changing ports
111
112         meshlink_set_invitation_timeout(mesh1, 86400);
113         meshlink_stop(mesh1);
114         meshlink_stop(mesh3);
115
116         int oldport = meshlink_get_port(mesh1);
117         bool success = false;
118
119         for(int i = 0; !success && i < 100; i++) {
120                 success = meshlink_set_port(mesh1, 0x9000 + rand() % 0x1000);
121         }
122
123         assert(success);
124         int newport = meshlink_get_port(mesh1);
125         assert(oldport != newport);
126
127         assert(meshlink_start(mesh1));
128         quux_url = meshlink_invite(mesh1, NULL, "quux");
129         assert(quux_url);
130
131         // The old port should not be in the invitation URL
132
133         char portstr[10];
134         snprintf(portstr, sizeof(portstr), ":%d", oldport);
135         assert(!strstr(quux_url, portstr));
136
137         // The new port should be in the invitation URL
138
139         snprintf(portstr, sizeof(portstr), ":%d", newport);
140         assert(strstr(quux_url, portstr));
141
142         // The invitation should work
143
144         assert(meshlink_join(mesh3, quux_url));
145         free(quux_url);
146
147         // Check that adding duplicate addresses get removed correctly
148
149         assert(meshlink_add_invitation_address(mesh1, "localhost", portstr + 1));
150         corge_url = meshlink_invite(mesh1, NULL, "corge");
151         assert(corge_url);
152         char *localhost = strstr(corge_url, "localhost");
153         assert(localhost);
154         assert(!strstr(localhost + 1, "localhost"));
155         free(corge_url);
156
157         // Check that resetting and adding multiple, different invitation address works
158
159         meshlink_clear_invitation_addresses(mesh1);
160         assert(meshlink_add_invitation_address(mesh1, "1.invalid.", "12345"));
161         assert(meshlink_add_invitation_address(mesh1, "2.invalid.", NULL));
162         assert(meshlink_add_invitation_address(mesh1, "3.invalid.", NULL));
163         assert(meshlink_add_invitation_address(mesh1, "4.invalid.", NULL));
164         assert(meshlink_add_invitation_address(mesh1, "5.invalid.", NULL));
165         char *grault_url = meshlink_invite(mesh1, NULL, "grault");
166         assert(grault_url);
167         localhost = strstr(grault_url, "localhost");
168         assert(localhost);
169         char *invalid1 = strstr(grault_url, "1.invalid.:12345");
170         assert(invalid1);
171         char *invalid5 = strstr(grault_url, "5.invalid.");
172         assert(invalid5);
173
174         // Check that explicitly added invitation addresses come before others, in the order they were specified.
175
176         assert(invalid1 < invalid5);
177         assert(invalid5 < localhost);
178         free(grault_url);
179
180         // Check inviting nodes into a submesh
181
182         assert(!meshlink_get_node_submesh(mesh1, meshlink_get_self(mesh1)));
183
184         meshlink_handle_t *mesh4 = meshlink_open("invite_join_conf.4", "four", "invite-join", DEV_CLASS_BACKBONE);
185         meshlink_handle_t *mesh5 = meshlink_open("invite_join_conf.5", "five", "invite-join", DEV_CLASS_BACKBONE);
186         meshlink_handle_t *mesh6 = meshlink_open("invite_join_conf.6", "six", "invite-join", DEV_CLASS_BACKBONE);
187         assert(mesh4);
188         assert(mesh5);
189         assert(mesh6);
190
191         meshlink_enable_discovery(mesh4, false);
192         meshlink_enable_discovery(mesh5, false);
193         meshlink_enable_discovery(mesh6, false);
194
195         meshlink_submesh_t *submesh1 = meshlink_submesh_open(mesh1, "submesh1");
196         meshlink_submesh_t *submesh2 = meshlink_submesh_open(mesh1, "submesh2");
197         assert(submesh1);
198         assert(submesh2);
199
200         char *four_url = meshlink_invite(mesh1, submesh1, mesh4->name);
201         char *five_url = meshlink_invite(mesh1, submesh1, mesh5->name);
202         char *six_url = meshlink_invite(mesh1, submesh2, mesh6->name);
203         assert(four_url);
204         assert(five_url);
205         assert(six_url);
206
207         assert(meshlink_join(mesh4, four_url));
208         assert(meshlink_join(mesh5, five_url));
209         assert(meshlink_join(mesh6, six_url));
210
211         free(four_url);
212         free(five_url);
213         free(six_url);
214
215         assert(meshlink_start(mesh2));
216         assert(meshlink_start(mesh4));
217         assert(meshlink_start(mesh5));
218         assert(meshlink_start(mesh6));
219
220         // Check that each node knows in which submesh it is
221
222         meshlink_submesh_t *mesh4_submesh = meshlink_get_node_submesh(mesh4, meshlink_get_self(mesh4));
223         meshlink_submesh_t *mesh5_submesh = meshlink_get_node_submesh(mesh4, meshlink_get_self(mesh5));
224         meshlink_submesh_t *mesh6_submesh = meshlink_get_node_submesh(mesh6, meshlink_get_self(mesh6));
225         assert(mesh4_submesh);
226         assert(mesh5_submesh);
227         assert(mesh6_submesh);
228         assert(!strcmp(mesh4_submesh->name, "submesh1"));
229         assert(!strcmp(mesh5_submesh->name, "submesh1"));
230         assert(!strcmp(mesh6_submesh->name, "submesh2"));
231
232         // Wait for nodes to connect, and check that foo sees the right submeshes
233
234         sleep(2);
235         meshlink_node_t *mesh1_four = meshlink_get_node(mesh1, mesh4->name);
236         meshlink_node_t *mesh1_six = meshlink_get_node(mesh1, mesh6->name);
237         assert(meshlink_get_node_submesh(mesh1, meshlink_get_self(mesh1)) == NULL);
238         assert(meshlink_get_node_submesh(mesh1, mesh1_four) == submesh1);
239         assert(meshlink_get_node_submesh(mesh1, mesh1_six) == submesh2);
240
241         // Check that the new invitees still have the right submesh information
242
243         meshlink_node_t *mesh4_four = meshlink_get_node(mesh4, mesh4->name);
244         meshlink_node_t *mesh4_five = meshlink_get_node(mesh4, mesh5->name);
245         meshlink_node_t *mesh6_six = meshlink_get_node(mesh6, mesh6->name);
246         assert(meshlink_get_node_submesh(mesh4, mesh4_four) == mesh4_submesh);
247         assert(meshlink_get_node_submesh(mesh4, mesh4_five) == mesh4_submesh);
248         assert(meshlink_get_node_submesh(mesh6, mesh6_six) == mesh6_submesh);
249
250         // Check that bar can see all the nodes in submeshes and vice versa
251
252         assert(meshlink_get_node(mesh2, mesh4->name));
253         assert(meshlink_get_node(mesh2, mesh5->name));
254         assert(meshlink_get_node(mesh2, mesh6->name));
255         assert(meshlink_get_node(mesh4, mesh2->name));
256         assert(meshlink_get_node(mesh5, mesh2->name));
257         assert(meshlink_get_node(mesh6, mesh2->name));
258
259         // Check that four and five can see each other
260
261         assert(meshlink_get_node(mesh4, mesh5->name));
262         assert(meshlink_get_node(mesh5, mesh4->name));
263
264         // Check that the nodes in different submeshes cannot see each other
265
266         assert(!meshlink_get_node(mesh4, mesh6->name));
267         assert(!meshlink_get_node(mesh5, mesh6->name));
268         assert(!meshlink_get_node(mesh6, mesh4->name));
269         assert(!meshlink_get_node(mesh6, mesh5->name));
270
271         // Check that bar sees the right submesh information for the nodes in submeshes
272
273         meshlink_submesh_t *mesh2_four_submesh = meshlink_get_node_submesh(mesh2, meshlink_get_node(mesh2, mesh4->name));
274         meshlink_submesh_t *mesh2_five_submesh = meshlink_get_node_submesh(mesh2, meshlink_get_node(mesh2, mesh5->name));
275         meshlink_submesh_t *mesh2_six_submesh = meshlink_get_node_submesh(mesh2, meshlink_get_node(mesh2, mesh6->name));
276         assert(mesh2_four_submesh);
277         assert(mesh2_five_submesh);
278         assert(mesh2_six_submesh);
279         assert(!strcmp(mesh2_four_submesh->name, "submesh1"));
280         assert(!strcmp(mesh2_five_submesh->name, "submesh1"));
281         assert(!strcmp(mesh2_six_submesh->name, "submesh2"));
282
283         // Clean up.
284
285         meshlink_close(mesh6);
286         meshlink_close(mesh5);
287         meshlink_close(mesh4);
288         meshlink_close(mesh3);
289         meshlink_close(mesh2);
290         meshlink_close(mesh1);
291 }