blob: ceb1a437560552711c76065dcc6430d98647b5dd [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "connection.h"
2#include "../certificate/certificate.h"
3#include "../dtls_transport/transport.h"
4#include "../ice_gather_options/options.h"
5#include "../ice_gatherer/gatherer.h"
6#include "../ice_server/server.h"
7#include "../peer_connection_configuration/configuration.h"
8#include "../peer_connection_description/description.h"
9#include "../peer_connection_ice_candidate/candidate.h"
10#include <rawrtc/config.h>
11#include <rawrtc/dtls_transport.h>
12#include <rawrtc/ice_candidate.h>
13#include <rawrtc/ice_gather_options.h>
14#include <rawrtc/ice_gatherer.h>
15#include <rawrtc/ice_parameters.h>
16#include <rawrtc/ice_transport.h>
17#include <rawrtc/peer_connection.h>
18#include <rawrtc/peer_connection_description.h>
19#include <rawrtc/peer_connection_state.h>
20#include <rawrtcc/code.h>
21#include <rawrtcc/utils.h>
22#include <rawrtcdc/data_channel.h>
23#include <rawrtcdc/data_channel_parameters.h>
24#include <rawrtcdc/data_transport.h>
25#include <rawrtcdc/sctp_transport.h>
26#include <re.h>
27
28#define DEBUG_MODULE "peer-connection"
29//#define RAWRTC_DEBUG_MODULE_LEVEL 7 // Note: Uncomment this to debug this module only
30#include <rawrtcc/debug.h>
31#include <src/peer_connection_configuration/configuration.h>
32
33/*
34 * Change the signalling state.
35 * Will call the corresponding handler.
36 * Caller MUST ensure that the same state is not set twice.
37 */
38static void set_signaling_state(
39 struct rawrtc_peer_connection* const connection, // not checked
40 enum rawrtc_signaling_state const state) {
41 // Set state
42 connection->signaling_state = state;
43
44 // Call handler (if any)
45 if (connection->signaling_state_change_handler) {
46 connection->signaling_state_change_handler(state, connection->arg);
47 }
48}
49
50/*
51 * Change the connection state to a specific state.
52 * Will call the corresponding handler.
53 * Caller MUST ensure that the same state is not set twice.
54 */
55static void set_connection_state(
56 struct rawrtc_peer_connection* const connection, // not checked
57 enum rawrtc_peer_connection_state const state) {
58 // Set state
59 connection->connection_state = state;
60
61 // Call handler (if any)
62 if (connection->connection_state_change_handler) {
63 connection->connection_state_change_handler(state, connection->arg);
64 }
65}
66
67/*
68 * Update connection state.
69 * Will call the corresponding handler.
70 */
71static void update_connection_state(struct rawrtc_peer_connection* const connection // not checked
72) {
73 enum rawrtc_code error;
74 enum rawrtc_ice_transport_state ice_transport_state = RAWRTC_ICE_TRANSPORT_STATE_NEW;
75 enum rawrtc_dtls_transport_state dtls_transport_state = RAWRTC_DTLS_TRANSPORT_STATE_NEW;
76 enum rawrtc_peer_connection_state connection_state;
77
78 // Nothing beats the closed state
79 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
80 return;
81 }
82
83 // Get ICE transport and DTLS transport states
84 if (connection->context.ice_transport) {
85 error =
86 rawrtc_ice_transport_get_state(&ice_transport_state, connection->context.ice_transport);
87 if (error) {
88 DEBUG_WARNING(
89 "Unable to get ICE transport state, reason: %s\n", rawrtc_error_to_code(error));
90 }
91 }
92 if (connection->context.dtls_transport) {
93 error = rawrtc_dtls_transport_get_state(
94 &dtls_transport_state, connection->context.dtls_transport);
95 if (error) {
96 DEBUG_WARNING(
97 "Unable to get DTLS transport state, reason: %s\n", rawrtc_error_to_code(error));
98 }
99 }
100
101 // Note: This follows the mindbogglingly confusing W3C spec description - it's just not
102 // super-obvious. We start with states that are easy to detect and remove more and more
103 // states from the equation.
104
105 // Failed: Any in the 'failed' state
106 if (ice_transport_state == RAWRTC_ICE_TRANSPORT_STATE_FAILED ||
107 dtls_transport_state == RAWRTC_DTLS_TRANSPORT_STATE_FAILED) {
108 connection_state = RAWRTC_PEER_CONNECTION_STATE_FAILED;
109 goto out;
110 }
111
112 // Connecting: Any in the 'connecting' or 'checking' state
113 if (ice_transport_state == RAWRTC_ICE_TRANSPORT_STATE_CHECKING ||
114 dtls_transport_state == RAWRTC_DTLS_TRANSPORT_STATE_CONNECTING) {
115 connection_state = RAWRTC_PEER_CONNECTION_STATE_CONNECTING;
116 goto out;
117 }
118
119 // Disconnected: Any in the 'disconnected' state
120 if (ice_transport_state == RAWRTC_ICE_TRANSPORT_STATE_DISCONNECTED) {
121 connection_state = RAWRTC_PEER_CONNECTION_STATE_DISCONNECTED;
122 goto out;
123 }
124
125 // New: Any in 'new' or all in 'closed'
126 if (ice_transport_state == RAWRTC_ICE_TRANSPORT_STATE_NEW ||
127 dtls_transport_state == RAWRTC_DTLS_TRANSPORT_STATE_NEW ||
128 (ice_transport_state == RAWRTC_ICE_TRANSPORT_STATE_CLOSED &&
129 dtls_transport_state == RAWRTC_DTLS_TRANSPORT_STATE_CLOSED)) {
130 connection_state = RAWRTC_PEER_CONNECTION_STATE_NEW;
131 goto out;
132 }
133
134 // Connected
135 connection_state = RAWRTC_PEER_CONNECTION_STATE_CONNECTED;
136
137out:
138 // Debug
139 DEBUG_PRINTF(
140 "ICE (%s) + DTLS (%s) = PC %s\n", rawrtc_ice_transport_state_to_name(ice_transport_state),
141 rawrtc_dtls_transport_state_to_name(dtls_transport_state),
142 rawrtc_peer_connection_state_to_name(connection_state));
143
144 // Check if the state would change
145 if (connection->connection_state == connection_state) {
146 return;
147 }
148
149 // Set state
150 connection->connection_state = connection_state;
151
152 // Call handler (if any)
153 if (connection->connection_state_change_handler) {
154 connection->connection_state_change_handler(connection_state, connection->arg);
155 }
156}
157
158/*
159 * Start the SCTP transport.
160 */
161static enum rawrtc_code sctp_transport_start(
162 struct rawrtc_sctp_transport* const sctp_transport, // not checked
163 struct rawrtc_peer_connection* const connection, // not checked
164 struct rawrtc_peer_connection_description* const description // not checked
165) {
166 enum rawrtc_code error;
167
168 // Start SCTP transport
169 error = rawrtc_sctp_transport_start(
170 sctp_transport, description->sctp_capabilities, description->sctp_port);
171 if (error) {
172 return error;
173 }
174
175 // Set MTU (if necessary)
176 if (connection->configuration->sctp.mtu != 0) {
177 error = rawrtc_sctp_transport_set_mtu(sctp_transport, connection->configuration->sctp.mtu);
178 if (error) {
179 return error;
180 }
181 }
182
183 // Enable path MTU discovery (if necessary)
184 if (connection->configuration->sctp.mtu_discovery) {
185 error = rawrtc_sctp_transport_enable_mtu_discovery(sctp_transport);
186 if (error) {
187 return error;
188 }
189 }
190
191 // Done
192 return RAWRTC_CODE_SUCCESS;
193}
194
195/*
196 * All the nasty SDP stuff has been done. Fire it all up - YAY!
197 */
198static enum rawrtc_code peer_connection_start(
199 struct rawrtc_peer_connection* const connection // not checked
200) {
201 enum rawrtc_code error;
202 struct rawrtc_peer_connection_context* const context = &connection->context;
203 struct rawrtc_peer_connection_description* description;
204 enum rawrtc_ice_role ice_role;
205 enum rawrtc_data_transport_type data_transport_type;
206 void* data_transport;
207 struct le* le;
208
209 // Check if it's too early to start
210 if (!connection->local_description || !connection->remote_description) {
211 return RAWRTC_CODE_NO_VALUE;
212 }
213
214 DEBUG_INFO("Local and remote description set, starting transports\n");
215 description = connection->remote_description;
216
217 // Determine ICE role
218 // TODO: Is this correct?
219 switch (description->type) {
220 case RAWRTC_SDP_TYPE_OFFER:
221 ice_role = RAWRTC_ICE_ROLE_CONTROLLED;
222 break;
223 case RAWRTC_SDP_TYPE_ANSWER:
224 ice_role = RAWRTC_ICE_ROLE_CONTROLLING;
225 break;
226 default:
227 DEBUG_WARNING(
228 "Cannot determine ICE role from SDP type %s, report this!\n",
229 rawrtc_sdp_type_to_str(description->type));
230 return RAWRTC_CODE_UNKNOWN_ERROR;
231 }
232
233 // Start ICE transport
234 error = rawrtc_ice_transport_start(
235 context->ice_transport, context->ice_gatherer, description->ice_parameters, ice_role);
236 if (error) {
237 return error;
238 }
239
240 // Get data transport
241 error = rawrtc_data_transport_get_transport(
242 &data_transport_type, &data_transport, context->data_transport);
243 if (error) {
244 return error;
245 }
246
247 // Start data transport
248 switch (data_transport_type) {
249 case RAWRTC_DATA_TRANSPORT_TYPE_SCTP: {
250 // Start DTLS transport
251 error =
252 rawrtc_dtls_transport_start(context->dtls_transport, description->dtls_parameters);
253 if (error) {
254 goto out;
255 }
256
257 // Start SCTP transport
258 error = sctp_transport_start(data_transport, connection, description);
259 if (error) {
260 goto out;
261 }
262 break;
263 }
264 default:
265 DEBUG_WARNING(
266 "Invalid data transport type: %s\n",
267 rawrtc_data_transport_type_to_str(data_transport_type));
268 error = RAWRTC_CODE_UNSUPPORTED_PROTOCOL;
269 goto out;
270 }
271
272 // Add remote ICE candidates
273 for (le = list_head(&description->ice_candidates); le != NULL; le = le->next) {
274 struct rawrtc_peer_connection_ice_candidate* const candidate = le->data;
275 error = rawrtc_peer_connection_add_ice_candidate(connection, candidate);
276 if (error) {
277 DEBUG_WARNING(
278 "Unable to add remote candidate, reason: %s\n", rawrtc_code_to_str(error));
279 // Note: Continuing here since other candidates may work
280 }
281 }
282
283 // Done
284 error = RAWRTC_CODE_SUCCESS;
285
286out:
287 mem_deref(data_transport);
288 return error;
289}
290
291/*
292 * Remove all instances that have been created which are not
293 * associated to the peer connection.
294 */
295static void revert_context(
296 struct rawrtc_peer_connection_context* const new, // not checked
297 struct rawrtc_peer_connection_context* const current // not checked
298) {
299 if (new->data_transport != current->data_transport) {
300 mem_deref(new->data_transport);
301 }
302 if (new->dtls_transport != current->dtls_transport) {
303 mem_deref(new->dtls_transport);
304 }
305 // TODO: This check is brittle...
306 if (!list_isempty(&new->certificates) && list_isempty(&current->certificates)) {
307 list_flush(&new->certificates);
308 }
309 if (new->ice_transport != current->ice_transport) {
310 mem_deref(new->ice_transport);
311 }
312 if (new->ice_gatherer != current->ice_gatherer) {
313 mem_deref(new->ice_gatherer);
314 }
315 if (new->gather_options != current->gather_options) {
316 mem_deref(new->gather_options);
317 }
318}
319
320/*
321 * Apply all instances on a peer connection.
322 * Return if anything inside the context has changed.
323 */
324static bool apply_context(
325 struct rawrtc_peer_connection_context* const new, // not checked
326 struct rawrtc_peer_connection_context* const current // not checked
327) {
328 bool changed = false;
329 if (new->data_transport != current->data_transport) {
330 current->data_transport = new->data_transport;
331 changed = true;
332 }
333 if (new->dtls_transport != current->dtls_transport) {
334 current->dtls_transport = new->dtls_transport;
335 str_ncpy(current->dtls_id, new->dtls_id, RAWRTC_DTLS_ID_LENGTH + 1);
336 changed = true;
337 }
338 // TODO: This check is brittle...
339 if (!list_isempty(&new->certificates) && list_isempty(&current->certificates)) {
340 current->certificates = new->certificates;
341 changed = true;
342 }
343 if (new->ice_transport != current->ice_transport) {
344 current->ice_transport = new->ice_transport;
345 changed = true;
346 }
347 if (new->ice_gatherer != current->ice_gatherer) {
348 current->ice_gatherer = new->ice_gatherer;
349 changed = true;
350 }
351 if (new->gather_options != current->gather_options) {
352 current->gather_options = new->gather_options;
353 changed = true;
354 }
355 return changed;
356}
357
358/*
359 * Wrap an ORTC ICE candidate to a peer connection ICE candidate.
360 */
361static enum rawrtc_code local_ortc_candidate_to_candidate(
362 struct rawrtc_peer_connection_ice_candidate** const candidatep, // de-referenced, not checked
363 struct rawrtc_ice_candidate* const ortc_candidate, // not checked
364 struct rawrtc_peer_connection* const connection // not checked
365) {
366 enum rawrtc_code error;
367 char* username_fragment;
368 struct rawrtc_peer_connection_ice_candidate* candidate;
369
370 // Copy username fragment (is going to be referenced later)
371 error =
372 rawrtc_strdup(&username_fragment, connection->context.ice_gatherer->ice_username_fragment);
373 if (error) {
374 DEBUG_WARNING(
375 "Unable to copy username fragment from ICE gatherer, reason: %s\n",
376 rawrtc_code_to_str(error));
377 return error;
378 }
379
380 // Create candidate
381 // Note: The local description will exist at this point since we start gathering when the
382 // local description is being set.
383 error = rawrtc_peer_connection_ice_candidate_from_ortc_candidate(
384 &candidate, ortc_candidate, connection->local_description->mid,
385 &connection->local_description->media_line_index, username_fragment);
386 if (error) {
387 goto out;
388 }
389
390 // Set pointer & done
391 *candidatep = candidate;
392 error = RAWRTC_CODE_SUCCESS;
393
394out:
395 // Un-reference
396 mem_deref(username_fragment);
397 return error;
398}
399
400/*
401 * Add candidate to description and announce candidate.
402 */
403static void ice_gatherer_local_candidate_handler(
404 struct rawrtc_ice_candidate* const ortc_candidate, // nullable
405 char const* const url, // nullable
406 void* const arg) {
407 struct rawrtc_peer_connection* const connection = arg;
408 enum rawrtc_code error;
409 struct rawrtc_peer_connection_ice_candidate* candidate = NULL;
410
411 // Check state
412 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_FAILED ||
413 connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
414 DEBUG_NOTICE(
415 "Ignoring candidate in the %s state\n",
416 rawrtc_peer_connection_state_to_name(connection->connection_state));
417 return;
418 }
419
420 // Wrap candidate (if any ORTC candidate)
421 if (ortc_candidate) {
422 error = local_ortc_candidate_to_candidate(&candidate, ortc_candidate, connection);
423 if (error) {
424 DEBUG_WARNING(
425 "Unable to create local candidate from ORTC candidate, reason: %s\n",
426 rawrtc_code_to_str(error));
427 return;
428 }
429 }
430
431 // Add candidate (or end-of-candidate) to description
432 error =
433 rawrtc_peer_connection_description_add_candidate(connection->local_description, candidate);
434 if (error) {
435 DEBUG_WARNING(
436 "Unable to add local candidate to local description, reason: %s\n",
437 rawrtc_code_to_str(error));
438 goto out;
439 }
440
441 // Call handler (if any)
442 if (connection->local_candidate_handler) {
443 connection->local_candidate_handler(candidate, url, connection->arg);
444 }
445
446out:
447 // Un-reference
448 mem_deref(candidate);
449}
450
451/*
452 * Announce ICE gatherer error as ICE candidate error.
453 */
454static void ice_gatherer_error_handler(
455 struct rawrtc_ice_candidate* const ortc_candidate, // nullable
456 char const* const url,
457 uint16_t const error_code,
458 char const* const error_text,
459 void* const arg) {
460 struct rawrtc_peer_connection* const connection = arg;
461 enum rawrtc_code error;
462 struct rawrtc_peer_connection_ice_candidate* candidate = NULL;
463
464 // Wrap candidate (if any ORTC candidate)
465 if (ortc_candidate) {
466 error = local_ortc_candidate_to_candidate(&candidate, ortc_candidate, connection);
467 if (error) {
468 DEBUG_WARNING(
469 "Unable to create local candidate from ORTC candidate, reason: %s\n",
470 rawrtc_code_to_str(error));
471 return;
472 }
473 }
474
475 // Call handler (if any)
476 if (connection->local_candidate_error_handler) {
477 connection->local_candidate_error_handler(
478 candidate, url, error_code, error_text, connection->arg);
479 }
480}
481
482/*
483 * Filter ICE gatherer state and announce it.
484 */
485static void ice_gatherer_state_change_handler(
486 enum rawrtc_ice_gatherer_state const state, void* const arg) {
487 struct rawrtc_peer_connection* const connection = arg;
488
489 // The only difference to the ORTC gatherer states is that there's no 'closed' state.
490 if (state == RAWRTC_ICE_GATHERER_STATE_CLOSED) {
491 return;
492 }
493
494 // Call handler (if any)
495 if (connection->ice_gathering_state_change_handler) {
496 connection->ice_gathering_state_change_handler(state, connection->arg);
497 }
498}
499
500/*
501 * Lazy-create an ICE gatherer.
502 */
503static enum rawrtc_code get_ice_gatherer(
504 struct rawrtc_peer_connection_context* const context, // not checked
505 struct rawrtc_peer_connection* const connection // not checked
506) {
507 enum rawrtc_code error;
508 struct rawrtc_ice_gather_options* options;
509 struct rawrtc_ice_gatherer* gatherer = NULL;
510 struct le* le;
511
512 // Already created?
513 if (context->ice_gatherer) {
514 return RAWRTC_CODE_SUCCESS;
515 }
516
517 // Create ICE gather options
518 error = rawrtc_ice_gather_options_create(&options, connection->configuration->gather_policy);
519 if (error) {
520 return error;
521 }
522
523 // Add ICE servers to gather options
524 for (le = list_head(&connection->configuration->ice_servers); le != NULL; le = le->next) {
525 struct rawrtc_ice_server* const source_server = le->data;
526 struct rawrtc_ice_server* server;
527
528 // Copy ICE server
529 error = rawrtc_ice_server_copy(&server, source_server);
530 if (error) {
531 goto out;
532 }
533
534 // Add ICE server to gather options
535 error = rawrtc_ice_gather_options_add_server_internal(options, server);
536 if (error) {
537 mem_deref(server);
538 goto out;
539 }
540 }
541
542 // Create ICE gatherer
543 error = rawrtc_ice_gatherer_create(
544 &gatherer, options, ice_gatherer_state_change_handler, ice_gatherer_error_handler,
545 ice_gatherer_local_candidate_handler, connection);
546 if (error) {
547 goto out;
548 }
549
550out:
551 if (error) {
552 mem_deref(gatherer);
553 mem_deref(options);
554 } else {
555 // Set pointers & done
556 context->gather_options = options;
557 context->ice_gatherer = gatherer;
558 }
559
560 return error;
561}
562
563static void ice_transport_candidate_pair_change_handler(
564 struct rawrtc_ice_candidate* const local, // read-only
565 struct rawrtc_ice_candidate* const remote, // read-only
566 void* const arg // will be casted to `struct client*`
567) {
568 (void) local;
569 (void) remote;
570 (void) arg;
571
572 // There's no handler that could potentially print this, so we print it here for debug purposes
573 DEBUG_PRINTF("ICE transport candidate pair change\n");
574}
575
576static void ice_transport_state_change_handler(
577 enum rawrtc_ice_transport_state const state, void* const arg) {
578 struct rawrtc_peer_connection* const connection = arg;
579
580 // Call handler (if any)
581 if (connection->ice_connection_state_change_handler) {
582 connection->ice_connection_state_change_handler(state, connection->arg);
583 }
584
585 // Update connection state
586 update_connection_state(connection);
587}
588
589/*
590 * Lazy-create an ICE transport.
591 */
592static enum rawrtc_code get_ice_transport(
593 struct rawrtc_peer_connection_context* const context, // not checked
594 struct rawrtc_peer_connection* const connection // not checked
595) {
596 enum rawrtc_code error;
597
598 // Already created?
599 if (context->ice_transport) {
600 return RAWRTC_CODE_SUCCESS;
601 }
602
603 // Get ICE gatherer
604 error = get_ice_gatherer(context, connection);
605 if (error) {
606 return error;
607 }
608
609 // Create ICE transport
610 return rawrtc_ice_transport_create(
611 &context->ice_transport, context->ice_gatherer, ice_transport_state_change_handler,
612 ice_transport_candidate_pair_change_handler, connection);
613}
614
615/*
616 * Lazy-generate a certificate list.
617 */
618static enum rawrtc_code get_certificates(
619 struct rawrtc_peer_connection_context* const context, // not checked
620 struct rawrtc_peer_connection_configuration* const configuration // not checked
621) {
622 enum rawrtc_code error;
623 struct rawrtc_certificate* certificate;
624
625 // Already created?
626 if (!list_isempty(&context->certificates)) {
627 return RAWRTC_CODE_SUCCESS;
628 }
629
630 // Certificates in the configuration? Copy them.
631 if (!list_isempty(&configuration->certificates)) {
632 return rawrtc_certificate_list_copy(&context->certificates, &configuration->certificates);
633 }
634
635 // Generate a certificate
636 error = rawrtc_certificate_generate(&certificate, NULL);
637 if (error) {
638 return error;
639 }
640
641 // Add certificate to the list
642 list_append(&context->certificates, &certificate->le, certificate);
643 return RAWRTC_CODE_SUCCESS;
644}
645
646static void dtls_transport_error_handler(
647 // TODO: error.message (probably from OpenSSL)
648 void* const arg) {
649 (void) arg;
650 // TODO: Print error message
651 DEBUG_WARNING("DTLS transport error: %s\n", "???");
652}
653
654static void dtls_transport_state_change_handler(
655 enum rawrtc_dtls_transport_state const state, void* const arg) {
656 struct rawrtc_peer_connection* connection = arg;
657 (void) state;
658
659 // Update connection state
660 update_connection_state(connection);
661}
662
663/*
664 * Lazy-create a DTLS transport.
665 */
666static enum rawrtc_code get_dtls_transport(
667 struct rawrtc_peer_connection_context* const context, // not checked
668 struct rawrtc_peer_connection* const connection // not checked
669) {
670 enum rawrtc_code error;
671 struct list certificates = LIST_INIT;
672
673 // Already created?
674 if (context->dtls_transport) {
675 return RAWRTC_CODE_SUCCESS;
676 }
677
678 // Get ICE transport
679 error = get_ice_transport(context, connection);
680 if (error) {
681 return error;
682 }
683
684 // Get certificates
685 error = get_certificates(context, connection->configuration);
686 if (error) {
687 return error;
688 }
689
690 // Copy certificates list
691 error = rawrtc_certificate_list_copy(&certificates, &context->certificates);
692 if (error) {
693 return error;
694 }
695
696 // Generate random DTLS ID
697 rand_str(context->dtls_id, sizeof(context->dtls_id));
698
699 // Create DTLS transport
700 return rawrtc_dtls_transport_create_internal(
701 &context->dtls_transport, context->ice_transport, &certificates,
702 dtls_transport_state_change_handler, dtls_transport_error_handler, connection);
703}
704
705static void sctp_transport_state_change_handler(
706 enum rawrtc_sctp_transport_state const state, void* const arg) {
707 (void) arg;
708 (void) state;
709
710 // There's no handler that could potentially print this, so we print it here for debug purposes
711 DEBUG_PRINTF("SCTP transport state change: %s\n", rawrtc_sctp_transport_state_to_name(state));
712}
713
714/*
715 * Lazy-create an SCTP transport.
716 */
717static enum rawrtc_code get_sctp_transport(
718 struct rawrtc_peer_connection_context* const context, // not checked
719 struct rawrtc_peer_connection* const connection // not checked
720) {
721 enum rawrtc_code error;
722 struct rawrtc_sctp_transport* sctp_transport;
723
724 // Get DTLS transport
725 error = get_dtls_transport(context, connection);
726 if (error) {
727 return error;
728 }
729
730 // Create SCTP transport
731 error = rawrtc_sctp_transport_create(
732 &sctp_transport, context->dtls_transport, RAWRTC_PEER_CONNECTION_SCTP_TRANSPORT_PORT,
733 connection->data_channel_handler, sctp_transport_state_change_handler, connection->arg);
734 if (error) {
735 return error;
736 }
737
738 // Set send/receive buffer length (if necessary)
739 if (connection->configuration->sctp.send_buffer_length != 0 &&
740 connection->configuration->sctp.receive_buffer_length != 0) {
741 error = rawrtc_sctp_transport_set_buffer_length(
742 sctp_transport, connection->configuration->sctp.send_buffer_length,
743 connection->configuration->sctp.receive_buffer_length);
744 if (error) {
745 goto out;
746 }
747 }
748
749 // Set congestion control algorithm (if necessary)
750 if (connection->configuration->sctp.congestion_ctrl_algorithm !=
751 RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_RFC2581) {
752 error = rawrtc_sctp_transport_set_congestion_ctrl_algorithm(
753 sctp_transport, connection->configuration->sctp.congestion_ctrl_algorithm);
754 if (error) {
755 goto out;
756 }
757 }
758
759 // Get data transport
760 error = rawrtc_sctp_transport_get_data_transport(&context->data_transport, sctp_transport);
761 if (error) {
762 goto out;
763 }
764
765out:
766 // Un-reference
767 // Note: As the data transport has a reference to the SCTP transport, we can
768 // still retrieve the reference later.
769 mem_deref(sctp_transport);
770 return error;
771}
772
773/*
774 * Lazy-create the requested data transport.
775 */
776static enum rawrtc_code get_data_transport(
777 struct rawrtc_peer_connection_context* const context, // not checked
778 struct rawrtc_peer_connection* const connection // not checked
779) {
780 // Already created?
781 if (context->data_transport) {
782 return RAWRTC_CODE_SUCCESS;
783 }
784
785 // Create data transport depending on what we want to have
786 switch (connection->data_transport_type) {
787 case RAWRTC_DATA_TRANSPORT_TYPE_SCTP: {
788 return get_sctp_transport(context, connection);
789 }
790 default:
791 return RAWRTC_CODE_NOT_IMPLEMENTED;
792 }
793}
794
795/*
796 * Destructor for an existing peer connection.
797 */
798static void rawrtc_peer_connection_destroy(void* arg) {
799 struct rawrtc_peer_connection* const connection = arg;
800
801 // Unset all handlers
802 rawrtc_peer_connection_unset_handlers(connection);
803
804 // Close peer connection
805 rawrtc_peer_connection_close(connection);
806
807 // Un-reference
808 mem_deref(connection->context.data_transport);
809 mem_deref(connection->context.dtls_transport);
810 list_flush(&connection->context.certificates);
811 mem_deref(connection->context.ice_transport);
812 mem_deref(connection->context.ice_gatherer);
813 mem_deref(connection->context.gather_options);
814 mem_deref(connection->remote_description);
815 mem_deref(connection->local_description);
816 mem_deref(connection->configuration);
817}
818
819/*
820 * Create a new peer connection.
821 * `*connectionp` must be unreferenced.
822 */
823enum rawrtc_code rawrtc_peer_connection_create(
824 struct rawrtc_peer_connection** const connectionp, // de-referenced
825 struct rawrtc_peer_connection_configuration* configuration, // referenced
826 rawrtc_negotiation_needed_handler const negotiation_needed_handler, // nullable
827 rawrtc_peer_connection_local_candidate_handler const local_candidate_handler, // nullable
828 rawrtc_peer_connection_local_candidate_error_handler const
829 local_candidate_error_handler, // nullable
830 rawrtc_signaling_state_change_handler const signaling_state_change_handler, // nullable
831 rawrtc_ice_transport_state_change_handler const
832 ice_connection_state_change_handler, // nullable
833 rawrtc_ice_gatherer_state_change_handler const ice_gathering_state_change_handler, // nullable
834 rawrtc_peer_connection_state_change_handler const connection_state_change_handler, // nullable
835 rawrtc_data_channel_handler const data_channel_handler, // nullable
836 void* const arg // nullable
837) {
838 struct rawrtc_peer_connection* connection;
839
840 // Check arguments
841 if (!connectionp) {
842 return RAWRTC_CODE_INVALID_ARGUMENT;
843 }
844
845 // Allocate
846 connection = mem_zalloc(sizeof(*connection), rawrtc_peer_connection_destroy);
847 if (!connection) {
848 return RAWRTC_CODE_NO_MEMORY;
849 }
850
851 // Set fields/reference
852 connection->connection_state = RAWRTC_PEER_CONNECTION_STATE_NEW;
853 connection->signaling_state = RAWRTC_SIGNALING_STATE_STABLE;
854 connection->configuration = mem_ref(configuration);
855 connection->negotiation_needed_handler = negotiation_needed_handler;
856 connection->local_candidate_handler = local_candidate_handler;
857 connection->local_candidate_error_handler = local_candidate_error_handler;
858 connection->signaling_state_change_handler = signaling_state_change_handler;
859 connection->ice_connection_state_change_handler = ice_connection_state_change_handler;
860 connection->ice_gathering_state_change_handler = ice_gathering_state_change_handler;
861 connection->connection_state_change_handler = connection_state_change_handler;
862 connection->data_channel_handler = data_channel_handler;
863 connection->data_transport_type = RAWRTC_DATA_TRANSPORT_TYPE_SCTP;
864 connection->arg = arg;
865
866 // Set pointer & done
867 *connectionp = connection;
868 return RAWRTC_CODE_SUCCESS;
869}
870
871/*
872 * Close the peer connection. This will stop all underlying transports
873 * and results in a final 'closed' state.
874 */
875enum rawrtc_code rawrtc_peer_connection_close(struct rawrtc_peer_connection* const connection) {
876 enum rawrtc_code error;
877
878 // Check arguments
879 if (!connection) {
880 return RAWRTC_CODE_INVALID_ARGUMENT;
881 }
882
883 // Check state
884 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
885 return RAWRTC_CODE_SUCCESS;
886 }
887
888 // Update signalling & connection state
889 // Note: We need to do this early or the 'closed' states when tearing down the transports may
890 // lead to surprising peer connection states such as 'connected' at the very end.
891 set_signaling_state(connection, RAWRTC_SIGNALING_STATE_CLOSED);
892 set_connection_state(connection, RAWRTC_PEER_CONNECTION_STATE_CLOSED);
893
894 // Stop data transport (if any)
895 if (connection->context.data_transport) {
896 enum rawrtc_data_transport_type data_transport_type;
897 void* data_transport;
898
899 // Get data transport
900 error = rawrtc_data_transport_get_transport(
901 &data_transport_type, &data_transport, connection->context.data_transport);
902 if (error) {
903 DEBUG_WARNING("Unable to get data transport, reason: %s\n", rawrtc_code_to_str(error));
904 } else {
905 // Stop transport
906 switch (data_transport_type) {
907 case RAWRTC_DATA_TRANSPORT_TYPE_SCTP: {
908 struct rawrtc_sctp_transport* const sctp_transport = data_transport;
909 error = rawrtc_sctp_transport_stop(sctp_transport);
910 if (error) {
911 DEBUG_WARNING(
912 "Unable to stop SCTP transport, reason: %s\n",
913 rawrtc_code_to_str(error));
914 }
915 break;
916 }
917 default:
918 DEBUG_WARNING(
919 "Invalid data transport type: %s\n",
920 rawrtc_data_transport_type_to_str(data_transport_type));
921 break;
922 }
923
924 // Un-reference
925 mem_deref(data_transport);
926 }
927 }
928
929 // Stop DTLS transport (if any)
930 if (connection->context.dtls_transport) {
931 error = rawrtc_dtls_transport_stop(connection->context.dtls_transport);
932 if (error) {
933 DEBUG_WARNING("Unable to stop DTLS transport, reason: %s\n", rawrtc_code_to_str(error));
934 }
935 }
936
937 // Stop ICE transport (if any)
938 if (connection->context.ice_transport) {
939 error = rawrtc_ice_transport_stop(connection->context.ice_transport);
940 if (error) {
941 DEBUG_WARNING("Unable to stop ICE transport, reason: %s\n", rawrtc_code_to_str(error));
942 }
943 }
944
945 // Close ICE gatherer (if any)
946 if (connection->context.ice_gatherer) {
947 error = rawrtc_ice_gatherer_close(connection->context.ice_gatherer);
948 if (error) {
949 DEBUG_WARNING("Unable to close ICE gatherer, reason: %s\n", rawrtc_code_to_str(error));
950 }
951 }
952
953 // Done
954 return RAWRTC_CODE_SUCCESS;
955}
956
957/*
958 * Create an offer.
959 * `*descriptionp` must be unreferenced.
960 */
961enum rawrtc_code rawrtc_peer_connection_create_offer(
962 struct rawrtc_peer_connection_description** const descriptionp, // de-referenced
963 struct rawrtc_peer_connection* const connection,
964 bool const ice_restart) {
965 // Check arguments
966 if (!connection) {
967 return RAWRTC_CODE_INVALID_ARGUMENT;
968 }
969
970 // TODO: Support ICE restart
971 if (ice_restart) {
972 DEBUG_WARNING("ICE restart currently not supported\n");
973 return RAWRTC_CODE_NOT_IMPLEMENTED;
974 }
975
976 // Check state
977 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
978 return RAWRTC_CODE_INVALID_STATE;
979 }
980
981 // TODO: Allow subsequent offers
982 if (connection->local_description) {
983 return RAWRTC_CODE_NOT_IMPLEMENTED;
984 }
985
986 // Create description
987 return rawrtc_peer_connection_description_create_internal(descriptionp, connection, true);
988}
989
990/*
991 * Create an answer.
992 * `*descriptionp` must be unreferenced.
993 */
994enum rawrtc_code rawrtc_peer_connection_create_answer(
995 struct rawrtc_peer_connection_description** const descriptionp, // de-referenced
996 struct rawrtc_peer_connection* const connection) {
997 // Check arguments
998 if (!connection) {
999 return RAWRTC_CODE_INVALID_ARGUMENT;
1000 }
1001
1002 // Check state
1003 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
1004 return RAWRTC_CODE_INVALID_STATE;
1005 }
1006
1007 // TODO: Allow subsequent answers
1008 if (connection->local_description) {
1009 return RAWRTC_CODE_NOT_IMPLEMENTED;
1010 }
1011
1012 // Create description
1013 return rawrtc_peer_connection_description_create_internal(descriptionp, connection, false);
1014}
1015
1016/*
1017 * Set and apply the local description.
1018 */
1019enum rawrtc_code rawrtc_peer_connection_set_local_description(
1020 struct rawrtc_peer_connection* const connection,
1021 struct rawrtc_peer_connection_description* const description // referenced
1022) {
1023 bool initial_description = true;
1024 enum rawrtc_code error;
1025
1026 // Check arguments
1027 if (!connection || !description) {
1028 return RAWRTC_CODE_INVALID_ARGUMENT;
1029 }
1030
1031 // Check state
1032 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
1033 return RAWRTC_CODE_INVALID_STATE;
1034 }
1035
1036 // Ensure it has been created by the local peer connection.
1037 if (description->connection != connection) {
1038 // Yeah, sorry, nope, I'm not parsing all this SDP nonsense again just to check
1039 // what kind of nasty things could have been done in the meantime.
1040 return RAWRTC_CODE_INVALID_ARGUMENT;
1041 }
1042
1043 // TODO: Allow changing the local description
1044 if (connection->local_description) {
1045 initial_description = false;
1046 (void) initial_description;
1047 return RAWRTC_CODE_NOT_IMPLEMENTED;
1048 }
1049
1050 // We only accept 'offer' or 'answer' at the moment
1051 // TODO: Handle the other ones as well
1052 if (description->type != RAWRTC_SDP_TYPE_OFFER && description->type != RAWRTC_SDP_TYPE_ANSWER) {
1053 DEBUG_WARNING("Only 'offer' or 'answer' descriptions can be handled at the moment\n");
1054 return RAWRTC_CODE_NOT_IMPLEMENTED;
1055 }
1056
1057 // Check SDP type
1058 DEBUG_PRINTF(
1059 "Set local description: %s (local), %s (remote)\n",
1060 rawrtc_sdp_type_to_str(description->type),
1061 connection->remote_description
1062 ? rawrtc_sdp_type_to_str(connection->remote_description->type)
1063 : "n/a");
1064 if (connection->remote_description) {
1065 switch (description->type) {
1066 case RAWRTC_SDP_TYPE_OFFER:
1067 // We have a remote description and get an offer. This requires renegotiation we
1068 // currently don't support.
1069 // TODO: Add support for this
1070 DEBUG_WARNING("There's no support for renegotiation at the moment.\n");
1071 return RAWRTC_CODE_NOT_IMPLEMENTED;
1072 case RAWRTC_SDP_TYPE_ANSWER:
1073 // We have a remote description and get an answer. Sanity-check that the remote
1074 // description is an offer.
1075 if (connection->remote_description->type != RAWRTC_SDP_TYPE_OFFER) {
1076 DEBUG_WARNING(
1077 "Got 'answer' but remote description is '%s'\n",
1078 rawrtc_sdp_type_to_str(connection->remote_description->type));
1079 return RAWRTC_CODE_INVALID_STATE;
1080 }
1081 break;
1082 default:
1083 DEBUG_WARNING("Unknown SDP type, please report this!\n");
1084 return RAWRTC_CODE_UNKNOWN_ERROR;
1085 }
1086 } else {
1087 switch (description->type) {
1088 case RAWRTC_SDP_TYPE_OFFER:
1089 // We have no remote description and get an offer. Fine.
1090 break;
1091 case RAWRTC_SDP_TYPE_ANSWER:
1092 // We have no remote description and get an answer. Not going to work.
1093 DEBUG_WARNING("Got 'answer' but have no remote description\n");
1094 return RAWRTC_CODE_INVALID_STATE;
1095 default:
1096 DEBUG_WARNING("Unknown SDP type, please report this!\n");
1097 return RAWRTC_CODE_UNKNOWN_ERROR;
1098 }
1099 }
1100
1101 // Remove reference to self
1102 description->connection = mem_deref(description->connection);
1103
1104 // Set local description
1105 connection->local_description = mem_ref(description);
1106
1107 // Start gathering (if initial description)
1108 if (initial_description) {
1109 error = rawrtc_ice_gatherer_gather(connection->context.ice_gatherer, NULL);
1110 if (error) {
1111 DEBUG_WARNING("Unable to start gathering, reason: %s\n", rawrtc_code_to_str(error));
1112 return error;
1113 }
1114 }
1115
1116 // Start peer connection if both description are set
1117 error = peer_connection_start(connection);
1118 if (error && error != RAWRTC_CODE_NO_VALUE) {
1119 DEBUG_WARNING("Unable to start peer connection, reason: %s\n", rawrtc_code_to_str(error));
1120 return error;
1121 }
1122
1123 // Update signalling state
1124 switch (connection->signaling_state) {
1125 case RAWRTC_SIGNALING_STATE_STABLE:
1126 // Can only be an offer or it would not have been accepted
1127 set_signaling_state(connection, RAWRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER);
1128 break;
1129 case RAWRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER:
1130 // Update of the local offer, nothing to do
1131 break;
1132 case RAWRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER:
1133 // Can only be an answer or it would not have been accepted
1134 // Note: This may change once we accept PR answers
1135 set_signaling_state(connection, RAWRTC_SIGNALING_STATE_STABLE);
1136 break;
1137 case RAWRTC_SIGNALING_STATE_HAVE_LOCAL_PROVISIONAL_ANSWER:
1138 // Impossible state
1139 // Note: This may change once we accept PR answers
1140 break;
1141 case RAWRTC_SIGNALING_STATE_HAVE_REMOTE_PROVISIONAL_ANSWER:
1142 // Impossible state
1143 // Note: This may change once we accept PR answers
1144 break;
1145 case RAWRTC_SIGNALING_STATE_CLOSED:
1146 // Impossible state
1147 break;
1148 }
1149
1150 // Done
1151 return RAWRTC_CODE_SUCCESS;
1152}
1153
1154/*
1155 * Set and apply the remote description.
1156 */
1157enum rawrtc_code rawrtc_peer_connection_set_remote_description(
1158 struct rawrtc_peer_connection* const connection,
1159 struct rawrtc_peer_connection_description* const description // referenced
1160) {
1161 enum rawrtc_code error;
1162 struct rawrtc_peer_connection_context context;
1163
1164 // Check arguments
1165 if (!connection || !description) {
1166 return RAWRTC_CODE_INVALID_ARGUMENT;
1167 }
1168
1169 // Check state
1170 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
1171 return RAWRTC_CODE_INVALID_STATE;
1172 }
1173
1174 // TODO: Allow changing the remote description
1175 if (connection->remote_description) {
1176 return RAWRTC_CODE_NOT_IMPLEMENTED;
1177 }
1178
1179 // We only accept 'offer' or 'answer' at the moment
1180 // TODO: Handle the other ones as well
1181 if (description->type != RAWRTC_SDP_TYPE_OFFER && description->type != RAWRTC_SDP_TYPE_ANSWER) {
1182 DEBUG_WARNING("Only 'offer' or 'answer' descriptions can be handled at the moment\n");
1183 return RAWRTC_CODE_NOT_IMPLEMENTED;
1184 }
1185
1186 // Check SDP type
1187 DEBUG_PRINTF(
1188 "Set remote description: %s (local), %s (remote)\n",
1189 connection->local_description ? rawrtc_sdp_type_to_str(connection->local_description->type)
1190 : "n/a",
1191 rawrtc_sdp_type_to_str(description->type));
1192 if (connection->local_description) {
1193 switch (description->type) {
1194 case RAWRTC_SDP_TYPE_OFFER:
1195 // We have a local description and get an offer. This requires renegotiation we
1196 // currently don't support.
1197 // TODO: Add support for this
1198 DEBUG_WARNING("There's no support for renegotiation at the moment.\n");
1199 return RAWRTC_CODE_NOT_IMPLEMENTED;
1200 case RAWRTC_SDP_TYPE_ANSWER:
1201 // We have a local description and get an answer. Sanity-check that the local
1202 // description is an offer.
1203 if (connection->local_description->type != RAWRTC_SDP_TYPE_OFFER) {
1204 DEBUG_WARNING(
1205 "Got 'answer' but local description is '%s'\n",
1206 rawrtc_sdp_type_to_str(connection->local_description->type));
1207 return RAWRTC_CODE_INVALID_STATE;
1208 }
1209 break;
1210 default:
1211 DEBUG_WARNING("Unknown SDP type, please report this!\n");
1212 return RAWRTC_CODE_UNKNOWN_ERROR;
1213 }
1214 } else {
1215 switch (description->type) {
1216 case RAWRTC_SDP_TYPE_OFFER:
1217 // We have no local description and get an offer. Fine.
1218 break;
1219 case RAWRTC_SDP_TYPE_ANSWER:
1220 // We have no local description and get an answer. Not going to work.
1221 DEBUG_WARNING("Got 'answer' but have no local description\n");
1222 return RAWRTC_CODE_INVALID_STATE;
1223 default:
1224 DEBUG_WARNING("Unknown SDP type, please report this!\n");
1225 return RAWRTC_CODE_UNKNOWN_ERROR;
1226 }
1227 }
1228
1229 // No trickle ICE? Ensure we have all candidates
1230 if (!description->trickle_ice && !description->end_of_candidates) {
1231 DEBUG_NOTICE("No trickle ICE indicated but don't have all candidates\n");
1232 // Note: We continue since we still accept further candidates.
1233 }
1234
1235 // No remote media 'application' line?
1236 if (!description->remote_media_line) {
1237 DEBUG_WARNING("No remote media 'application' line for data channels found\n");
1238 return RAWRTC_CODE_INVALID_ARGUMENT;
1239 }
1240
1241 // No ICE parameters?
1242 // Note: We either have valid ICE parameters or none at this point
1243 if (!description->ice_parameters) {
1244 DEBUG_WARNING("Required ICE parameters not present\n");
1245 return RAWRTC_CODE_INVALID_ARGUMENT;
1246 }
1247
1248 // No DTLS parameters?
1249 // Note: We either have valid DTLS parameters or none at this point
1250 if (!description->dtls_parameters) {
1251 DEBUG_WARNING("Required DTLS parameters not present\n");
1252 return RAWRTC_CODE_INVALID_ARGUMENT;
1253 }
1254
1255 // No SCTP capabilities or port?
1256 // Note: We either have valid SCTP capabilities or none at this point
1257 if (!description->sctp_capabilities) {
1258 DEBUG_WARNING("Required SCTP capabilities not present\n");
1259 return RAWRTC_CODE_INVALID_ARGUMENT;
1260 }
1261 if (description->sctp_port == 0) {
1262 DEBUG_WARNING("Invalid SCTP port (0)\n");
1263 return RAWRTC_CODE_INVALID_ARGUMENT;
1264 }
1265
1266 // Set remote description
1267 connection->remote_description = mem_ref(description);
1268
1269 // Initialise context
1270 context = connection->context;
1271
1272 // Create a data transport if we're answering
1273 if (description->type == RAWRTC_SDP_TYPE_OFFER) {
1274 // Get data transport
1275 error = get_data_transport(&context, connection);
1276 if (error) {
1277 DEBUG_WARNING(
1278 "Unable to create data transport, reason: %s\n", rawrtc_code_to_str(error));
1279 return error;
1280 }
1281
1282 // Apply context
1283 apply_context(&context, &connection->context);
1284 }
1285
1286 // Start peer connection if both descriptions are set
1287 error = peer_connection_start(connection);
1288 if (error && error != RAWRTC_CODE_NO_VALUE) {
1289 DEBUG_WARNING("Unable to start peer connection, reason: %s\n", rawrtc_code_to_str(error));
1290 return error;
1291 }
1292
1293 // Update signalling state
1294 switch (connection->signaling_state) {
1295 case RAWRTC_SIGNALING_STATE_STABLE:
1296 // Can only be an offer or it would not have been accepted
1297 set_signaling_state(connection, RAWRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER);
1298 break;
1299 case RAWRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER:
1300 // Can only be an answer or it would not have been accepted
1301 // Note: This may change once we accept PR answers
1302 set_signaling_state(connection, RAWRTC_SIGNALING_STATE_STABLE);
1303 break;
1304 case RAWRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER:
1305 // Update of the remote offer, nothing to do
1306 break;
1307 case RAWRTC_SIGNALING_STATE_HAVE_LOCAL_PROVISIONAL_ANSWER:
1308 // Impossible state
1309 // Note: This may change once we accept PR answers
1310 break;
1311 case RAWRTC_SIGNALING_STATE_HAVE_REMOTE_PROVISIONAL_ANSWER:
1312 // Impossible state
1313 // Note: This may change once we accept PR answers
1314 break;
1315 case RAWRTC_SIGNALING_STATE_CLOSED:
1316 // Impossible state
1317 break;
1318 }
1319
1320 // Done
1321 return RAWRTC_CODE_SUCCESS;
1322}
1323
1324/*
1325 * Add an ICE candidate to the peer connection.
1326 */
1327enum rawrtc_code rawrtc_peer_connection_add_ice_candidate(
1328 struct rawrtc_peer_connection* const connection,
1329 struct rawrtc_peer_connection_ice_candidate* const candidate) {
1330 enum rawrtc_code error;
1331 struct rawrtc_peer_connection_description* description;
1332
1333 // Check arguments
1334 if (!connection || !candidate) {
1335 return RAWRTC_CODE_INVALID_ARGUMENT;
1336 }
1337
1338 // Check state
1339 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
1340 return RAWRTC_CODE_INVALID_STATE;
1341 }
1342
1343 // Ensure there's a remote description
1344 description = connection->remote_description;
1345 if (!description) {
1346 return RAWRTC_CODE_INVALID_STATE;
1347 }
1348
1349 // Note: We can be sure that either 'mid' or the media line index is present at this point.
1350
1351 // Check if the 'mid' matches (if any)
1352 // TODO: Once we support further media lines, we need to look up the appropriate transport here
1353 if (candidate->mid && description->mid && str_cmp(candidate->mid, description->mid) != 0) {
1354 DEBUG_WARNING("No matching 'mid' in remote description\n");
1355 return RAWRTC_CODE_INVALID_ARGUMENT;
1356 }
1357
1358 // Check if the media line index matches (if any)
1359 if (candidate->media_line_index >= 0 && candidate->media_line_index <= UINT8_MAX &&
1360 ((uint8_t) candidate->media_line_index) != description->media_line_index) {
1361 DEBUG_WARNING("No matching media line index in remote description\n");
1362 return RAWRTC_CODE_INVALID_ARGUMENT;
1363 }
1364
1365 // Check if the username fragment matches (if any)
1366 // TODO: This would need to be done across ICE generations
1367 if (candidate->username_fragment) {
1368 char* username_fragment;
1369 bool matching;
1370
1371 // Get username fragment from the remote ICE parameters
1372 error = rawrtc_ice_parameters_get_username_fragment(
1373 &username_fragment, description->ice_parameters);
1374 if (error) {
1375 DEBUG_WARNING(
1376 "Unable to retrieve username fragment, reason: %s\n", rawrtc_code_to_str(error));
1377 return error;
1378 }
1379
1380 // Compare username fragments
1381 matching = str_cmp(candidate->username_fragment, username_fragment) == 0;
1382 mem_deref(username_fragment);
1383 if (!matching) {
1384 DEBUG_WARNING("Username fragments don't match\n");
1385 return RAWRTC_CODE_INVALID_ARGUMENT;
1386 }
1387 }
1388
1389 // Add ICE candidate
1390 return rawrtc_ice_transport_add_remote_candidate(
1391 connection->context.ice_transport, candidate->candidate);
1392}
1393
1394/*
1395 * Create a data channel on a peer connection.
1396 * `*channelp` must be unreferenced.
1397 */
1398enum rawrtc_code rawrtc_peer_connection_create_data_channel(
1399 struct rawrtc_data_channel** const channelp, // de-referenced
1400 struct rawrtc_peer_connection* const connection,
1401 struct rawrtc_data_channel_parameters* const parameters, // referenced
1402 rawrtc_data_channel_open_handler const open_handler, // nullable
1403 rawrtc_data_channel_buffered_amount_low_handler const buffered_amount_low_handler, // nullable
1404 rawrtc_data_channel_error_handler const error_handler, // nullable
1405 rawrtc_data_channel_close_handler const close_handler, // nullable
1406 rawrtc_data_channel_message_handler const message_handler, // nullable
1407 void* const arg // nullable
1408) {
1409 enum rawrtc_code error;
1410 struct rawrtc_peer_connection_context context;
1411 struct rawrtc_data_channel* channel = NULL;
1412
1413 // Check arguments
1414 if (!connection) {
1415 return RAWRTC_CODE_INVALID_ARGUMENT;
1416 }
1417
1418 // Check state
1419 if (connection->connection_state == RAWRTC_PEER_CONNECTION_STATE_CLOSED) {
1420 return RAWRTC_CODE_INVALID_STATE;
1421 }
1422
1423 // Initialise context
1424 context = connection->context;
1425
1426 // Get data transport (if no description has been set, yet)
1427 if (!connection->local_description && !connection->remote_description) {
1428 error = get_data_transport(&context, connection);
1429 if (error) {
1430 DEBUG_WARNING(
1431 "Unable to create data transport, reason: %s\n", rawrtc_code_to_str(error));
1432 return error;
1433 }
1434 }
1435
1436 // Create data channel
1437 // TODO: Fix data channel cannot be created before transports have been started
1438 error = rawrtc_data_channel_create(
1439 &channel, context.data_transport, parameters, open_handler, buffered_amount_low_handler,
1440 error_handler, close_handler, message_handler, arg);
1441 if (error) {
1442 goto out;
1443 }
1444
1445out:
1446 if (error) {
1447 // Un-reference
1448 mem_deref(channel);
1449
1450 // Remove all newly created instances
1451 revert_context(&context, &connection->context);
1452 } else {
1453 // Apply context
1454 bool const negotiation_needed = apply_context(&context, &connection->context);
1455
1456 // Set pointer
1457 *channelp = channel;
1458
1459 // Negotiation needed?
1460 if (negotiation_needed) {
1461 connection->negotiation_needed_handler(connection->arg);
1462 }
1463 }
1464 return error;
1465}