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