]> git.meshlink.io Git - meshlink-tiny/blob - test/channels-fork.c
Add a metering test.
[meshlink-tiny] / 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-tiny.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         assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
88
89         char *data = meshlink_export(mesh);
90         assert(data);
91
92         ssize_t len = strlen(data);
93         assert(write(wfd, &len, sizeof(len)) == sizeof(len));
94         assert(write(wfd, data, len) == len);
95         free(data);
96
97         assert(read(rfd, &len, sizeof(len)) == sizeof(len));
98         char indata[len + 1];
99         assert(read(rfd, indata, len) == len);
100         indata[len] = 0;
101
102         assert(meshlink_import(mesh, indata));
103
104         assert(meshlink_start(mesh));
105
106         // Open a channel from foo to bar.
107
108         meshlink_node_t *bar = meshlink_get_node(mesh, "bar");
109         assert(bar);
110
111         meshlink_channel_t *channel = meshlink_channel_open(mesh, bar, 7, foo_receive_cb, NULL, 0);
112         assert(channel);
113
114         meshlink_set_channel_poll_cb(mesh, channel, poll_cb);
115
116         assert(wait_sync_flag(&bar_responded, 20));
117
118         meshlink_channel_close(mesh, channel);
119
120         // Clean up.
121
122         meshlink_close(mesh);
123
124         return 0;
125 }
126
127
128 static int main2(int rfd, int wfd) {
129 #ifdef __linux__
130         prctl(PR_SET_PDEATHSIG, SIGTERM);
131 #endif
132
133         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
134
135         assert(meshlink_destroy("channels_fork_conf.2"));
136         meshlink_handle_t *mesh = meshlink_open("channels_fork_conf.2", "bar", "channels-fork", DEV_CLASS_BACKBONE);
137         assert(mesh);
138
139         assert(meshlink_set_canonical_address(mesh, meshlink_get_self(mesh), "localhost", NULL));
140
141         char *data = meshlink_export(mesh);
142         assert(data);
143
144         ssize_t len = strlen(data);
145         assert(write(wfd, &len, sizeof(len)) == sizeof(len));
146         assert(write(wfd, data, len) == len);
147         free(data);
148
149         assert(read(rfd, &len, sizeof(len)) == sizeof(len));
150         char indata[len + 1];
151         assert(read(rfd, indata, len) == len);
152         indata[len] = 0;
153
154         assert(meshlink_import(mesh, indata));
155
156         meshlink_set_channel_accept_cb(mesh, accept_cb);
157
158         assert(meshlink_start(mesh));
159
160         assert(wait_sync_flag(&foo_connected, 20));
161         assert(wait_sync_flag(&foo_gone, 20));
162
163         meshlink_close(mesh);
164
165         return 0;
166 }
167
168 static void alarm_handler(int sig) {
169         (void)sig;
170         assert(0);
171 }
172
173 int main(void) {
174         init_sync_flag(&bar_responded);
175         init_sync_flag(&foo_connected);
176         init_sync_flag(&foo_gone);
177
178         int fda[2], fdb[2];
179
180         assert(pipe(fda) != -1);
181         assert(pipe(fdb) != -1);
182
183         if(!fork()) {
184                 return main2(fdb[0], fda[1]);
185         }
186
187         signal(SIGALRM, alarm_handler);
188         alarm(30);
189         assert(main1(fda[0], fdb[1]) == 0);
190
191         int wstatus;
192         assert(wait(&wstatus) != -1 || errno == ECHILD);
193         assert(WIFEXITED(wstatus));
194         assert(WEXITSTATUS(wstatus) == 0);
195 }