]> git.meshlink.io Git - meshlink/blob - test/channels-fork.c
74aa84b7f525a8370771d2ebeb8118ed69c9f96b
[meshlink] / test / channels-fork.c
1 #define _GNU_SOURCE 1
2
3 #ifdef NDEBUG
4 #undef NDEBUG
5 #endif
6
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <errno.h>
15
16 #ifdef __linux__
17 #include <sys/prctl.h>
18 #endif
19
20 #include "utils.h"
21 #include "../src/meshlink.h"
22
23 static struct sync_flag bar_responded;
24 static struct sync_flag foo_connected;
25 static struct sync_flag foo_gone;
26
27 static void foo_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
28         (void)mesh;
29         (void)channel;
30         (void)len;
31
32         if(len == 5 && !memcmp(data, "Hello", 5)) {
33                 set_sync_flag(&bar_responded, true);
34         }
35 }
36
37 static void bar_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
38         (void)mesh;
39
40         if(!strcmp(node->name, "foo") && !reachable) {
41                 set_sync_flag(&foo_gone, true);
42         }
43 }
44
45 static void bar_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
46         // Echo the data back.
47         if(len) {
48                 assert(meshlink_channel_send(mesh, channel, data, len) == (ssize_t)len);
49         } else {
50                 meshlink_channel_close(mesh, channel);
51         }
52 }
53
54 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
55         if(port != 7) {
56                 return false;
57         }
58
59         meshlink_set_node_status_cb(mesh, bar_status_cb);
60         meshlink_set_channel_receive_cb(mesh, channel, bar_receive_cb);
61         set_sync_flag(&foo_connected, true);
62
63         if(data) {
64                 bar_receive_cb(mesh, channel, data, len);
65         }
66
67         return true;
68 }
69
70 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
71         (void)len;
72
73         meshlink_set_channel_poll_cb(mesh, channel, NULL);
74
75         if(meshlink_channel_send(mesh, channel, "Hello", 5) != 5) {
76                 fprintf(stderr, "Could not send whole message\n");
77         }
78 }
79
80 static int main1(int rfd, int wfd) {
81         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
82
83         assert(meshlink_destroy("channels_fork_conf.1"));
84         meshlink_handle_t *mesh = meshlink_open("channels_fork_conf.1", "foo", "channels-fork", DEV_CLASS_BACKBONE);
85         assert(mesh);
86
87         meshlink_enable_discovery(mesh, false);
88
89         assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
90
91         char *data = meshlink_export(mesh);
92         assert(data);
93
94         ssize_t len = strlen(data);
95         assert(write(wfd, &len, sizeof(len)) == sizeof(len));
96         assert(write(wfd, data, len) == len);
97         free(data);
98
99         assert(read(rfd, &len, sizeof(len)) == sizeof(len));
100         char indata[len + 1];
101         assert(read(rfd, indata, len) == len);
102         indata[len] = 0;
103
104         assert(meshlink_import(mesh, indata));
105
106         assert(meshlink_start(mesh));
107
108         // Open a channel from foo to bar.
109
110         meshlink_node_t *bar = meshlink_get_node(mesh, "bar");
111         assert(bar);
112
113         meshlink_channel_t *channel = meshlink_channel_open(mesh, bar, 7, foo_receive_cb, NULL, 0);
114         assert(channel);
115
116         meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
117
118         assert(wait_sync_flag(&bar_responded, 20));
119
120         meshlink_channel_close(mesh, channel);
121
122         // Clean up.
123
124         meshlink_close(mesh);
125
126         return 0;
127 }
128
129
130 static int main2(int rfd, int wfd) {
131 #ifdef __linux__
132         prctl(PR_SET_PDEATHSIG, SIGTERM);
133 #endif
134
135         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
136
137         assert(meshlink_destroy("channels_fork_conf.2"));
138         meshlink_handle_t *mesh = meshlink_open("channels_fork_conf.2", "bar", "channels-fork", DEV_CLASS_BACKBONE);
139         assert(mesh);
140
141         meshlink_enable_discovery(mesh, false);
142
143         assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
144
145         char *data = meshlink_export(mesh);
146         assert(data);
147
148         ssize_t len = strlen(data);
149         assert(write(wfd, &len, sizeof(len)) == sizeof(len));
150         assert(write(wfd, data, len) == len);
151         free(data);
152
153         assert(read(rfd, &len, sizeof(len)) == sizeof(len));
154         char indata[len + 1];
155         assert(read(rfd, indata, len) == len);
156         indata[len] = 0;
157
158         assert(meshlink_import(mesh, indata));
159
160         meshlink_set_channel_accept_cb(mesh, accept_cb);
161
162         assert(meshlink_start(mesh));
163
164         assert(wait_sync_flag(&foo_connected, 20));
165         assert(wait_sync_flag(&foo_gone, 20));
166
167         meshlink_close(mesh);
168
169         return 0;
170 }
171
172 static void alarm_handler(int sig) {
173         (void)sig;
174         assert(0);
175 }
176
177 int main(void) {
178         init_sync_flag(&bar_responded);
179         init_sync_flag(&foo_connected);
180         init_sync_flag(&foo_gone);
181
182         int fda[2], fdb[2];
183
184         assert(pipe(fda) != -1);
185         assert(pipe(fdb) != -1);
186
187         if(!fork()) {
188                 return main2(fdb[0], fda[1]);
189         }
190
191         signal(SIGALRM, alarm_handler);
192         alarm(30);
193         assert(main1(fda[0], fdb[1]) == 0);
194
195         int wstatus;
196         assert(wait(&wstatus) != -1 || errno == ECHILD);
197         assert(WIFEXITED(wstatus));
198         assert(WEXITSTATUS(wstatus) == 0);
199 }