diff options
Diffstat (limited to 'src/msg.c')
-rw-r--r-- | src/msg.c | 192 |
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); +} |