From 046cf995855c0bdaa5885d376fc77cecf607b58f Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 2 Oct 2011 18:33:10 +0100 Subject: [PATCH] Move ipc_send_message and ipc_recv_message to libi3 Make i3-msg and src/ipc.c use it --- i3-msg/main.c | 89 ++++++---------------------------------- include/libi3.h | 25 +++++++++++ libi3/ipc_recv_message.c | 81 ++++++++++++++++++++++++++++++++++++ libi3/ipc_send_message.c | 53 ++++++++++++++++++++++++ src/ipc.c | 49 ++++------------------ 5 files changed, 179 insertions(+), 118 deletions(-) create mode 100644 libi3/ipc_recv_message.c create mode 100644 libi3/ipc_send_message.c diff --git a/i3-msg/main.c b/i3-msg/main.c index 23ffd414..5bc35b88 100644 --- a/i3-msg/main.c +++ b/i3-msg/main.c @@ -10,7 +10,10 @@ * i3-msg/main.c: Utility which sends messages to a running i3-instance using * IPC via UNIX domain sockets. * - * This serves as an example for how to send your own messages to i3. + * This (in combination with libi3/ipc_send_message.c and + * libi3/ipc_recv_message.c) serves as an example for how to send your own + * messages to i3. + * * Additionally, it’s even useful sometimes :-). * */ @@ -37,80 +40,6 @@ static char *socket_path; -/* - * Formats a message (payload) of the given size and type and sends it to i3 via - * the given socket file descriptor. - * - */ -static void ipc_send_message(int sockfd, uint32_t message_size, - uint32_t message_type, uint8_t *payload) { - int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t) + message_size; - char msg[buffer_size]; - char *walk = msg; - - strcpy(walk, I3_IPC_MAGIC); - walk += strlen(I3_IPC_MAGIC); - memcpy(walk, &message_size, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &message_type, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, payload, message_size); - - int sent_bytes = 0; - int bytes_to_go = buffer_size; - while (sent_bytes < bytes_to_go) { - int n = write(sockfd, msg + sent_bytes, bytes_to_go); - if (n == -1) - err(EXIT_FAILURE, "write() failed"); - - sent_bytes += n; - bytes_to_go -= n; - } -} - -static void ipc_recv_message(int sockfd, uint32_t message_type, - uint32_t *reply_length, uint8_t **reply) { - /* Read the message header first */ - uint32_t to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); - char msg[to_read]; - char *walk = msg; - - uint32_t read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, msg + read_bytes, to_read); - if (n == -1) - err(EXIT_FAILURE, "read() failed"); - if (n == 0) - errx(EXIT_FAILURE, "received EOF instead of reply"); - - read_bytes += n; - to_read -= n; - } - - if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) - errx(EXIT_FAILURE, "invalid magic in reply"); - - walk += strlen(I3_IPC_MAGIC); - *reply_length = *((uint32_t*)walk); - walk += sizeof(uint32_t); - if (*((uint32_t*)walk) != message_type) - errx(EXIT_FAILURE, "unexpected reply type (got %d, expected %d)", *((uint32_t*)walk), message_type); - walk += sizeof(uint32_t); - - *reply = smalloc(*reply_length); - - to_read = *reply_length; - read_bytes = 0; - while (read_bytes < to_read) { - int n = read(sockfd, *reply + read_bytes, to_read); - if (n == -1) - err(EXIT_FAILURE, "read() failed"); - - read_bytes += n; - to_read -= n; - } -} - int main(int argc, char *argv[]) { socket_path = getenv("I3SOCK"); int o, option_index = 0; @@ -199,14 +128,20 @@ int main(int argc, char *argv[]) { if (connect(sockfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) err(EXIT_FAILURE, "Could not connect to i3"); - ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t*)payload); + if (ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t*)payload) == -1) + err(EXIT_FAILURE, "IPC: write()"); if (quiet) return 0; uint32_t reply_length; uint8_t *reply; - ipc_recv_message(sockfd, message_type, &reply_length, &reply); + int ret; + if ((ret = ipc_recv_message(sockfd, message_type, &reply_length, &reply)) != 0) { + if (ret == -1) + err(EXIT_FAILURE, "IPC: read()"); + exit(1); + } printf("%.*s\n", reply_length, reply); free(reply); diff --git a/include/libi3.h b/include/libi3.h index a675d11e..079d160b 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -42,4 +42,29 @@ void *srealloc(void *ptr, size_t size); */ char *sstrdup(const char *str); +/** + * Formats a message (payload) of the given size and type and sends it to i3 via + * the given socket file descriptor. + * + * Returns -1 when write() fails, errno will remain. + * Returns 0 on success. + * + */ +int ipc_send_message(int sockfd, uint32_t message_size, + uint32_t message_type, const uint8_t *payload); + +/** + * Reads a message from the given socket file descriptor and stores its length + * (reply_length) as well as a pointer to its contents (reply). + * + * Returns -1 when read() fails, errno will remain. + * Returns -2 when the IPC protocol is violated (invalid magic, unexpected + * message type, EOF instead of a message). Additionally, the error will be + * printed to stderr. + * Returns 0 on success. + * + */ +int ipc_recv_message(int sockfd, uint32_t message_type, + uint32_t *reply_length, uint8_t **reply); + #endif diff --git a/libi3/ipc_recv_message.c b/libi3/ipc_recv_message.c new file mode 100644 index 00000000..47d6dea3 --- /dev/null +++ b/libi3/ipc_recv_message.c @@ -0,0 +1,81 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * © 2009-2011 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ +#include +#include +#include +#include +#include + +#include + +#include "libi3.h" + +/* + * Reads a message from the given socket file descriptor and stores its length + * (reply_length) as well as a pointer to its contents (reply). + * + * Returns -1 when read() fails, errno will remain. + * Returns -2 when the IPC protocol is violated (invalid magic, unexpected + * message type, EOF instead of a message). Additionally, the error will be + * printed to stderr. + * Returns 0 on success. + * + */ +int ipc_recv_message(int sockfd, uint32_t message_type, + uint32_t *reply_length, uint8_t **reply) { + /* Read the message header first */ + uint32_t to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); + char msg[to_read]; + char *walk = msg; + + uint32_t read_bytes = 0; + while (read_bytes < to_read) { + int n = read(sockfd, msg + read_bytes, to_read); + if (n == -1) + return -1; + if (n == 0) { + fprintf(stderr, "IPC: received EOF instead of reply\n"); + return -2; + } + + read_bytes += n; + to_read -= n; + } + + if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { + fprintf(stderr, "IPC: invalid magic in reply\n"); + return -2; + } + + walk += strlen(I3_IPC_MAGIC); + *reply_length = *((uint32_t*)walk); + walk += sizeof(uint32_t); + if (*((uint32_t*)walk) != message_type) { + fprintf(stderr, "IPC: unexpected reply type (got %d, expected %d)\n", *((uint32_t*)walk), message_type); + return -2; + } + walk += sizeof(uint32_t); + + *reply = smalloc(*reply_length); + + to_read = *reply_length; + read_bytes = 0; + while (read_bytes < to_read) { + int n = read(sockfd, *reply + read_bytes, to_read); + if (n == -1) + return -1; + + read_bytes += n; + to_read -= n; + } + + return 0; +} diff --git a/libi3/ipc_send_message.c b/libi3/ipc_send_message.c new file mode 100644 index 00000000..ff395ada --- /dev/null +++ b/libi3/ipc_send_message.c @@ -0,0 +1,53 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * © 2009-2011 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ +#include +#include +#include +#include +#include + +#include + +/* + * Formats a message (payload) of the given size and type and sends it to i3 via + * the given socket file descriptor. + * + * Returns -1 when write() fails, errno will remain. + * Returns 0 on success. + * + */ +int ipc_send_message(int sockfd, uint32_t message_size, + uint32_t message_type, const uint8_t *payload) { + int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t) + message_size; + char msg[buffer_size]; + char *walk = msg; + + strncpy(walk, I3_IPC_MAGIC, buffer_size - 1); + walk += strlen(I3_IPC_MAGIC); + memcpy(walk, &message_size, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &message_type, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, payload, message_size); + + int sent_bytes = 0; + int bytes_to_go = buffer_size; + while (sent_bytes < bytes_to_go) { + int n = write(sockfd, msg + sent_bytes, bytes_to_go); + if (n == -1) + return -1; + + sent_bytes += n; + bytes_to_go -= n; + } + + return 0; +} diff --git a/src/ipc.c b/src/ipc.c index 031ee9ab..eba778cd 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -72,35 +72,6 @@ static bool mkdirp(const char *path) { return result; } -static void ipc_send_message(int fd, const unsigned char *payload, - int message_type, int message_size) { - int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) + - sizeof(uint32_t) + message_size; - char msg[buffer_size]; - char *walk = msg; - - strncpy(walk, "i3-ipc", buffer_size - 1); - walk += strlen("i3-ipc"); - memcpy(walk, &message_size, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, &message_type, sizeof(uint32_t)); - walk += sizeof(uint32_t); - memcpy(walk, payload, message_size); - - int sent_bytes = 0; - int bytes_to_go = buffer_size; - while (sent_bytes < bytes_to_go) { - int n = write(fd, msg + sent_bytes, bytes_to_go); - if (n == -1) { - DLOG("write() failed: %s\n", strerror(errno)); - return; - } - - sent_bytes += n; - bytes_to_go -= n; - } -} - /* * Sends the specified event to all IPC clients which are currently connected * and subscribed to this kind of event. @@ -120,8 +91,7 @@ void ipc_send_event(const char *event, uint32_t message_type, const char *payloa if (!interested) continue; - ipc_send_message(current->fd, (const unsigned char*)payload, - message_type, strlen(payload)); + ipc_send_message(current->fd, strlen(payload), message_type, (const uint8_t*)payload); } } @@ -156,8 +126,7 @@ IPC_HANDLER(command) { /* If no reply was provided, we just use the default success message */ if (reply == NULL) reply = "{\"success\":true}"; - ipc_send_message(fd, (const unsigned char*)reply, - I3_IPC_REPLY_TYPE_COMMAND, strlen(reply)); + ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_COMMAND, (const uint8_t*)reply); FREE(save_reply); } @@ -339,7 +308,7 @@ IPC_HANDLER(tree) { #endif y(get_buf, &payload, &length); - ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_TREE, length); + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_TREE, payload); y(free); } @@ -412,7 +381,7 @@ IPC_HANDLER(get_workspaces) { #endif y(get_buf, &payload, &length); - ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_WORKSPACES, length); + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload); y(free); } @@ -470,7 +439,7 @@ IPC_HANDLER(get_outputs) { #endif y(get_buf, &payload, &length); - ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_OUTPUTS, length); + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload); y(free); } @@ -502,7 +471,7 @@ IPC_HANDLER(get_marks) { #endif y(get_buf, &payload, &length); - ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_MARKS, length); + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_MARKS, payload); y(free); } @@ -580,15 +549,13 @@ IPC_HANDLER(subscribe) { yajl_free_error(p, err); const char *reply = "{\"success\":false}"; - ipc_send_message(fd, (const unsigned char*)reply, - I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply)); + ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t*)reply); yajl_free(p); return; } yajl_free(p); const char *reply = "{\"success\":true}"; - ipc_send_message(fd, (const unsigned char*)reply, - I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply)); + ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t*)reply); } /* The index of each callback function corresponds to the numeric -- 2.39.5