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/ice_candidate/helper.c b/src/ice_candidate/helper.c
new file mode 100644
index 0000000..ff74c71
--- /dev/null
+++ b/src/ice_candidate/helper.c
@@ -0,0 +1,209 @@
+#include "helper.h"
+#include "../ice_gatherer/gatherer.h"
+#include "../ice_server/server.h"
+#include <rawrtc/main.h>
+#include <rawrtcc/code.h>
+#include <rawrtcc/utils.h>
+#include <re.h>
+#include <rew.h>
+
+/*
+ * Destructor for an existing candidate helper.
+ */
+static void rawrtc_candidate_helper_destroy(void* arg) {
+    struct rawrtc_candidate_helper* const local_candidate = arg;
+
+    // Un-reference
+    list_flush(&local_candidate->stun_sessions);
+    mem_deref(local_candidate->udp_helper);
+    mem_deref(local_candidate->candidate);
+    mem_deref(local_candidate->gatherer);
+}
+
+/*
+ * Create a candidate helper.
+ */
+enum rawrtc_code rawrtc_candidate_helper_create(
+    struct rawrtc_candidate_helper** const candidate_helperp,  // de-referenced
+    struct rawrtc_ice_gatherer* gatherer,
+    struct ice_lcand* const candidate,
+    udp_helper_recv_h* const receive_handler,
+    void* const arg) {
+    struct rawrtc_candidate_helper* candidate_helper;
+    enum rawrtc_code error;
+
+    // Check arguments
+    if (!candidate_helperp || !gatherer || !candidate || !receive_handler) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Create candidate helper
+    candidate_helper = mem_zalloc(sizeof(*candidate_helper), rawrtc_candidate_helper_destroy);
+    if (!candidate_helper) {
+        return RAWRTC_CODE_NO_MEMORY;
+    }
+
+    // Set fields
+    candidate_helper->gatherer = mem_ref(gatherer);
+    candidate_helper->candidate = mem_ref(candidate);
+    candidate_helper->srflx_pending_count = 0;
+    candidate_helper->relay_pending_count = 0;
+
+    // Set receive handler
+    error = rawrtc_candidate_helper_set_receive_handler(candidate_helper, receive_handler, arg);
+    if (error) {
+        goto out;
+    }
+
+out:
+    if (error) {
+        mem_deref(candidate_helper);
+    } else {
+        // Set pointer
+        *candidate_helperp = candidate_helper;
+    }
+    return error;
+}
+
+/*
+ * Set a candidate helper's receive handler.
+ */
+enum rawrtc_code rawrtc_candidate_helper_set_receive_handler(
+    struct rawrtc_candidate_helper* const candidate_helper,
+    udp_helper_recv_h* const receive_handler,
+    void* const arg) {
+    enum rawrtc_code error;
+    struct udp_helper* udp_helper;
+    struct udp_sock* udp_socket;
+
+    // Check arguments
+    if (!candidate_helper || !receive_handler) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Get local candidate's UDP socket
+    udp_socket = trice_lcand_sock(candidate_helper->gatherer->ice, candidate_helper->candidate);
+    if (!udp_socket) {
+        return RAWRTC_CODE_NO_SOCKET;
+    }
+
+    // Create UDP helper
+    error = rawrtc_error_to_code(udp_register_helper(
+        &udp_helper, udp_socket, RAWRTC_LAYER_DTLS_SRTP_STUN, NULL, receive_handler, arg));
+    if (error) {
+        return error;
+    }
+
+    // Unset current helper (if any) and set new helper
+    mem_deref(candidate_helper->udp_helper);
+    candidate_helper->udp_helper = udp_helper;
+
+    // TODO: What about TCP helpers?
+
+    // Done
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Find a specific candidate helper by re candidate.
+ */
+enum rawrtc_code rawrtc_candidate_helper_find(
+    struct rawrtc_candidate_helper** const candidate_helperp,
+    struct list* const candidate_helpers,
+    struct ice_lcand* re_candidate) {
+    struct le* le;
+
+    // Check arguments
+    if (!candidate_helperp || !candidate_helpers || !re_candidate) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Lookup candidate helper
+    for (le = list_head(candidate_helpers); le != NULL; le = le->next) {
+        struct rawrtc_candidate_helper* const candidate_helper = le->data;
+        if (candidate_helper->candidate->us == re_candidate->us) {
+            // Found
+            *candidate_helperp = candidate_helper;
+            return RAWRTC_CODE_SUCCESS;
+        }
+    }
+
+    // Not found
+    return RAWRTC_CODE_NO_VALUE;
+}
+
+static void rawrtc_candidate_helper_stun_session_destroy(void* arg) {
+    struct rawrtc_candidate_helper_stun_session* const session = arg;
+
+    // Remove from list
+    list_unlink(&session->le);
+
+    // Un-reference
+    mem_deref(session->url);
+    mem_deref(session->stun_keepalive);
+    mem_deref(session->candidate_helper);
+}
+
+/*
+ * Create a STUN session.
+ */
+enum rawrtc_code rawrtc_candidate_helper_stun_session_create(
+    struct rawrtc_candidate_helper_stun_session** const sessionp,  // de-referenced
+    struct rawrtc_ice_server_url* const url) {
+    struct rawrtc_candidate_helper_stun_session* session;
+
+    // Check arguments
+    if (!sessionp || !url) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Allocate
+    session = mem_zalloc(sizeof(*session), rawrtc_candidate_helper_stun_session_destroy);
+    if (!session) {
+        return RAWRTC_CODE_NO_MEMORY;
+    }
+
+    // Set fields/reference
+    session->url = mem_ref(url);
+    session->pending = true;
+
+    // Set pointer & done
+    *sessionp = session;
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Add a STUN session to a candidate helper.
+ */
+enum rawrtc_code rawrtc_candidate_helper_stun_session_add(
+    struct rawrtc_candidate_helper_stun_session* const session,
+    struct rawrtc_candidate_helper* const candidate_helper,
+    struct stun_keepalive* const stun_keepalive) {
+    // Check arguments
+    if (!session || !candidate_helper || !stun_keepalive) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Set fields/reference
+    session->candidate_helper = mem_ref(candidate_helper);
+    session->stun_keepalive = mem_ref(stun_keepalive);
+
+    // Append to STUN sessions
+    list_append(&candidate_helper->stun_sessions, &session->le, session);
+
+    // Done
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Remove STUN sessions list handler (for candidate helper lists).
+ */
+bool rawrtc_candidate_helper_remove_stun_sessions_handler(struct le* le, void* arg) {
+    struct rawrtc_candidate_helper* const candidate_helper = le->data;
+    (void) arg;
+
+    // Flush STUN sessions
+    list_flush(&candidate_helper->stun_sessions);
+
+    return false;  // continue traversing
+}