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/tools/helper/utils.c b/tools/helper/utils.c
new file mode 100644
index 0000000..2c15b00
--- /dev/null
+++ b/tools/helper/utils.c
@@ -0,0 +1,380 @@
+#include "utils.h"
+#include "common.h"
+#include <rawrtc.h>
+#include <rawrtcc.h>
+#include <rawrtcdc.h>
+#include <re.h>
+#include <limits.h>  // ULONG_MAX
+#include <stdlib.h>  // strto*
+#include <string.h>  // strlen
+
+#define DEBUG_MODULE "helper-utils"
+#define DEBUG_LEVEL 7
+#include <re_dbg.h>
+
+/*
+ * Convert string to uint16.
+ */
+bool str_to_uint16(uint16_t* const numberp, char* const str) {
+    char* end;
+    unsigned long number = strtoul(str, &end, 10);
+
+    // Check result (this function is insane, srsly...)
+    if (*end != '\0' || (number == ULONG_MAX && errno == ERANGE)) {
+        return false;
+    }
+
+    // Check bounds
+#if (ULONG_MAX > UINT16_MAX)
+    if (number > UINT16_MAX) {
+        return false;
+    }
+#endif
+
+    // Done
+    *numberp = (uint16_t) number;
+    return true;
+}
+
+/*
+ * Convert string to uint64.
+ */
+bool str_to_uint64(uint64_t* const numberp, char* const str) {
+    char* end;
+    unsigned long long number = strtoull(str, &end, 10);
+
+    // Check result (this function is insane, srsly...)
+    if (*end != '\0' || (number == ULONG_MAX && errno == ERANGE)) {
+        return false;
+    }
+
+    // Check bounds
+#if (ULONG_MAX > UINT64_MAX)
+    if (number > UINT64_MAX) {
+        return false;
+    }
+#endif
+
+    // Done
+    *numberp = (uint64_t) number;
+    return true;
+}
+
+/*
+ * Convert string to uint32.
+ */
+bool str_to_uint32(uint32_t* const numberp, char* const str) {
+    uint64_t number;
+    bool success = str_to_uint64(&number, str);
+
+    // Validate
+    if (!success || number > UINT32_MAX) {
+        return false;
+    }
+
+    // Done
+    *numberp = (uint32_t) number;
+    return true;
+}
+
+/*
+ * Get a dictionary entry and store it in `*valuep`.
+ */
+enum rawrtc_code dict_get_entry(
+    void* const valuep,
+    struct odict* const parent,
+    char* const key,
+    enum odict_type const type,
+    bool required) {
+    struct odict_entry const* entry;
+
+    // Check arguments
+    if (!valuep || !parent || !key) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Do lookup
+    entry = odict_lookup(parent, key);
+
+    // Check for entry
+    if (!entry) {
+        if (required) {
+            DEBUG_WARNING("'%s' missing\n", key);
+            return RAWRTC_CODE_INVALID_ARGUMENT;
+        } else {
+            return RAWRTC_CODE_NO_VALUE;
+        }
+    }
+
+    // Check for type
+    if (entry->type != type) {
+        DEBUG_WARNING("'%s' is of different type than expected\n", key);
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Set value according to type
+    switch (type) {
+        case ODICT_OBJECT:
+        case ODICT_ARRAY:
+            *((struct odict * * const) valuep) = entry->u.odict;
+            break;
+        case ODICT_STRING:
+            *((char** const) valuep) = entry->u.str;
+            break;
+        case ODICT_INT:
+            *((int64_t* const) valuep) = entry->u.integer;
+            break;
+        case ODICT_DOUBLE:
+            *((double* const) valuep) = entry->u.dbl;
+            break;
+        case ODICT_BOOL:
+            *((bool* const) valuep) = entry->u.boolean;
+            break;
+        case ODICT_NULL:
+            *((char** const) valuep) = NULL;  // meh!
+            break;
+        default:
+            return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Done
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Get a uint32 entry and store it in `*valuep`.
+ */
+enum rawrtc_code dict_get_uint32(
+    uint32_t* const valuep, struct odict* const parent, char* const key, bool required) {
+    enum rawrtc_code error;
+    int64_t value;
+
+    // Check arguments
+    if (!valuep || !parent || !key) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Get int64_t
+    error = dict_get_entry(&value, parent, key, ODICT_INT, required);
+    if (error) {
+        return error;
+    }
+
+    // Check bounds
+    if (value < 0 || value > UINT32_MAX) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Set value & done
+    *valuep = (uint32_t) value;
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Get a uint16 entry and store it in `*valuep`.
+ */
+enum rawrtc_code dict_get_uint16(
+    uint16_t* const valuep, struct odict* const parent, char* const key, bool required) {
+    enum rawrtc_code error;
+    int64_t value;
+
+    // Check arguments
+    if (!valuep || !parent || !key) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Get int64_t
+    error = dict_get_entry(&value, parent, key, ODICT_INT, required);
+    if (error) {
+        return error;
+    }
+
+    // Check bounds
+    if (value < 0 || value > UINT16_MAX) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Set value & done
+    *valuep = (uint16_t) value;
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Get JSON from stdin and parse it to a dictionary.
+ */
+enum rawrtc_code get_json_stdin(struct odict** const dictp  // de-referenced
+) {
+    char buffer[PARAMETERS_MAX_LENGTH];
+    size_t length;
+
+    // Get message from stdin
+    if (!fgets((char*) buffer, PARAMETERS_MAX_LENGTH, stdin)) {
+        EWE("Error polling stdin");
+    }
+    length = strlen(buffer);
+
+    // Exit?
+    if (length == 1 && buffer[0] == '\n') {
+        return RAWRTC_CODE_NO_VALUE;
+    }
+
+    // Decode JSON
+    EOR(json_decode_odict(dictp, 16, buffer, length, 3));
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Get the ICE role from a string.
+ */
+enum rawrtc_code get_ice_role(
+    enum rawrtc_ice_role* const rolep,  // de-referenced
+    char const* const str) {
+    // Get ICE role
+    switch (str[0]) {
+        case '0':
+            *rolep = RAWRTC_ICE_ROLE_CONTROLLED;
+            return RAWRTC_CODE_SUCCESS;
+        case '1':
+            *rolep = RAWRTC_ICE_ROLE_CONTROLLING;
+            return RAWRTC_CODE_SUCCESS;
+        default:
+            return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+}
+
+/*
+ * Get the congestion control algorithm from a string.
+ */
+enum rawrtc_code get_congestion_control_algorithm(
+    enum rawrtc_sctp_transport_congestion_ctrl* const algorithmp,  // de-referenced
+    char const* const str) {
+    if (str_casecmp(str, "RFC2581") == 0) {
+        *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_RFC2581;
+        return RAWRTC_CODE_SUCCESS;
+    } else if (str_casecmp(str, "HSTCP") == 0) {
+        *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_HSTCP;
+        return RAWRTC_CODE_SUCCESS;
+    } else if (str_casecmp(str, "HTCP") == 0) {
+        *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_HTCP;
+        return RAWRTC_CODE_SUCCESS;
+    } else if (str_casecmp(str, "RTCC") == 0) {
+        *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_RTCC;
+        return RAWRTC_CODE_SUCCESS;
+    } else {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+}
+
+static void data_channel_helper_destroy(void* arg) {
+    struct data_channel_helper* const channel = arg;
+
+    // Unset handler argument & handlers of the channel
+    if (channel->channel) {
+        EOE(rawrtc_data_channel_unset_handlers(channel->channel));
+    }
+
+    // Remove from list
+    list_unlink(&channel->le);
+
+    // Un-reference
+    mem_deref(channel->arg);
+    mem_deref(channel->label);
+    mem_deref(channel->channel);
+}
+
+/*
+ * Create a data channel helper instance.
+ */
+void data_channel_helper_create(
+    struct data_channel_helper** const channel_helperp,  // de-referenced
+    struct client* const client,
+    char* const label) {
+    // Allocate
+    struct data_channel_helper* const channel =
+        mem_zalloc(sizeof(*channel), data_channel_helper_destroy);
+    if (!channel) {
+        EOE(RAWRTC_CODE_NO_MEMORY);
+        return;
+    }
+
+    // Set fields
+    channel->client = client;
+    EOE(rawrtc_strdup(&channel->label, label));
+
+    // Set pointer & done
+    *channel_helperp = channel;
+}
+
+/*
+ * Create a data channel helper instance from parameters.
+ */
+void data_channel_helper_create_from_channel(
+    struct data_channel_helper** const channel_helperp,  // de-referenced
+    struct rawrtc_data_channel* channel,
+    struct client* const client,
+    void* const arg  // nullable
+) {
+    enum rawrtc_code error;
+    struct rawrtc_data_channel_parameters* parameters;
+    char* label;
+
+    // Allocate
+    struct data_channel_helper* const channel_helper =
+        mem_zalloc(sizeof(*channel_helper), data_channel_helper_destroy);
+    if (!channel_helper) {
+        EOE(RAWRTC_CODE_NO_MEMORY);
+        return;
+    }
+
+    // Get parameters
+    EOE(rawrtc_data_channel_get_parameters(&parameters, channel));
+
+    // Get & set label
+    error = rawrtc_data_channel_parameters_get_label(&label, parameters);
+    switch (error) {
+        case RAWRTC_CODE_SUCCESS:
+            EOE(rawrtc_strdup(&channel_helper->label, label));
+            mem_deref(label);
+            break;
+        case RAWRTC_CODE_NO_VALUE:
+            EOE(rawrtc_strdup(&channel_helper->label, "n/a"));
+            break;
+        default:
+            EOE(error);
+    }
+
+    // Set fields
+    channel_helper->client = client;
+    channel_helper->channel = channel;
+    channel_helper->arg = mem_ref(arg);
+
+    // Set pointer
+    *channel_helperp = channel_helper;
+
+    // Un-reference & done
+    mem_deref(parameters);
+}
+
+/*
+ * Add the ICE candidate to the remote ICE transport if the ICE
+ * candidate type is enabled.
+ */
+void add_to_other_if_ice_candidate_type_enabled(
+    struct client* const client,
+    struct rawrtc_ice_candidate* const candidate,
+    struct rawrtc_ice_transport* const transport) {
+    if (candidate) {
+        enum rawrtc_ice_candidate_type type;
+
+        // Get ICE candidate type
+        EOE(rawrtc_ice_candidate_get_type(&type, candidate));
+
+        // Add to other client as remote candidate (if type enabled)
+        if (ice_candidate_type_enabled(client, type)) {
+            EOE(rawrtc_ice_transport_add_remote_candidate(transport, candidate));
+        }
+    } else {
+        // Last candidate is always being added
+        EOE(rawrtc_ice_transport_add_remote_candidate(transport, candidate));
+    }
+}