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