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