Squashed 'third_party/rawrtc/rawrtc-common/' content from commit aff7a3a3b

Change-Id: I2cb019410e8d0e1e0bf814577b0ef83aeb32c7fd
git-subtree-dir: third_party/rawrtc/rawrtc-common
git-subtree-split: aff7a3a3b9bbf49f7d2fc8b123edd301825b3e1c
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..15aec96
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,4 @@
+sources = []
+
+subdir('message_buffer')
+subdir('utils')
diff --git a/src/message_buffer/buffer.c b/src/message_buffer/buffer.c
new file mode 100644
index 0000000..75004f1
--- /dev/null
+++ b/src/message_buffer/buffer.c
@@ -0,0 +1,99 @@
+#include <rawrtcc/code.h>
+#include <rawrtcc/message_buffer.h>
+#include <re.h>
+
+/*
+ * Message buffer.
+ */
+struct buffered_message {
+    struct le le;
+    struct mbuf* buffer;  // referenced
+    void* context;  // referenced, nullable
+};
+
+/*
+ * Destructor for an existing buffered message.
+ */
+static void rawrtc_message_buffer_destroy(void* arg) {
+    struct buffered_message* const buffered_message = arg;
+
+    // Un-reference
+    mem_deref(buffered_message->context);
+    mem_deref(buffered_message->buffer);
+}
+
+/*
+ * Create a message buffer and add it to a list.
+ *
+ * TODO: Add timestamp to be able to ignore old messages
+ */
+enum rawrtc_code rawrtc_message_buffer_append(
+    struct list* const message_buffer,
+    struct mbuf* const buffer,  // referenced
+    void* const context  // referenced, nullable
+) {
+    struct buffered_message* buffered_message;
+
+    // Check arguments
+    if (!message_buffer || !buffer) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Create buffered message
+    buffered_message = mem_zalloc(sizeof(*buffered_message), rawrtc_message_buffer_destroy);
+    if (!buffered_message) {
+        return RAWRTC_CODE_NO_MEMORY;
+    }
+
+    // Set fields
+    buffered_message->buffer = mem_ref(buffer);
+    buffered_message->context = mem_ref(context);
+
+    // Add to list
+    list_append(message_buffer, &buffered_message->le, buffered_message);
+    return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Apply a receive handler to buffered messages.
+ *
+ * Will stop iterating and return `RAWRTC_CODE_STOP_ITERATION` in case
+ * the message handler returned `false`.
+ */
+enum rawrtc_code rawrtc_message_buffer_clear(
+    struct list* const message_buffer,
+    rawrtc_message_buffer_handler* const message_handler,
+    void* arg) {
+    struct le* le;
+    bool unlink;
+
+    // Check arguments
+    if (!message_buffer || !message_handler) {
+        return RAWRTC_CODE_INVALID_ARGUMENT;
+    }
+
+    // Handle each message
+    le = list_head(message_buffer);
+    while (le != NULL) {
+        struct buffered_message* const buffered_message = le->data;
+
+        // Handle message
+        unlink = message_handler(buffered_message->buffer, buffered_message->context, arg);
+        if (unlink) {
+            list_unlink(le);
+        }
+
+        // Get next message
+        le = le->next;
+
+        // Remove message
+        if (unlink) {
+            mem_deref(buffered_message);
+        } else {
+            return RAWRTC_CODE_STOP_ITERATION;
+        }
+    }
+
+    // Done
+    return RAWRTC_CODE_SUCCESS;
+}
diff --git a/src/message_buffer/meson.build b/src/message_buffer/meson.build
new file mode 100644
index 0000000..c95a347
--- /dev/null
+++ b/src/message_buffer/meson.build
@@ -0,0 +1 @@
+sources += files('buffer.c')
diff --git a/src/utils/meson.build b/src/utils/meson.build
new file mode 100644
index 0000000..d82c551
--- /dev/null
+++ b/src/utils/meson.build
@@ -0,0 +1 @@
+sources += files('utils.c')
diff --git a/src/utils/utils.c b/src/utils/utils.c
new file mode 100644
index 0000000..d837a60
--- /dev/null
+++ b/src/utils/utils.c
@@ -0,0 +1,109 @@
+#include <rawrtcc/code.h>
+#include <rawrtcc/utils.h>
+#include <re.h>
+#include <stdarg.h>  // va_*
+
+/*
+ * Translate a rawrtc return code to a string.
+ */
+char const* rawrtc_code_to_str(enum rawrtc_code const code) {
+    switch (code) {
+        case RAWRTC_CODE_UNKNOWN_ERROR:
+            return "unknown error";
+        case RAWRTC_CODE_NOT_IMPLEMENTED:
+            return "not implemented";
+        case RAWRTC_CODE_SUCCESS:
+            return "success";
+        case RAWRTC_CODE_INITIALISE_FAIL:
+            return "failed to initialise";
+        case RAWRTC_CODE_INVALID_ARGUMENT:
+            return "invalid argument";
+        case RAWRTC_CODE_NO_MEMORY:
+            return "no memory";
+        case RAWRTC_CODE_INVALID_STATE:
+            return "invalid state";
+        case RAWRTC_CODE_UNSUPPORTED_PROTOCOL:
+            return "unsupported protocol";
+        case RAWRTC_CODE_UNSUPPORTED_ALGORITHM:
+            return "unsupported algorithm";
+        case RAWRTC_CODE_NO_VALUE:
+            return "no value";
+        case RAWRTC_CODE_NO_SOCKET:
+            return "no socket";
+        case RAWRTC_CODE_INVALID_CERTIFICATE:
+            return "invalid certificate";
+        case RAWRTC_CODE_INVALID_FINGERPRINT:
+            return "invalid fingerprint";
+        case RAWRTC_CODE_INSUFFICIENT_SPACE:
+            return "insufficient space";
+        case RAWRTC_CODE_STILL_IN_USE:
+            return "still in use";
+        case RAWRTC_CODE_INVALID_MESSAGE:
+            return "invalid message";
+        case RAWRTC_CODE_MESSAGE_TOO_LONG:
+            return "message too long";
+        case RAWRTC_CODE_TRY_AGAIN_LATER:
+            return "try again later";
+        case RAWRTC_CODE_STOP_ITERATION:
+            return "stop iteration";
+        case RAWRTC_CODE_NOT_PERMITTED:
+            return "not permitted";
+        case RAWRTC_CODE_EXTERNAL_ERROR:
+            return "external callback error-ed";
+        default:
+            return "(no error translation)";
+    }
+}
+
+/*
+ * Translate an re error to a rawrtc code.
+ * TODO: Add codes from trice_lcand_add
+ */
+enum rawrtc_code rawrtc_error_to_code(int const code) {
+    switch (code) {
+        case 0:
+            return RAWRTC_CODE_SUCCESS;
+        case EAGAIN:
+#if (EAGAIN != EWOULDBLOCK)
+        case EWOULDBLOCK:
+#endif
+            return RAWRTC_CODE_TRY_AGAIN_LATER;
+        case EAUTH:
+            return RAWRTC_CODE_INVALID_CERTIFICATE;
+        case EBADMSG:
+            return RAWRTC_CODE_INVALID_MESSAGE;
+        case EINVAL:
+            return RAWRTC_CODE_INVALID_ARGUMENT;
+        case EMSGSIZE:
+            return RAWRTC_CODE_MESSAGE_TOO_LONG;
+        case ENOMEM:
+            return RAWRTC_CODE_NO_MEMORY;
+        case EPERM:
+            return RAWRTC_CODE_NOT_PERMITTED;
+        default:
+            return RAWRTC_CODE_UNKNOWN_ERROR;
+    }
+}
+
+/*
+ * Duplicate a string.
+ * `*destinationp` will be set to a copy of `source` and must be
+ * unreferenced.
+ */
+enum rawrtc_code rawrtc_strdup(char** const destinationp, char const* const source) {
+    int err = str_dup(destinationp, source);
+    return rawrtc_error_to_code(err);
+}
+
+/*
+ * Print a formatted string to a dynamically allocated buffer.
+ * `*destinationp` must be unreferenced.
+ */
+enum rawrtc_code rawrtc_sdprintf(char** const destinationp, char* const formatter, ...) {
+    int err;
+    va_list args;
+    va_start(args, formatter);
+    err = re_vsdprintf(destinationp, formatter, args);
+    va_end(args);
+    return rawrtc_error_to_code(err);
+}