blob: 8dd10f0ece0b7db4d6083122c37cdcd273c1afaf [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "helper/handler.h"
2#include "helper/parameters.h"
3#include "helper/utils.h"
4#include <rawrtc.h>
5#include <rawrtcc.h>
6#include <rawrtcdc.h>
7#include <re.h>
8#include <stdlib.h> // exit
9#include <string.h> // memcpy
10#include <unistd.h> // STDIN_FILENO
11
12#define DEBUG_MODULE "data-channel-sctp-echo-app"
13#define DEBUG_LEVEL 7
14#include <re_dbg.h>
15
16enum {
17 TRANSPORT_BUFFER_LENGTH = 1048576, // 1 MiB
18};
19
20struct parameters {
21 struct rawrtc_ice_parameters* ice_parameters;
22 struct rawrtc_ice_candidates* ice_candidates;
23 struct rawrtc_dtls_parameters* dtls_parameters;
24 struct sctp_parameters sctp_parameters;
25};
26
27// Note: Shadows struct client
28struct data_channel_sctp_client {
29 char* name;
30 char** ice_candidate_types;
31 size_t n_ice_candidate_types;
32 struct rawrtc_ice_gather_options* gather_options;
33 enum rawrtc_ice_role role;
34 struct rawrtc_certificate* certificate;
35 struct rawrtc_ice_gatherer* gatherer;
36 struct rawrtc_ice_transport* ice_transport;
37 struct rawrtc_dtls_transport* dtls_transport;
38 struct rawrtc_sctp_transport* sctp_transport;
39 struct rawrtc_data_transport* data_transport;
40 struct list data_channels;
41 struct parameters local_parameters;
42 struct parameters remote_parameters;
43};
44
45static void print_local_parameters(struct data_channel_sctp_client* client);
46
47static void ice_gatherer_local_candidate_handler(
48 struct rawrtc_ice_candidate* const candidate,
49 char const* const url, // read-only
50 void* const arg) {
51 struct data_channel_sctp_client* const client = arg;
52
53 // Print local candidate
54 default_ice_gatherer_local_candidate_handler(candidate, url, arg);
55
56 // Print local parameters (if last candidate)
57 if (!candidate) {
58 print_local_parameters(client);
59 }
60}
61
62/*
63 * Print the data channel's received message's size and echo the
64 * message back.
65 */
66static void data_channel_message_handler(
67 struct mbuf* const buffer,
68 enum rawrtc_data_channel_message_flag const flags,
69 void* const arg // will be casted to `struct data_channel_helper*`
70) {
71 struct data_channel_helper* const channel = arg;
72 struct data_channel_sctp_client* const client =
73 (struct data_channel_sctp_client*) channel->client;
74 enum rawrtc_code error;
75 (void) flags;
76
77 // Print message size
78 default_data_channel_message_handler(buffer, flags, arg);
79
80 // Send message
81 DEBUG_PRINTF("(%s) Sending %zu bytes\n", client->name, mbuf_get_left(buffer));
82 error = rawrtc_data_channel_send(
83 channel->channel, buffer,
84 flags & RAWRTC_DATA_CHANNEL_MESSAGE_FLAG_IS_BINARY ? true : false);
85 if (error) {
86 DEBUG_WARNING("Could not send, reason: %s\n", rawrtc_code_to_str(error));
87 }
88}
89
90/*
91 * Handle the newly created data channel.
92 */
93static void data_channel_handler(
94 struct rawrtc_data_channel* const channel, // read-only, MUST be referenced when used
95 void* const arg // will be casted to `struct client*`
96) {
97 struct data_channel_sctp_client* const client = arg;
98 struct data_channel_helper* channel_helper;
99
100 // Print channel
101 default_data_channel_handler(channel, arg);
102
103 // Create data channel helper instance & add to list
104 // Note: In this case we need to reference the channel because we have not created it
105 data_channel_helper_create_from_channel(&channel_helper, mem_ref(channel), arg, NULL);
106 list_append(&client->data_channels, &channel_helper->le, channel_helper);
107
108 // Set handler argument & handlers
109 EOE(rawrtc_data_channel_set_arg(channel, channel_helper));
110 EOE(rawrtc_data_channel_set_open_handler(channel, default_data_channel_open_handler));
111 EOE(rawrtc_data_channel_set_buffered_amount_low_handler(
112 channel, default_data_channel_buffered_amount_low_handler));
113 EOE(rawrtc_data_channel_set_error_handler(channel, default_data_channel_error_handler));
114 EOE(rawrtc_data_channel_set_close_handler(channel, default_data_channel_close_handler));
115 EOE(rawrtc_data_channel_set_message_handler(channel, data_channel_message_handler));
116}
117
118static void client_init(struct data_channel_sctp_client* const client) {
119 struct rawrtc_certificate* certificates[1];
120
121 // Generate certificates
122 EOE(rawrtc_certificate_generate(&client->certificate, NULL));
123 certificates[0] = client->certificate;
124
125 // Create ICE gatherer
126 EOE(rawrtc_ice_gatherer_create(
127 &client->gatherer, client->gather_options, default_ice_gatherer_state_change_handler,
128 default_ice_gatherer_error_handler, ice_gatherer_local_candidate_handler, client));
129
130 // Create ICE transport
131 EOE(rawrtc_ice_transport_create(
132 &client->ice_transport, client->gatherer, default_ice_transport_state_change_handler,
133 default_ice_transport_candidate_pair_change_handler, client));
134
135 // Create DTLS transport
136 EOE(rawrtc_dtls_transport_create(
137 &client->dtls_transport, client->ice_transport, certificates, ARRAY_SIZE(certificates),
138 default_dtls_transport_state_change_handler, default_dtls_transport_error_handler, client));
139
140 // Create SCTP transport
141 EOE(rawrtc_sctp_transport_create(
142 &client->sctp_transport, client->dtls_transport,
143 client->local_parameters.sctp_parameters.port, data_channel_handler,
144 default_sctp_transport_state_change_handler, client));
145 EOE(rawrtc_sctp_transport_set_buffer_length(
146 client->sctp_transport, TRANSPORT_BUFFER_LENGTH, TRANSPORT_BUFFER_LENGTH));
147
148 // Get data transport
149 EOE(rawrtc_sctp_transport_get_data_transport(&client->data_transport, client->sctp_transport));
150}
151
152static void client_start_gathering(struct data_channel_sctp_client* const client) {
153 // Start gathering
154 EOE(rawrtc_ice_gatherer_gather(client->gatherer, NULL));
155}
156
157static void client_start_transports(struct data_channel_sctp_client* const client) {
158 struct parameters* const remote_parameters = &client->remote_parameters;
159
160 // Start ICE transport
161 EOE(rawrtc_ice_transport_start(
162 client->ice_transport, client->gatherer, remote_parameters->ice_parameters, client->role));
163
164 // Start DTLS transport
165 EOE(rawrtc_dtls_transport_start(client->dtls_transport, remote_parameters->dtls_parameters));
166
167 // Start SCTP transport
168 EOE(rawrtc_sctp_transport_start(
169 client->sctp_transport, remote_parameters->sctp_parameters.capabilities,
170 remote_parameters->sctp_parameters.port));
171}
172
173static void parameters_destroy(struct parameters* const parameters) {
174 // Un-reference
175 parameters->ice_parameters = mem_deref(parameters->ice_parameters);
176 parameters->ice_candidates = mem_deref(parameters->ice_candidates);
177 parameters->dtls_parameters = mem_deref(parameters->dtls_parameters);
178 if (parameters->sctp_parameters.capabilities) {
179 parameters->sctp_parameters.capabilities =
180 mem_deref(parameters->sctp_parameters.capabilities);
181 }
182}
183
184static void client_stop(struct data_channel_sctp_client* const client) {
185 // Clear data channels
186 list_flush(&client->data_channels);
187
188 // Stop all transports & gatherer
189 if (client->sctp_transport) {
190 EOE(rawrtc_sctp_transport_stop(client->sctp_transport));
191 }
192 if (client->dtls_transport) {
193 EOE(rawrtc_dtls_transport_stop(client->dtls_transport));
194 }
195 if (client->ice_transport) {
196 EOE(rawrtc_ice_transport_stop(client->ice_transport));
197 }
198 if (client->gatherer) {
199 EOE(rawrtc_ice_gatherer_close(client->gatherer));
200 }
201
202 // Un-reference & close
203 parameters_destroy(&client->remote_parameters);
204 parameters_destroy(&client->local_parameters);
205 client->data_transport = mem_deref(client->data_transport);
206 client->sctp_transport = mem_deref(client->sctp_transport);
207 client->dtls_transport = mem_deref(client->dtls_transport);
208 client->ice_transport = mem_deref(client->ice_transport);
209 client->gatherer = mem_deref(client->gatherer);
210 client->certificate = mem_deref(client->certificate);
211 client->gather_options = mem_deref(client->gather_options);
212
213 // Stop listening on STDIN
214 fd_close(STDIN_FILENO);
215}
216
217static void client_set_parameters(struct data_channel_sctp_client* const client) {
218 struct parameters* const remote_parameters = &client->remote_parameters;
219
220 // Set remote ICE candidates
221 EOE(rawrtc_ice_transport_set_remote_candidates(
222 client->ice_transport, remote_parameters->ice_candidates->candidates,
223 remote_parameters->ice_candidates->n_candidates));
224}
225
226static void parse_remote_parameters(int flags, void* arg) {
227 struct data_channel_sctp_client* const client = arg;
228 enum rawrtc_code error;
229 struct odict* dict = NULL;
230 struct odict* node = NULL;
231 struct rawrtc_ice_parameters* ice_parameters = NULL;
232 struct rawrtc_ice_candidates* ice_candidates = NULL;
233 struct rawrtc_dtls_parameters* dtls_parameters = NULL;
234 struct sctp_parameters sctp_parameters = {0};
235 (void) flags;
236
237 // Get dict from JSON
238 error = get_json_stdin(&dict);
239 if (error) {
240 goto out;
241 }
242
243 // Decode JSON
244 error |= dict_get_entry(&node, dict, "iceParameters", ODICT_OBJECT, true);
245 error |= get_ice_parameters(&ice_parameters, node);
246 error |= dict_get_entry(&node, dict, "iceCandidates", ODICT_ARRAY, true);
247 error |= get_ice_candidates(&ice_candidates, node, arg);
248 error |= dict_get_entry(&node, dict, "dtlsParameters", ODICT_OBJECT, true);
249 error |= get_dtls_parameters(&dtls_parameters, node);
250 error |= dict_get_entry(&node, dict, "sctpParameters", ODICT_OBJECT, true);
251 error |= get_sctp_parameters(&sctp_parameters, node);
252
253 // Ok?
254 if (error) {
255 DEBUG_WARNING("Invalid remote parameters\n");
256 if (sctp_parameters.capabilities) {
257 mem_deref(sctp_parameters.capabilities);
258 }
259 goto out;
260 }
261
262 // Set parameters & start transports
263 client->remote_parameters.ice_parameters = mem_ref(ice_parameters);
264 client->remote_parameters.ice_candidates = mem_ref(ice_candidates);
265 client->remote_parameters.dtls_parameters = mem_ref(dtls_parameters);
266 memcpy(&client->remote_parameters.sctp_parameters, &sctp_parameters, sizeof(sctp_parameters));
267 DEBUG_INFO("Applying remote parameters\n");
268 client_set_parameters(client);
269 client_start_transports(client);
270
271out:
272 // Un-reference
273 mem_deref(dtls_parameters);
274 mem_deref(ice_candidates);
275 mem_deref(ice_parameters);
276 mem_deref(dict);
277
278 // Exit?
279 if (error == RAWRTC_CODE_NO_VALUE) {
280 DEBUG_NOTICE("Exiting\n");
281
282 // Stop client & bye
283 client_stop(client);
284 re_cancel();
285 }
286}
287
288static void client_get_parameters(struct data_channel_sctp_client* const client) {
289 struct parameters* const local_parameters = &client->local_parameters;
290
291 // Get local ICE parameters
292 EOE(rawrtc_ice_gatherer_get_local_parameters(
293 &local_parameters->ice_parameters, client->gatherer));
294
295 // Get local ICE candidates
296 EOE(rawrtc_ice_gatherer_get_local_candidates(
297 &local_parameters->ice_candidates, client->gatherer));
298
299 // Get local DTLS parameters
300 EOE(rawrtc_dtls_transport_get_local_parameters(
301 &local_parameters->dtls_parameters, client->dtls_transport));
302
303 // Get local SCTP parameters
304 EOE(rawrtc_sctp_transport_get_capabilities(&local_parameters->sctp_parameters.capabilities));
305 EOE(rawrtc_sctp_transport_get_port(
306 &local_parameters->sctp_parameters.port, client->sctp_transport));
307}
308
309static void print_local_parameters(struct data_channel_sctp_client* client) {
310 struct odict* dict;
311 struct odict* node;
312
313 // Get local parameters
314 client_get_parameters(client);
315
316 // Create dict
317 EOR(odict_alloc(&dict, 16));
318
319 // Create nodes
320 EOR(odict_alloc(&node, 16));
321 set_ice_parameters(client->local_parameters.ice_parameters, node);
322 EOR(odict_entry_add(dict, "iceParameters", ODICT_OBJECT, node));
323 mem_deref(node);
324 EOR(odict_alloc(&node, 16));
325 set_ice_candidates(client->local_parameters.ice_candidates, node);
326 EOR(odict_entry_add(dict, "iceCandidates", ODICT_ARRAY, node));
327 mem_deref(node);
328 EOR(odict_alloc(&node, 16));
329 set_dtls_parameters(client->local_parameters.dtls_parameters, node);
330 EOR(odict_entry_add(dict, "dtlsParameters", ODICT_OBJECT, node));
331 mem_deref(node);
332 EOR(odict_alloc(&node, 16));
333 set_sctp_parameters(client->sctp_transport, &client->local_parameters.sctp_parameters, node);
334 EOR(odict_entry_add(dict, "sctpParameters", ODICT_OBJECT, node));
335 mem_deref(node);
336
337 // Print JSON
338 DEBUG_INFO("Local Parameters:\n%H\n", json_encode_odict, dict);
339
340 // Un-reference
341 mem_deref(dict);
342}
343
344static void exit_with_usage(char* program) {
345 DEBUG_WARNING("Usage: %s <0|1 (ice-role)> [<sctp-port>] [<ice-candidate-type> ...]", program);
346 exit(1);
347}
348
349int main(int argc, char* argv[argc + 1]) {
350 char** ice_candidate_types = NULL;
351 size_t n_ice_candidate_types = 0;
352 enum rawrtc_ice_role role;
353 struct rawrtc_ice_gather_options* gather_options;
354 char* const turn_zwuenf_org_urls[] = {"stun:turn.zwuenf.org"};
355 struct data_channel_sctp_client client = {0};
356 (void) client.ice_candidate_types;
357 (void) client.n_ice_candidate_types;
358
359 // Debug
360 dbg_init(DBG_DEBUG, DBG_ALL);
361 DEBUG_PRINTF("Init\n");
362
363 // Initialise
364 EOE(rawrtc_init(true));
365
366 // Check arguments length
367 if (argc < 2) {
368 exit_with_usage(argv[0]);
369 }
370
371 // Get ICE role
372 if (get_ice_role(&role, argv[1])) {
373 exit_with_usage(argv[0]);
374 }
375
376 // Get SCTP port (optional)
377 if (argc >= 3 && !str_to_uint16(&client.local_parameters.sctp_parameters.port, argv[2])) {
378 exit_with_usage(argv[0]);
379 }
380
381 // Get enabled ICE candidate types to be added (optional)
382 if (argc >= 4) {
383 ice_candidate_types = &argv[3];
384 n_ice_candidate_types = (size_t) argc - 3;
385 }
386
387 // Create ICE gather options
388 EOE(rawrtc_ice_gather_options_create(&gather_options, RAWRTC_ICE_GATHER_POLICY_ALL));
389
390 // Add ICE servers to ICE gather options
391 EOE(rawrtc_ice_gather_options_add_server(
392 gather_options, turn_zwuenf_org_urls, ARRAY_SIZE(turn_zwuenf_org_urls), NULL, NULL,
393 RAWRTC_ICE_CREDENTIAL_TYPE_NONE));
394
395 // Set client fields
396 client.name = "A";
397 client.ice_candidate_types = ice_candidate_types;
398 client.n_ice_candidate_types = n_ice_candidate_types;
399 client.gather_options = gather_options;
400 client.role = role;
401 list_init(&client.data_channels);
402
403 // Setup client
404 client_init(&client);
405
406 // Start gathering
407 client_start_gathering(&client);
408
409 // Listen on stdin
410 EOR(fd_listen(STDIN_FILENO, FD_READ, parse_remote_parameters, &client));
411
412 // Start main loop
413 EOR(re_main(default_signal_handler));
414
415 // Stop client & bye
416 client_stop(&client);
417 before_exit();
418 return 0;
419}