aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmdsclient/proto-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmdsclient/proto-util.c')
-rw-r--r--src/libmdsclient/proto-util.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/libmdsclient/proto-util.c b/src/libmdsclient/proto-util.c
index f104d05..85b755f 100644
--- a/src/libmdsclient/proto-util.c
+++ b/src/libmdsclient/proto-util.c
@@ -743,3 +743,49 @@ int libmds_compose_v(char** restrict buffer, size_t* restrict buffer_size, size_
return 0;
}
+
+/**
+ * Increase the message ID counter
+ *
+ * @param message_id Pointer to the current message ID, will be update with
+ * the next free message ID. Must not be `NULL`.
+ * @param test Function that tests whether an message ID is free,
+ * it takes the message ID to test as its first argument,
+ * and `data` as its second argument, and returns zero if
+ * it is in used, a positive integer if it is free, and a
+ * negative integer if an error occurred. `NULL` if there
+ * should be no testing.
+ * @param data Argument to pass to `test` so that it can deal with
+ * threading or any other issues. Unused if `test` is `NULL`.
+ * @return Zero on success, -1 on error, `errno` will have been set
+ * accordingly on error.
+ *
+ * @throws EAGAIN If there are no free message ID to be used.
+ * It is advisable to make `test` throw this immediately if
+ * there are no free message ID:s.
+ * @throws Any error that `test` may throw.
+ */
+int libmds_next_message_id(uint32_t* restrict message_id,
+ int (*test)(uint32_t message_id, void* data), void* data)
+{
+ uint32_t id = *message_id;
+ int r;
+
+ id = id == UINT32_MAX ? 0 : (id + 1);
+ if (test != NULL)
+ for (;;)
+ {
+ r = test(id, data);
+ if (r < 0)
+ return -1;
+ if (r)
+ break;
+ id = id == UINT32_MAX ? 0 : (id + 1);
+ if (id == *message_id)
+ return errno = EAGAIN, -1;
+ }
+
+ *message_id = id;
+ return 0;
+}
+