summaryrefslogtreecommitdiffstats
path: root/src/queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/queue.c')
-rw-r--r--src/queue.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/queue.c b/src/queue.c
new file mode 100644
index 0000000..16b0a0f
--- /dev/null
+++ b/src/queue.c
@@ -0,0 +1,192 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "db.h"
+
+#define DROP 0
+#define SET 1
+
+/**
+ * Queue
+ */
+struct queue
+{
+ uint32_t read, write, capacity;
+ void *queue;
+};
+typedef struct queue queue_t;
+
+/** the queue */
+static queue_t queue;
+
+static
+bool
+qread(
+ void *data,
+ uint32_t length
+) {
+ if (queue.read + length > queue.write)
+ return false;
+
+ memcpy(data, queue.queue + queue.read, length);
+ queue.read += length;
+ return true;
+}
+
+static
+bool
+qget_char(
+ char *value
+) {
+ return qread(value, sizeof *value);
+}
+
+static
+bool
+qget_uint32(
+ uint32_t *value
+) {
+ return qread(value, sizeof *value);
+}
+
+static
+bool
+qget_string(
+ const char **text
+) {
+ char *p = queue.queue + queue.read;
+ uint32_t length = (uint32_t)strlen(p);
+ if (queue.read + length >= queue.write)
+ return false;
+ *text = p;
+ queue.read += length + 1;
+ return true;
+}
+
+static
+bool
+qwrite(
+ const void *data,
+ uint32_t length
+) {
+ uint32_t c;
+ void *b;
+
+ c = queue.capacity;
+ while (c < queue.write + length)
+ c += 4096;
+ if (c != queue.capacity) {
+ b = realloc(queue.queue, c);
+ if (b == NULL)
+ return false;
+ queue.queue = b;
+ queue.capacity = c;
+ }
+ memcpy(queue.queue + queue.write, data, length);
+ queue.write += length;
+ return true;
+}
+
+static
+bool
+qput_char(
+ char value
+) {
+ return qwrite(&value, sizeof value);
+}
+
+static
+bool
+qput_uint32(
+ uint32_t value
+) {
+ return qwrite(&value, sizeof value);
+}
+
+static
+bool
+qput_string(
+ const char *text
+) {
+ size_t len;
+ text = text ?: "";
+ /* check length */
+ len = strnlen(text, MAX_NAME_LENGTH + 1);
+ if (len > MAX_NAME_LENGTH)
+ return false;
+ return qwrite(text, 1 + (uint32_t)len);
+}
+
+int
+queue_drop(
+ const char *client,
+ const char *session,
+ const char *user,
+ const char *permission
+) {
+ return qput_char(DROP)
+ && qput_string(client)
+ && qput_string(session)
+ && qput_string(user)
+ && qput_string(permission)
+ ? 0 : -(errno = ENOMEM);
+}
+
+int
+queue_set(
+ const char *client,
+ const char *session,
+ const char *user,
+ const char *permission,
+ uint32_t value
+) {
+ return qput_char(SET)
+ && qput_string(client)
+ && qput_string(session)
+ && qput_string(user)
+ && qput_string(permission)
+ && qput_uint32(value)
+ ? 0 : -(errno = ENOMEM);
+}
+
+
+void
+queue_clear(
+) {
+ queue.write = 0;
+}
+
+int
+queue_play(
+) {
+ int rc, rc2;
+ char op;
+ const char *client;
+ const char *session;
+ const char *user;
+ const char *permission;
+ uint32_t value;
+
+ rc = 0;
+ queue.read = 0;
+ while (queue.read < queue.write) {
+ rc2 = -EINVAL;
+ if (qget_char(&op)
+ && qget_string(&client)
+ && qget_string(&session)
+ && qget_string(&user)
+ && qget_string(&permission)) {
+ if (op == DROP)
+ rc2 = db_drop(client, session, user, permission);
+ else if (qget_uint32(&value))
+ rc2 = db_set(client, session, user, permission, value);
+ }
+ if (rc2 != 0 && rc == 0)
+ rc = rc2;
+ }
+ return rc;
+}
+