From 8981b48cd2cdd0a59c1546f2816587b303538d77 Mon Sep 17 00:00:00 2001 From: minus Date: Sun, 16 Aug 2015 20:24:18 +0200 Subject: very basic IPC implementation simply executes the received data as command --- include/ipc.h | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 include/ipc.h (limited to 'include/ipc.h') diff --git a/include/ipc.h b/include/ipc.h new file mode 100644 index 00000000..aab9cf0c --- /dev/null +++ b/include/ipc.h @@ -0,0 +1,6 @@ +#ifndef _SWAY_IPC_H +#define _SWAY_IPC_H + +void init_ipc(void); + +#endif -- cgit v1.2.3-70-g09d2 From 5d99215469088790d9b07a2932fd266133c8dc0b Mon Sep 17 00:00:00 2001 From: minus Date: Sun, 16 Aug 2015 22:02:16 +0200 Subject: added i3-ipc support/parsing --- include/ipc.h | 11 ++++++++ sway/ipc.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 84 insertions(+), 7 deletions(-) (limited to 'include/ipc.h') diff --git a/include/ipc.h b/include/ipc.h index aab9cf0c..25d2fc61 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -1,6 +1,17 @@ #ifndef _SWAY_IPC_H #define _SWAY_IPC_H +enum ipc_command_type { + IPC_COMMAND = 0, + IPC_GET_WORKSPACES = 1, + IPC_SUBSCRIBE = 2, + IPC_GET_OUTPUTS = 3, + IPC_GET_TREE = 4, + IPC_GET_MARKS = 5, + IPC_GET_BAR_CONFIG = 6, + IPC_GET_VERSION = 7, +}; + void init_ipc(void); #endif diff --git a/sway/ipc.c b/sway/ipc.c index ac5246d2..1a074788 100644 --- a/sway/ipc.c +++ b/sway/ipc.c @@ -2,15 +2,23 @@ #include #include #include +#include #include #include +#include +#include "ipc.h" #include "log.h" #include "config.h" #include "commands.h" static int ipc_socket = -1; +static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; + int ipc_handle_connection(int fd, uint32_t mask, void *data); +size_t ipc_handle_command(char **reply_data, char *data, ssize_t length); +size_t ipc_format_reply(char **data, enum ipc_command_type command_type, const char *payload, uint32_t payload_length); + void init_ipc() { ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); @@ -36,7 +44,8 @@ void init_ipc() { wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); } -int ipc_handle_connection(int /*fd*/, uint32_t /*mask*/, void */*data*/) { +int ipc_handle_connection(int fd, uint32_t mask, void *data) { + sway_log(L_DEBUG, "Event on IPC listening socket"); int client_socket = accept(ipc_socket, NULL, NULL); if (client_socket == -1) { char error[256]; @@ -46,7 +55,9 @@ int ipc_handle_connection(int /*fd*/, uint32_t /*mask*/, void */*data*/) { } char buf[1024]; - if (recv(client_socket, buf, sizeof(buf), 0) == -1) { + // Leave one byte of space at the end of the buffer for NULL terminator + ssize_t received = recv(client_socket, buf, sizeof(buf) - 1, 0); + if (received == -1) { char error[256]; strerror_r(errno, error, sizeof(error)); sway_log(L_INFO, "Unable to receive from IPC client: %s", error); @@ -54,17 +65,72 @@ int ipc_handle_connection(int /*fd*/, uint32_t /*mask*/, void */*data*/) { return 0; } - sway_log(L_INFO, "Executing IPC command: %s", buf); - - bool success = handle_command(config, buf); - snprintf(buf, sizeof(buf), "{\"success\":%s}\n", success ? "true" : "false"); + char *reply_buf; + size_t reply_length = ipc_handle_command(&reply_buf, buf, received); + sway_log(L_DEBUG, "IPC reply: %s", reply_buf); - if (send(client_socket, buf, strlen(buf), 0) == -1) { + if (send(client_socket, reply_buf, reply_length, 0) == -1) { char error[256]; strerror_r(errno, error, sizeof(error)); sway_log(L_INFO, "Unable to send to IPC client: %s", error); } + free(reply_buf); close(client_socket); return 0; } + +static const int ipc_header_size = sizeof(ipc_magic)+8; + +size_t ipc_handle_command(char **reply_data, char *data, ssize_t length) { + // See https://i3wm.org/docs/ipc.html for protocol details + + if (length < ipc_header_size) { + sway_log(L_DEBUG, "IPC data too short"); + return false; + } + + if (memcmp(data, ipc_magic, sizeof(ipc_magic)) != 0) { + sway_log(L_DEBUG, "IPC header check failed"); + return false; + } + + uint32_t payload_length = *(uint32_t *)&data[sizeof(ipc_magic)]; + uint32_t command_type = *(uint32_t *)&data[sizeof(ipc_magic)+4]; + + if (length != payload_length + ipc_header_size) { + // TODO: try to read enough data + sway_log(L_DEBUG, "IPC payload size mismatch"); + return false; + } + + switch (command_type) { + case IPC_COMMAND: + { + char *cmd = &data[ipc_header_size]; + data[ipc_header_size + payload_length] = '\0'; + bool success = handle_command(config, cmd); + char buf[64]; + int length = snprintf(buf, sizeof(buf), "{\"success\":%s}", success ? "true" : "false"); + return ipc_format_reply(reply_data, IPC_COMMAND, buf, (uint32_t) length); + } + default: + sway_log(L_INFO, "Unknown IPC command type %i", command_type); + return false; + } +} + +size_t ipc_format_reply(char **data, enum ipc_command_type command_type, const char *payload, uint32_t payload_length) { + assert(data); + assert(payload); + + size_t length = ipc_header_size + payload_length; + *data = malloc(length); + + memcpy(*data, ipc_magic, sizeof(ipc_magic)); + *(uint32_t *)&((*data)[sizeof(ipc_magic)]) = payload_length; + *(uint32_t *)&((*data)[sizeof(ipc_magic)+4]) = command_type; + memcpy(&(*data)[ipc_header_size], payload, payload_length); + + return length; +} -- cgit v1.2.3-70-g09d2 From 91c08772645e2162015c3acf8a8ae7187502adb4 Mon Sep 17 00:00:00 2001 From: minus Date: Wed, 19 Aug 2015 01:52:46 +0200 Subject: properly exit sway - wlc_terminate() instead of exit(0) - unlink IPC socket --- include/ipc.h | 3 ++- sway/commands.c | 2 +- sway/ipc.c | 23 ++++++++++++++++------- sway/main.c | 4 +++- 4 files changed, 22 insertions(+), 10 deletions(-) (limited to 'include/ipc.h') diff --git a/include/ipc.h b/include/ipc.h index 25d2fc61..606c47ba 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -12,6 +12,7 @@ enum ipc_command_type { IPC_GET_VERSION = 7, }; -void init_ipc(void); +void ipc_init(void); +void ipc_shutdown(void); #endif diff --git a/sway/commands.c b/sway/commands.c index 803d9a21..38557b62 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -186,7 +186,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) { } // Close all views container_map(&root_container, kill_views, NULL); - exit(0); + wlc_terminate(); return true; } diff --git a/sway/ipc.c b/sway/ipc.c index ba01a679..a6c4eb1a 100644 --- a/sway/ipc.c +++ b/sway/ipc.c @@ -16,6 +16,11 @@ #include "commands.h" static int ipc_socket = -1; +static struct wlc_event_source *ipc_event_source = NULL; +static struct sockaddr_un ipc_sockaddr = { + .sun_family = AF_UNIX, + .sun_path = "/tmp/sway-ipc.sock" +}; static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; @@ -32,17 +37,12 @@ void ipc_client_disconnect(struct ipc_client *client); void ipc_client_handle_command(struct ipc_client *client); bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); -void init_ipc() { +void ipc_init(void) { ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (ipc_socket == -1) { sway_abort("Unable to create IPC socket"); } - struct sockaddr_un ipc_sockaddr = { - .sun_family = AF_UNIX, - .sun_path = "/tmp/sway-ipc.sock" - }; - if (getenv("SWAYSOCK") != NULL) { strncpy(ipc_sockaddr.sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr.sun_path)); } @@ -56,10 +56,19 @@ void init_ipc() { sway_abort("Unable to listen on IPC socket"); } - wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); + ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); +} + +void ipc_shutdown(void) { + if (ipc_event_source) { + wlc_event_source_remove(ipc_event_source); + } + close(ipc_socket); + unlink(ipc_sockaddr.sun_path); } int ipc_handle_connection(int fd, uint32_t mask, void *data) { + (void) fd; (void) data; sway_log(L_DEBUG, "Event on IPC listening socket"); assert(mask == WLC_EVENT_READABLE); diff --git a/sway/main.c b/sway/main.c index 1af1278d..a42fbcb7 100644 --- a/sway/main.c +++ b/sway/main.c @@ -100,13 +100,15 @@ int main(int argc, char **argv) { free(config_path); } - init_ipc(); + ipc_init(); wlc_run(); if (devnull) { fclose(devnull); } + ipc_shutdown(); + return 0; } -- cgit v1.2.3-70-g09d2 From f26ed32e460f3007e623c529d28562f4a0b261cd Mon Sep 17 00:00:00 2001 From: minus Date: Thu, 20 Aug 2015 15:12:34 +0200 Subject: added sway_terminate to exit cleanly --- include/ipc.h | 2 +- sway/commands.c | 3 ++- sway/ipc.c | 2 +- sway/log.c | 3 ++- sway/main.c | 15 +++++++++++++-- 5 files changed, 19 insertions(+), 6 deletions(-) (limited to 'include/ipc.h') diff --git a/include/ipc.h b/include/ipc.h index 606c47ba..0b6441f6 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -13,6 +13,6 @@ enum ipc_command_type { }; void ipc_init(void); -void ipc_shutdown(void); +void ipc_terminate(void); #endif diff --git a/sway/commands.c b/sway/commands.c index 38557b62..644b8005 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -15,6 +15,7 @@ #include "commands.h" #include "container.h" #include "handlers.h" +#include "sway.h" struct modifier_key { char *name; @@ -186,7 +187,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) { } // Close all views container_map(&root_container, kill_views, NULL); - wlc_terminate(); + sway_terminate(); return true; } diff --git a/sway/ipc.c b/sway/ipc.c index 69f4a4f3..d55469ed 100644 --- a/sway/ipc.c +++ b/sway/ipc.c @@ -60,7 +60,7 @@ void ipc_init(void) { ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); } -void ipc_shutdown(void) { +void ipc_terminate(void) { if (ipc_event_source) { wlc_event_source_remove(ipc_event_source); } diff --git a/sway/log.c b/sway/log.c index e8c1b78f..6e01421b 100644 --- a/sway/log.c +++ b/sway/log.c @@ -1,4 +1,5 @@ #include "log.h" +#include "sway.h" #include #include #include @@ -42,7 +43,7 @@ void sway_abort(const char *format, ...) { vfprintf(stderr, format, args); va_end(args); fprintf(stderr, "\n"); - exit(1); + sway_terminate(); } void sway_log(int verbosity, const char* format, ...) { diff --git a/sway/main.c b/sway/main.c index a42fbcb7..f37f086d 100644 --- a/sway/main.c +++ b/sway/main.c @@ -10,6 +10,14 @@ #include "log.h" #include "handlers.h" #include "ipc.h" +#include "sway.h" + +static bool terminate_request = false; + +void sway_terminate(void) { + terminate_request = true; + wlc_terminate(); +} static void sigchld_handle(int signal); @@ -102,12 +110,15 @@ int main(int argc, char **argv) { ipc_init(); - wlc_run(); + if (!terminate_request) { + wlc_run(); + } + if (devnull) { fclose(devnull); } - ipc_shutdown(); + ipc_terminate(); return 0; } -- cgit v1.2.3-70-g09d2