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