Squashed 'third_party/rawrtc/rawrtc/' content from commit aa3ae4b24
Change-Id: I38a655a4259b62f591334e90a1315bd4e7e4d8ec
git-subtree-dir: third_party/rawrtc/rawrtc
git-subtree-split: aa3ae4b247275cc6e69c30613b3a4ba7fdc82d1b
diff --git a/src/peer_connection_ice_candidate/attributes.c b/src/peer_connection_ice_candidate/attributes.c
new file mode 100644
index 0000000..eed0125
--- /dev/null
+++ b/src/peer_connection_ice_candidate/attributes.c
@@ -0,0 +1,220 @@
+#include "candidate.h"
+#include <rawrtc/ice_candidate.h>
+#include <rawrtc/peer_connection_ice_candidate.h>
+#include <rawrtcc/code.h>
+#include <rawrtcc/utils.h>
+#include <re.h>
+
+/*
+ * Encode the ICE candidate into SDP.
+ * `*sdpp` will be set to a copy of the SDP attribute that must be
+ * unreferenced.
+ *
+ * Note: This is equivalent to the `candidate` attribute of the W3C
+ * WebRTC specification's `RTCIceCandidateInit`.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_sdp(
+ char** const sdpp, // de-referenced
+ struct rawrtc_peer_connection_ice_candidate* const candidate) {
+ enum rawrtc_code error;
+ char* foundation = NULL;
+ uint16_t component_id = 1;
+ enum rawrtc_ice_protocol protocol;
+ char const* protocol_str;
+ uint32_t priority;
+ char* ip = NULL;
+ uint16_t port;
+ enum rawrtc_ice_candidate_type type;
+ char const* type_str;
+ struct mbuf* sdp = NULL;
+ char* related_address = NULL;
+ uint16_t related_port = 0;
+ enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
+ char const* tcp_type_str;
+
+ // Check arguments
+ if (!sdpp || !candidate) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Get values for mandatory fields
+ error = rawrtc_ice_candidate_get_foundation(&foundation, candidate->candidate);
+ if (error) {
+ goto out;
+ }
+ // TODO: Get component ID from candidate/gatherer/transport
+ error = rawrtc_ice_candidate_get_protocol(&protocol, candidate->candidate);
+ if (error) {
+ goto out;
+ }
+ error = rawrtc_ice_candidate_get_priority(&priority, candidate->candidate);
+ if (error) {
+ goto out;
+ }
+ error = rawrtc_ice_candidate_get_ip(&ip, candidate->candidate);
+ if (error) {
+ goto out;
+ }
+ error = rawrtc_ice_candidate_get_port(&port, candidate->candidate);
+ if (error) {
+ goto out;
+ }
+ error = rawrtc_ice_candidate_get_type(&type, candidate->candidate);
+ if (error) {
+ goto out;
+ }
+ error = rawrtc_ice_candidate_get_related_address(&related_address, candidate->candidate);
+ if (error && error != RAWRTC_CODE_NO_VALUE) {
+ goto out;
+ }
+ error = rawrtc_ice_candidate_get_related_port(&related_port, candidate->candidate);
+ if (error && error != RAWRTC_CODE_NO_VALUE) {
+ goto out;
+ }
+ protocol_str = rawrtc_ice_protocol_to_str(protocol);
+ type_str = rawrtc_ice_candidate_type_to_str(type);
+
+ // Initialise SDP attribute buffer
+ sdp = mbuf_alloc(RAWRTC_PEER_CONNECTION_CANDIDATE_DEFAULT_SIZE);
+ if (!sdp) {
+ error = RAWRTC_CODE_NO_MEMORY;
+ goto out;
+ }
+
+ // Encode candidate's mandatory fields
+ error = rawrtc_error_to_code(mbuf_printf(
+ sdp, "candidate:%s %" PRIu16 " %s %" PRIu32 " %s %" PRIu16 " typ %s", foundation,
+ component_id, protocol_str, priority, ip, port, type_str));
+ if (error) {
+ goto out;
+ }
+ if (related_address) {
+ error = rawrtc_error_to_code(mbuf_printf(sdp, " raddr %s", related_address));
+ if (error) {
+ goto out;
+ }
+ }
+ if (related_port > 0) {
+ error = rawrtc_error_to_code(mbuf_printf(sdp, " rport %" PRIu16, related_port));
+ if (error) {
+ goto out;
+ }
+ }
+
+ // Get value for 'tcptype' extension field and encode it (if available)
+ error = rawrtc_ice_candidate_get_tcp_type(&tcp_type, candidate->candidate);
+ switch (error) {
+ case RAWRTC_CODE_SUCCESS:
+ tcp_type_str = rawrtc_ice_tcp_candidate_type_to_str(tcp_type);
+ mbuf_printf(sdp, " tcptype %s", tcp_type_str);
+ break;
+ case RAWRTC_CODE_NO_VALUE:
+ break;
+ default:
+ goto out;
+ }
+
+ // Copy SDP attribute
+ error = rawrtc_sdprintf(sdpp, "%b", sdp->buf, sdp->end);
+ if (error) {
+ goto out;
+ }
+
+out:
+ // Un-reference
+ mem_deref(related_address);
+ mem_deref(sdp);
+ mem_deref(ip);
+ mem_deref(foundation);
+ return error;
+}
+
+/*
+ * Get the media stream identification tag the ICE candidate is
+ * associated to.
+ * `*midp` will be set to a copy of the candidate's mid and must be
+ * unreferenced.
+ *
+ * Return `RAWRTC_CODE_NO_VALUE` in case no 'mid' has been set.
+ * Otherwise, `RAWRTC_CODE_SUCCESS` will be returned and `*midp* must
+ * be unreferenced.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_sdp_mid(
+ char** const midp, // de-referenced
+ struct rawrtc_peer_connection_ice_candidate* const candidate) {
+ // Check arguments
+ if (!midp || !candidate) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Copy mid (if any)
+ if (candidate->mid) {
+ return rawrtc_strdup(midp, candidate->mid);
+ } else {
+ return RAWRTC_CODE_NO_VALUE;
+ }
+}
+
+/*
+ * Get the media stream line index the ICE candidate is associated to.
+ * Return `RAWRTC_CODE_NO_VALUE` in case no media line index has been
+ * set.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_sdp_media_line_index(
+ uint8_t* const media_line_index, // de-referenced
+ struct rawrtc_peer_connection_ice_candidate* const candidate) {
+ // Check arguments
+ if (!media_line_index || !candidate) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Set media line index (if any)
+ if (candidate->media_line_index >= 0 && candidate->media_line_index <= UINT8_MAX) {
+ *media_line_index = (uint8_t) candidate->media_line_index;
+ return RAWRTC_CODE_SUCCESS;
+ } else {
+ return RAWRTC_CODE_NO_VALUE;
+ }
+}
+
+/*
+ * Get the username fragment the ICE candidate is associated to.
+ * `*username_fragmentp` will be set to a copy of the candidate's
+ * username fragment and must be unreferenced.
+ *
+ * Return `RAWRTC_CODE_NO_VALUE` in case no username fragment has been
+ * set. Otherwise, `RAWRTC_CODE_SUCCESS` will be returned and
+ * `*username_fragmentp* must be unreferenced.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_username_fragment(
+ char** const username_fragmentp, // de-referenced
+ struct rawrtc_peer_connection_ice_candidate* const candidate) {
+ // Check arguments
+ if (!username_fragmentp || !candidate) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Copy username fragment (if any)
+ if (candidate->username_fragment) {
+ return rawrtc_strdup(username_fragmentp, candidate->username_fragment);
+ } else {
+ return RAWRTC_CODE_NO_VALUE;
+ }
+}
+
+/*
+ * Get the underlying ORTC ICE candidate from the ICE candidate.
+ * `*ortc_candidatep` must be unreferenced.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_ortc_candidate(
+ struct rawrtc_ice_candidate** const ortc_candidatep, // de-referenced
+ struct rawrtc_peer_connection_ice_candidate* const candidate) {
+ // Check arguments
+ if (!ortc_candidatep || !candidate) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Reference ORTC ICE candidate
+ *ortc_candidatep = mem_ref(candidate->candidate);
+ return RAWRTC_CODE_SUCCESS;
+}
diff --git a/src/peer_connection_ice_candidate/candidate.c b/src/peer_connection_ice_candidate/candidate.c
new file mode 100644
index 0000000..4f2c7fc
--- /dev/null
+++ b/src/peer_connection_ice_candidate/candidate.c
@@ -0,0 +1,252 @@
+#include "candidate.h"
+#include "../ice_candidate/candidate.h"
+#include <rawrtc/ice_candidate.h>
+#include <rawrtc/peer_connection_ice_candidate.h>
+#include <rawrtcc/code.h>
+#include <rawrtcc/utils.h>
+#include <re.h>
+
+static char const sdp_ice_candidate_regex[] =
+ "candidate:[^ ]+ [0-9]+ [^ ]+ [0-9]+ [^ ]+ [0-9]+ typ [^ ]+[^]*";
+static char const sdp_ice_candidate_related_address_regex[] = "[^]* raddr [^ ]+";
+static char const sdp_ice_candidate_related_port_regex[] = "[^]* rport [0-9]+";
+static char const sdp_ice_candidate_tcp_type_regex[] = "[^]* tcptype [^ ]+";
+
+/*
+ * Destructor for an existing peer connection.
+ */
+static void rawrtc_peer_connection_ice_candidate_destroy(void* arg) {
+ struct rawrtc_peer_connection_ice_candidate* const candidate = arg;
+
+ // Un-reference
+ mem_deref(candidate->username_fragment);
+ mem_deref(candidate->mid);
+ mem_deref(candidate->candidate);
+}
+
+/*
+ * Create a new ICE candidate from an existing (ORTC) ICE candidate.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_from_ortc_candidate(
+ struct rawrtc_peer_connection_ice_candidate** const candidatep, // de-referenced
+ struct rawrtc_ice_candidate* const ortc_candidate, // nullable
+ char* const mid, // nullable, referenced
+ uint8_t const* const media_line_index, // nullable, copied
+ char* const username_fragment // nullable, referenced
+) {
+ struct rawrtc_peer_connection_ice_candidate* candidate;
+
+ // Ensure either 'mid' or the media line index is present
+ if (!mid && !media_line_index) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Allocate
+ candidate = mem_zalloc(sizeof(*candidate), rawrtc_peer_connection_ice_candidate_destroy);
+ if (!candidate) {
+ return RAWRTC_CODE_NO_MEMORY;
+ }
+
+ // Set fields
+ candidate->candidate = mem_ref(ortc_candidate);
+ candidate->mid = mem_ref(mid);
+ candidate->media_line_index = (int16_t)(media_line_index ? *media_line_index : -1);
+ candidate->username_fragment = mem_ref(username_fragment);
+
+ // Set pointer & done
+ *candidatep = candidate;
+ return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Create a new ICE candidate from SDP (pl variant).
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_create_internal(
+ struct rawrtc_peer_connection_ice_candidate** const candidatep, // de-referenced
+ struct pl* const sdp,
+ char* const mid, // nullable, referenced
+ uint8_t const* const media_line_index, // nullable, copied
+ char* const username_fragment // nullable, referenced
+) {
+ enum rawrtc_code error;
+ struct pl optional;
+ uint32_t value_u32;
+
+ // Mandatory fields
+ struct pl foundation_pl;
+ struct pl component_id_pl;
+ struct pl protocol_pl;
+ struct pl priority_pl;
+ struct pl ip_pl;
+ struct pl port_pl;
+ struct pl type_pl;
+ uint32_t priority;
+ enum rawrtc_ice_protocol protocol;
+ uint16_t port;
+ enum rawrtc_ice_candidate_type type;
+
+ // Optional fields
+ struct pl related_address_pl = PL_INIT;
+ struct pl related_port_pl = PL_INIT;
+ struct pl tcp_type_pl = PL_INIT;
+ uint16_t related_port = 0;
+ enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
+
+ // (ORTC) ICE candidate
+ struct rawrtc_ice_candidate* ortc_candidate;
+
+ // ICE candidate
+ struct rawrtc_peer_connection_ice_candidate* candidate;
+
+ // Check arguments
+ if (!candidatep || !sdp) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Ensure either 'mid' or the media line index is present
+ if (!mid && !media_line_index) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ if (pl_isset(sdp)) {
+ // Get mandatory ICE candidate fields
+ if (re_regex(
+ sdp->p, sdp->l, sdp_ice_candidate_regex, &foundation_pl, &component_id_pl,
+ &protocol_pl, &priority_pl, &ip_pl, &port_pl, &type_pl, &optional)) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Get optional ICE candidate fields
+ re_regex(
+ optional.p, optional.l, sdp_ice_candidate_related_address_regex, NULL,
+ &related_address_pl);
+ re_regex(
+ optional.p, optional.l, sdp_ice_candidate_related_port_regex, NULL, &related_port_pl);
+ re_regex(optional.p, optional.l, sdp_ice_candidate_tcp_type_regex, NULL, &tcp_type_pl);
+
+ // Component ID
+ // TODO: Handle
+ (void) component_id_pl;
+
+ // Protocol
+ error = rawrtc_pl_to_ice_protocol(&protocol, &protocol_pl);
+ if (error) {
+ return error;
+ }
+
+ // Priority
+ priority = pl_u32(&priority_pl);
+
+ // Port
+ value_u32 = pl_u32(&port_pl);
+ if (value_u32 > UINT16_MAX) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+ port = (uint16_t) value_u32;
+
+ // Type
+ error = rawrtc_pl_to_ice_candidate_type(&type, &type_pl);
+ if (error) {
+ return error;
+ }
+
+ // Related port (if any)
+ if (pl_isset(&related_port_pl)) {
+ value_u32 = pl_u32(&related_port_pl);
+ if (value_u32 > UINT16_MAX) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+ related_port = (uint16_t) value_u32;
+ }
+
+ // TCP type (if any)
+ if (pl_isset(&tcp_type_pl)) {
+ error = rawrtc_pl_to_ice_tcp_candidate_type(&tcp_type, &tcp_type_pl);
+ if (error) {
+ return error;
+ }
+ }
+
+ // Create (ORTC) ICE candidate
+ error = rawrtc_ice_candidate_create_internal(
+ &ortc_candidate, &foundation_pl, priority, &ip_pl, protocol, port, type, tcp_type,
+ &related_address_pl, related_port);
+ if (error) {
+ return error;
+ }
+ } else {
+ ortc_candidate = NULL;
+ }
+
+ // Create ICE candidate
+ error = rawrtc_peer_connection_ice_candidate_from_ortc_candidate(
+ &candidate, ortc_candidate, mid, media_line_index, username_fragment);
+ if (error) {
+ goto out;
+ }
+
+out:
+ // Un-reference
+ mem_deref(ortc_candidate);
+ if (!error) {
+ // Set pointer & done
+ *candidatep = candidate;
+ }
+ return error;
+}
+
+/*
+ * Create a new ICE candidate from SDP.
+ * `*candidatesp` must be unreferenced.
+ *
+ * Note: This is equivalent to creating an `RTCIceCandidate` from an
+ * `RTCIceCandidateInit` instance in the W3C WebRTC
+ * specification.
+ */
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_create(
+ struct rawrtc_peer_connection_ice_candidate** const candidatep, // de-referenced
+ char* const sdp,
+ char* const mid, // nullable, copied
+ uint8_t const* const media_line_index, // nullable, copied
+ char* const username_fragment // nullable, copied
+) {
+ struct pl sdp_pl;
+ enum rawrtc_code error;
+ char* mid_copy = NULL;
+ char* username_fragment_copy = NULL;
+
+ // Check arguments (not checked in the internal function)
+ if (!sdp) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Convert SDP str to pl
+ pl_set_str(&sdp_pl, sdp);
+
+ // Copy arguments that will be referenced
+ if (mid) {
+ error = rawrtc_strdup(&mid_copy, mid);
+ if (error) {
+ goto out;
+ }
+ }
+ if (username_fragment) {
+ error = rawrtc_strdup(&username_fragment_copy, username_fragment);
+ if (error) {
+ goto out;
+ }
+ }
+
+ // Create ICE candidate
+ error = rawrtc_peer_connection_ice_candidate_create_internal(
+ candidatep, &sdp_pl, mid_copy, media_line_index, username_fragment_copy);
+ if (error) {
+ goto out;
+ }
+
+out:
+ // Un-reference
+ mem_deref(username_fragment_copy);
+ mem_deref(mid_copy);
+ return error;
+}
diff --git a/src/peer_connection_ice_candidate/candidate.h b/src/peer_connection_ice_candidate/candidate.h
new file mode 100644
index 0000000..6fbd828
--- /dev/null
+++ b/src/peer_connection_ice_candidate/candidate.h
@@ -0,0 +1,32 @@
+#pragma once
+#include <rawrtc.h>
+
+enum {
+ RAWRTC_PEER_CONNECTION_CANDIDATE_DEFAULT_SIZE = 256,
+};
+
+struct rawrtc_peer_connection_ice_candidate {
+ struct le le;
+ struct rawrtc_ice_candidate* candidate;
+ char* mid;
+ int16_t media_line_index;
+ char* username_fragment;
+};
+
+int rawrtc_peer_connection_ice_candidate_debug(
+ struct re_printf* const pf, struct rawrtc_peer_connection_ice_candidate* const candidate);
+
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_from_ortc_candidate(
+ struct rawrtc_peer_connection_ice_candidate** const candidatep, // de-referenced
+ struct rawrtc_ice_candidate* const ortc_candidate, // nullable
+ char* const mid, // nullable, referenced
+ uint8_t const* const media_line_index, // nullable, copied
+ char* const username_fragment // nullable, referenced
+);
+
+enum rawrtc_code rawrtc_peer_connection_ice_candidate_create_internal(
+ struct rawrtc_peer_connection_ice_candidate** const candidatep, // de-referenced
+ struct pl* const sdp,
+ char* const mid, // nullable
+ uint8_t const* const media_line_index, // nullable
+ char* const username_fragment);
diff --git a/src/peer_connection_ice_candidate/meson.build b/src/peer_connection_ice_candidate/meson.build
new file mode 100644
index 0000000..6ff3140
--- /dev/null
+++ b/src/peer_connection_ice_candidate/meson.build
@@ -0,0 +1,5 @@
+sources += files([
+ 'attributes.c',
+ 'candidate.c',
+ 'utils.c',
+])
diff --git a/src/peer_connection_ice_candidate/utils.c b/src/peer_connection_ice_candidate/utils.c
new file mode 100644
index 0000000..49cd11e
--- /dev/null
+++ b/src/peer_connection_ice_candidate/utils.c
@@ -0,0 +1,47 @@
+#include "candidate.h"
+#include "../ice_candidate/candidate.h"
+#include <rawrtcc/code.h>
+#include <re.h>
+
+/*
+ * Print debug information for an ICE candidate.
+ */
+int rawrtc_peer_connection_ice_candidate_debug(
+ struct re_printf* const pf, struct rawrtc_peer_connection_ice_candidate* const candidate) {
+ int err = 0;
+
+ // Check arguments
+ if (!candidate) {
+ return 0;
+ }
+
+ // ORTC ICE candidate
+ err |= re_hprintf(pf, "%H", rawrtc_ice_candidate_debug, candidate->candidate);
+
+ // Media line identification tag
+ err |= re_hprintf(pf, " mid=");
+ if (candidate->mid) {
+ err |= re_hprintf(pf, "\"%s\"\n", candidate->mid);
+ } else {
+ err |= re_hprintf(pf, "n/a\n");
+ }
+
+ // Media line index
+ err |= re_hprintf(pf, " media_line_index=");
+ if (candidate->media_line_index >= 0 && candidate->media_line_index <= UINT8_MAX) {
+ err |= re_hprintf(pf, "%" PRId16 "\n", candidate->media_line_index);
+ } else {
+ err |= re_hprintf(pf, "n/a\n");
+ }
+
+ // Username fragment
+ err |= re_hprintf(pf, " username_fragment=");
+ if (candidate->username_fragment) {
+ err |= re_hprintf(pf, "\"%s\"\n", candidate->username_fragment);
+ } else {
+ err |= re_hprintf(pf, "n/a\n");
+ }
+
+ // Done
+ return err;
+}