#include "msg.h" #include "log.h" #include "net.h" #include #include static int msg_copy_argv(struct msg *msg, char **argv) { msg->argv = calloc(msg->argc, sizeof(char *)); if (!msg->argv) { print_errno("calloc"); return -1; } for (int i = 0; i < msg->argc; ++i) { msg->argv[i] = strdup(argv[i]); if (!msg->argv[i]) { print_errno("strdup"); goto free; } } return 0; free: msg_free(msg); return -1; } struct msg *msg_copy(const struct msg *src) { struct msg *dest; int ret = 0; dest = malloc(sizeof(*dest)); if (!dest) { print_errno("calloc"); return NULL; } dest->argc = src->argc; ret = msg_copy_argv(dest, src->argv); if (ret < 0) goto free; return dest; free: free(dest); return NULL; } void msg_free(const struct msg *msg) { for (int i = 0; i < msg->argc; ++i) free((char *)msg->argv[i]); free(msg->argv); } int msg_from_argv(struct msg *msg, char **argv) { int argc = 0; for (char **s = argv; *s; ++s) ++argc; msg->argc = argc; return msg_copy_argv(msg, argv); } static size_t calc_buf_len(const struct msg *msg) { size_t len = 0; for (int i = 0; i < msg->argc; ++i) len += strlen(msg->argv[i]) + 1; return len; } static int calc_argv_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 argv_pack(char *dest, const struct msg *msg) { for (int i = 0; i < msg->argc; ++i) { strcpy(dest, msg->argv[i]); dest += strlen(msg->argv[i]) + 1; } } static int argv_unpack(struct msg *msg, const char *src) { msg->argv = calloc(msg->argc, sizeof(char *)); if (!msg->argv) { print_errno("calloc"); return -1; } for (int i = 0; i < msg->argc; ++i) { size_t len = strlen(src); msg->argv[i] = malloc(len); if (!msg->argv[i]) { print_errno("malloc"); goto free; } strcpy(msg->argv[i], src); src += len + 1; } return 0; free: msg_free(msg); return -1; } int msg_send(int fd, const struct msg *msg) { int ret = 0; size_t len = calc_buf_len(msg); char *buf = malloc(len); if (!buf) { print_errno("malloc"); return -1; } argv_pack(buf, msg); ret = net_send_buf(fd, buf, len); if (ret < 0) goto free_buf; free_buf: free(buf); return ret; } int msg_send_and_wait(int fd, const struct msg *msg, int *result) { int ret = 0; ret = msg_send(fd, msg); if (ret < 0) return ret; ret = net_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 = net_recv_buf(fd, &buf, &len); if (ret < 0) return ret; msg->argc = calc_argv_len(buf, len); ret = argv_unpack(msg, buf); if (ret < 0) goto free_buf; free_buf: free(buf); return ret; } int msg_recv_and_handle(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 = net_send_buf(fd, &result, sizeof(result)); if (ret < 0) goto free_msg; free_msg: msg_free(&msg); return ret; } int msg_dump_unknown(const struct msg *msg) { print_log("Received an unknown message:\n"); for (int i = 0; i < msg->argc; ++i) print_log("\t%s\n", msg->argv[i]); return -1; }