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;
+}