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