]> git.meshlink.io Git - meshlink/blob - test/channels-fork.c
Reduce how often we have to poll the packet queue.
[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 reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
55         (void)mesh;
56         (void)channel;
57         (void)port;
58         (void)data;
59         (void)len;
60
61         return false;
62 }
63
64 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
65         if(port != 7) {
66                 return false;
67         }
68
69         meshlink_set_node_status_cb(mesh, bar_status_cb);
70         meshlink_set_channel_receive_cb(mesh, channel, bar_receive_cb);
71         set_sync_flag(&foo_connected, true);
72
73         if(data) {
74                 bar_receive_cb(mesh, channel, data, len);
75         }
76
77         return true;
78 }
79
80 static void poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, size_t len) {
81         (void)len;
82
83         meshlink_set_channel_poll_cb(mesh, channel, NULL);
84
85         if(meshlink_channel_send(mesh, channel, "Hello", 5) != 5) {
86                 fprintf(stderr, "Could not send whole message\n");
87         }
88 }
89
90 static int main1(int rfd, int wfd) {
91         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
92
93         assert(meshlink_destroy("channels_fork_conf.1"));
94         meshlink_handle_t *mesh = meshlink_open("channels_fork_conf.1", "foo", "channels", DEV_CLASS_BACKBONE);
95         assert(mesh);
96
97         meshlink_enable_discovery(mesh, false);
98
99         assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
100
101         char *data = meshlink_export(mesh);
102         assert(data);
103
104         ssize_t len = strlen(data);
105         assert(write(wfd, &len, sizeof(len)) == sizeof(len));
106         assert(write(wfd, data, len) == len);
107         free(data);
108
109         assert(read(rfd, &len, sizeof(len)) == sizeof(len));
110         char indata[len + 1];
111         assert(read(rfd, indata, len) == len);
112         indata[len] = 0;
113
114         assert(meshlink_import(mesh, indata));
115
116         meshlink_set_channel_accept_cb(mesh, reject_cb);
117
118         assert(meshlink_start(mesh));
119
120         // Open a channel from foo to bar.
121
122         meshlink_node_t *bar = meshlink_get_node(mesh, "bar");
123         assert(bar);
124
125         meshlink_channel_t *channel = meshlink_channel_open(mesh, bar, 7, foo_receive_cb, NULL, 0);
126         assert(channel);
127
128         meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
129
130         assert(wait_sync_flag(&bar_responded, 20));
131
132         meshlink_channel_close(mesh, channel);
133
134         // Clean up.
135
136         meshlink_close(mesh);
137
138         return 0;
139 }
140
141
142 static int main2(int rfd, int wfd) {
143 #ifdef __linux__
144         prctl(PR_SET_PDEATHSIG, SIGTERM);
145 #endif
146
147         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
148
149         assert(meshlink_destroy("channels_fork_conf.2"));
150         meshlink_handle_t *mesh = meshlink_open("channels_fork_conf.2", "bar", "channels", DEV_CLASS_BACKBONE);
151         assert(mesh);
152
153         meshlink_enable_discovery(mesh, false);
154
155         assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
156
157         char *data = meshlink_export(mesh);
158         assert(data);
159
160         ssize_t len = strlen(data);
161         assert(write(wfd, &len, sizeof(len)) == sizeof(len));
162         assert(write(wfd, data, len) == len);
163         free(data);
164
165         assert(read(rfd, &len, sizeof(len)) == sizeof(len));
166         char indata[len + 1];
167         assert(read(rfd, indata, len) == len);
168         indata[len] = 0;
169
170         assert(meshlink_import(mesh, indata));
171
172         meshlink_set_channel_accept_cb(mesh, accept_cb);
173
174         assert(meshlink_start(mesh));
175
176         assert(wait_sync_flag(&foo_connected, 20));
177         assert(wait_sync_flag(&foo_gone, 20));
178
179         meshlink_close(mesh);
180
181         return 0;
182 }
183
184 static void alarm_handler(int sig) {
185         (void)sig;
186         assert(0);
187 }
188
189 int main() {
190         int fda[2], fdb[2];
191
192         assert(pipe2(fda, 0) != -1);
193         assert(pipe2(fdb, 0) != -1);
194
195         if(!fork()) {
196                 return main2(fdb[0], fda[1]);
197         }
198
199         signal(SIGALRM, alarm_handler);
200         alarm(30);
201         assert(main1(fda[0], fdb[1]) == 0);
202
203         int wstatus;
204         assert(wait(&wstatus) != -1 || errno == ECHILD);
205         assert(WIFEXITED(wstatus));
206         assert(WEXITSTATUS(wstatus) == 0);
207 }