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