From 7b0d75ee0af44d91b46d22853a55e2f491d92385 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 11 Jan 2013 19:09:41 +0100 Subject: [PATCH] ipc_send_message: use stack frame with fixed size --- include/i3/ipc.h | 9 +++++++- include/libi3.h | 4 ++-- libi3/ipc_send_message.c | 45 +++++++++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/include/i3/ipc.h b/include/i3/ipc.h index 93b2ae87..7ce9ac65 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) * * This public header defines the different constants and message types to use * for the IPC interface to i3 (see docs/ipc for more information). @@ -11,6 +11,13 @@ #ifndef I3_I3_IPC_H #define I3_I3_IPC_H +typedef struct i3_ipc_header { + /* 6 = strlen(I3_IPC_MAGIC) */ + char magic[6]; + uint32_t size; + uint32_t type; +} __attribute__ ((packed)) i3_ipc_header_t; + /* * Messages from clients to i3 * diff --git a/include/libi3.h b/include/libi3.h index 54fa0cc7..2037da2e 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -202,8 +202,8 @@ int ipc_connect(const char *socket_path); * Returns 0 on success. * */ -int ipc_send_message(int sockfd, uint32_t message_size, - uint32_t message_type, const uint8_t *payload); +int ipc_send_message(int sockfd, const uint32_t message_size, + const uint32_t message_type, const uint8_t *payload); /** * Reads a message from the given socket file descriptor and stores its length diff --git a/libi3/ipc_send_message.c b/libi3/ipc_send_message.c index 88d87a6a..c5560c0d 100644 --- a/libi3/ipc_send_message.c +++ b/libi3/ipc_send_message.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) * */ #include @@ -24,24 +24,35 @@ * 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 ipc_send_message(int sockfd, const uint32_t message_size, + const uint32_t message_type, const uint8_t *payload) { + const i3_ipc_header_t header = { + /* We don’t use I3_IPC_MAGIC because it’s a 0-terminated C string. */ + .magic = { 'i', '3', '-', 'i', 'p', 'c' }, + .size = message_size, + .type = message_type + }; int sent_bytes = 0; - while (sent_bytes < buffer_size) { - int n = write(sockfd, msg + sent_bytes, buffer_size - sent_bytes); - if (n == -1) { + int n = 0; + + /* This first loop is basically unnecessary. No operating system has + * buffers which cannot fit 14 bytes into them, so the write() will only be + * called once. */ + while (sent_bytes < sizeof(i3_ipc_header_t)) { + if ((n = write(sockfd, ((void*)&header) + sent_bytes, sizeof(i3_ipc_header_t) - sent_bytes)) == -1) { + if (errno == EAGAIN) + continue; + return -1; + } + + sent_bytes += n; + } + + sent_bytes = 0; + + while (sent_bytes < message_size) { + if ((n = write(sockfd, payload + sent_bytes, message_size - sent_bytes)) == -1) { if (errno == EAGAIN) continue; return -1; -- 2.39.5