aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/msg.c')
-rw-r--r--src/msg.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/msg.c b/src/msg.c
new file mode 100644
index 0000000..ba6c474
--- /dev/null
+++ b/src/msg.c
@@ -0,0 +1,192 @@
+#include "msg.h"
+#include "log.h"
+#include "net.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+int msg_from_argv(struct msg *msg, const char *argv[])
+{
+ int argc = 0;
+
+ for (const char **s = argv; *s; ++s)
+ ++argc;
+
+ msg->argc = argc;
+ msg->argv = calloc(argc, sizeof(char *));
+
+ if (!msg->argv) {
+ print_errno("calloc");
+ return -1;
+ }
+
+ for (int i = 0; i < argc; ++i) {
+ msg->argv[i] = strdup(argv[i]);
+ if (!msg->argv[i]) {
+ print_errno("strdup");
+ goto free;
+ }
+ }
+
+ return 0;
+
+free:
+ for (int i = 0; i < argc; ++i)
+ if (msg->argv[i])
+ free(msg->argv[i]);
+ else
+ break;
+
+ free(msg->argv);
+ return -1;
+}
+
+static size_t calc_buf_len(int argc, char **argv)
+{
+ size_t len = 0;
+ for (int i = 0; i < argc; ++i)
+ len += strlen(argv[i]) + 1;
+ return len;
+}
+
+static int calc_arr_len(const void *buf, size_t len)
+{
+ int argc = 0;
+ for (const char *it = buf; it < (const char *)buf + len; it += strlen(it) + 1)
+ ++argc;
+ return argc;
+}
+
+static void arr_pack(char *dest, int argc, char **argv)
+{
+ for (int i = 0; i < argc; ++i) {
+ strcpy(dest, argv[i]);
+ dest += strlen(argv[i]) + 1;
+ }
+}
+
+static int arr_unpack(char **argv, int argc, const char *src)
+{
+ for (int i = 0; i < argc; ++i) {
+ size_t len = strlen(src);
+
+ argv[i] = malloc(len);
+ if (!argv[i]) {
+ print_errno("malloc");
+ goto free;
+ }
+
+ strcpy(argv[i], src);
+ src += len + 1;
+ }
+
+ return 0;
+
+free:
+ for (int i = 0; i < argc; ++i)
+ if (argv[i])
+ free(argv[i]);
+ else
+ break;
+
+ return -1;
+}
+
+int msg_send(int fd, const struct msg *msg)
+{
+ int ret = 0;
+
+ size_t len = calc_buf_len(msg->argc, msg->argv);
+ char *buf = malloc(len);
+ if (!buf) {
+ print_errno("malloc");
+ return -1;
+ }
+ arr_pack(buf, msg->argc, msg->argv);
+
+ ret = send_buf(fd, buf, len);
+ if (ret < 0)
+ goto free_buf;
+
+free_buf:
+ free(buf);
+
+ return ret;
+}
+
+int msg_send_and_wait_for_result(int fd, const struct msg *msg, int *result)
+{
+ int ret = 0;
+
+ ret = msg_send(fd, msg);
+ if (ret < 0)
+ return ret;
+
+ ret = recv_static(fd, result, sizeof(*result));
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+int msg_recv(int fd, struct msg *msg)
+{
+ void *buf;
+ size_t len;
+ int ret = 0;
+
+ ret = recv_buf(fd, &buf, &len);
+ if (ret < 0)
+ return ret;
+
+ msg->argc = calc_arr_len(buf, len);
+ msg->argv = calloc(msg->argc, sizeof(char *));
+ if (!msg->argv) {
+ print_errno("calloc");
+ ret = -1;
+ goto free_buf;
+ }
+
+ ret = arr_unpack(msg->argv, msg->argc, buf);
+ if (ret < 0)
+ goto free_argv;
+
+ goto free_buf;
+
+free_argv:
+ free(msg->argv);
+
+free_buf:
+ free(buf);
+
+ return ret;
+}
+
+int msg_recv_and_send_result(int fd, msg_handler handler, void *arg)
+{
+ struct msg msg;
+ int result;
+ int ret = 0;
+
+ ret = msg_recv(fd, &msg);
+ if (ret < 0)
+ return ret;
+
+ result = handler(&msg, arg);
+
+ ret = send_buf(fd, &result, sizeof(result));
+ if (ret < 0)
+ goto free_msg;
+
+free_msg:
+ msg_free(&msg);
+
+ return ret;
+}
+
+void msg_free(const struct msg *msg)
+{
+ for (int i = 0; i < msg->argc; ++i)
+ free(msg->argv[i]);
+ free(msg->argv);
+}