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