]> git.meshlink.io Git - meshlink/blob - test/channels-udp.c
Don't use assert() to check the results of pthread_*() calls.
[meshlink] / test / channels-udp.c
1 #ifdef NDEBUG
2 #undef NDEBUG
3 #endif
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/time.h>
11 #include <time.h>
12
13 #include "../src/meshlink.h"
14 #include "utils.h"
15
16 static struct sync_flag accept_flag;
17 static struct sync_flag close_flag;
18
19 struct client {
20         meshlink_handle_t *mesh;
21         meshlink_channel_t *channel;
22         size_t received;
23         bool got_large_packet;
24 };
25
26 static void server_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
27         (void)data;
28
29         // We expect no data from clients, apart from disconnections.
30         assert(len == 0);
31
32         meshlink_channel_t **c = mesh->priv;
33         int count = 0;
34
35         for(int i = 0; i < 3; i++) {
36                 if(c[i] == channel) {
37                         c[i] = NULL;
38                         meshlink_channel_close(mesh, channel);
39                 }
40
41                 if(c[i]) {
42                         count++;
43                 }
44         }
45
46         if(!count) {
47                 set_sync_flag(&close_flag, true);
48         }
49 }
50
51 static void client_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
52         (void)channel;
53         (void)data;
54
55         // We expect always the same amount of data from the server.
56         assert(mesh->priv);
57         struct client *client = mesh->priv;
58         assert(len == 512 || len == 65536);
59         client->received += len;
60
61         if(len == 65536) {
62                 client->got_large_packet = true;
63         }
64 }
65
66 static void status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
67         assert(mesh->priv);
68         struct client *client = mesh->priv;
69
70         if(reachable && !strcmp(node->name, "server")) {
71                 assert(!client->channel);
72                 client->channel = meshlink_channel_open_ex(mesh, node, 1, client_receive_cb, NULL, 0, MESHLINK_CHANNEL_UDP);
73                 assert(client->channel);
74         }
75 }
76
77 static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
78         (void)data;
79         (void)len;
80
81         assert(port == 1);
82         assert(meshlink_channel_get_flags(mesh, channel) == MESHLINK_CHANNEL_UDP);
83         meshlink_set_channel_receive_cb(mesh, channel, server_receive_cb);
84
85         assert(mesh->priv);
86         meshlink_channel_t **c = mesh->priv;
87
88         for(int i = 0; i < 3; i++) {
89                 if(c[i] == NULL) {
90                         c[i] = channel;
91
92                         if(i == 2) {
93                                 set_sync_flag(&accept_flag, true);
94                         }
95
96                         return true;
97                 }
98         }
99
100         return false;
101 }
102
103 int main(void) {
104         init_sync_flag(&accept_flag);
105         init_sync_flag(&close_flag);
106
107         meshlink_set_log_cb(NULL, MESHLINK_WARNING, log_cb);
108
109         // Open four new meshlink instance, the server and three peers.
110
111         const char *names[3] = {"foo", "bar", "baz"};
112         struct client clients[3];
113         meshlink_channel_t *channels[3] = {NULL, NULL, NULL};
114         memset(clients, 0, sizeof(clients));
115
116         assert(meshlink_destroy("channels_udp_conf.0"));
117         meshlink_handle_t *server = meshlink_open("channels_udp_conf.0", "server", "channels-udp", DEV_CLASS_BACKBONE);
118         assert(server);
119         meshlink_enable_discovery(server, false);
120         server->priv = channels;
121         meshlink_set_channel_accept_cb(server, accept_cb);
122         assert(meshlink_start(server));
123
124         for(int i = 0; i < 3; i++) {
125                 char dir[100];
126                 snprintf(dir, sizeof(dir), "channels_udp_conf.%d", i + 1);
127                 assert(meshlink_destroy(dir));
128                 clients[i].mesh = meshlink_open(dir, names[i], "channels-udp", DEV_CLASS_STATIONARY);
129                 assert(clients[i].mesh);
130                 clients[i].mesh->priv = &clients[i];
131                 meshlink_enable_discovery(clients[i].mesh, false);
132                 link_meshlink_pair(server, clients[i].mesh);
133                 meshlink_set_node_status_cb(clients[i].mesh, status_cb);
134                 assert(meshlink_start(clients[i].mesh));
135         }
136
137         // Wait for all three channels to connect
138
139         assert(wait_sync_flag(&accept_flag, 10));
140
141         for(int i = 0; i < 3; i++) {
142                 assert(channels[i]);
143                 assert(clients[i].channel);
144         }
145
146         // Check that we can send up to 65535 bytes without errors
147
148         char large_data[65536] = "";
149
150         for(int i = 0; i < 3; i++) {
151                 assert(meshlink_channel_send(server, channels[i], large_data, sizeof(large_data) + 1) == -1);
152                 assert(meshlink_channel_send(server, channels[i], large_data, sizeof(large_data)) == sizeof(large_data));
153         }
154
155         // Assert that packets larger than 64 kiB are not allowed
156
157         assert(meshlink_channel_send(server, channels[0], large_data, 65537) == -1);
158
159         // Stream packets from server to clients for 5 seconds at 40 Mbps (1 kB * 500 Hz)
160
161         char data[512];
162         memset(data, 'U', sizeof(data));
163
164         for(int j = 0; j < 2500; j++) {
165                 for(int i = 0; i < 3; i++) {
166                         assert(meshlink_channel_send(server, channels[i], data, sizeof(data)) == sizeof(data));
167                 }
168
169                 const struct timespec req = {0, 2000000};
170                 nanosleep(&req, NULL);
171         }
172
173         // Let the clients close the channels
174
175         for(int i = 0; i < 3; i++) {
176                 meshlink_channel_close(clients[i].mesh, clients[i].channel);
177                 meshlink_set_node_status_cb(clients[i].mesh, NULL);
178         }
179
180         assert(wait_sync_flag(&close_flag, 10));
181
182         // Check that the clients have received (most of) the data
183
184         for(int i = 0; i < 3; i++) {
185                 fprintf(stderr, "%s received %zu\n", clients[i].mesh->name, clients[i].received);
186         }
187
188         for(int i = 0; i < 3; i++) {
189                 assert(clients[i].received >= 1000000);
190                 assert(clients[i].received <= 1345536);
191                 assert(clients[i].got_large_packet);
192         }
193
194         // Clean up.
195
196         for(int i = 0; i < 3; i++) {
197                 meshlink_close(clients[i].mesh);
198         }
199
200         meshlink_close(server);
201
202         return 0;
203 }