Use a proper patch from upstream to fix issue https://github.com/i3/i3/issues/3579 instead of reverting some code. Comments ? Ok ? Cheers Giovanni
Index: Makefile =================================================================== RCS file: /var/cvs/ports/x11/i3/Makefile,v retrieving revision 1.115 diff -u -p -r1.115 Makefile --- Makefile 18 Jan 2019 11:34:20 -0000 1.115 +++ Makefile 19 Jan 2019 10:10:55 -0000 @@ -3,7 +3,7 @@ COMMENT = improved dynamic tiling window manager DISTNAME = i3-4.16 -REVISION = 0 +REVISION = 1 CATEGORIES = x11 Index: patches/patch-docs_ipc =================================================================== RCS file: patches/patch-docs_ipc diff -N patches/patch-docs_ipc --- patches/patch-docs_ipc 18 Jan 2019 11:34:20 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,20 +0,0 @@ -$OpenBSD: patch-docs_ipc,v 1.1 2019/01/18 11:34:20 giovanni Exp $ - -Index: docs/ipc ---- docs/ipc.orig -+++ docs/ipc -@@ -693,14 +693,6 @@ program does not want to cope which such kinds of race - event based library may not have a problem here), I suggest you create a - separate connection to receive events. - --If an event message needs to be sent and the socket is not writeable (write --returns EAGAIN, happens when the socket doesn't have enough buffer space for --writing new data) then i3 uses a queue system to store outgoing messages for --each client. This is combined with a timer: if the message queue for a client is --not empty and no data where successfully written in the past 10 seconds, the --connection is killed. Practically, this means that your client should try to --always read events from the socket to avoid having its connection closed. -- - === Subscribing to events - - By sending a message of type SUBSCRIBE with a JSON-encoded array as payload Index: patches/patch-include_config_directives_h =================================================================== RCS file: patches/patch-include_config_directives_h diff -N patches/patch-include_config_directives_h --- patches/patch-include_config_directives_h 18 Jan 2019 11:34:20 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,13 +0,0 @@ -$OpenBSD: patch-include_config_directives_h,v 1.1 2019/01/18 11:34:20 giovanni Exp $ - -Index: include/config_directives.h ---- include/config_directives.h.orig -+++ include/config_directives.h -@@ -63,7 +63,6 @@ CFGFUN(assign_output, const char *output); - CFGFUN(assign, const char *workspace, bool is_number); - CFGFUN(no_focus); - CFGFUN(ipc_socket, const char *path); --CFGFUN(ipc_kill_timeout, const long timeout_ms); - CFGFUN(restart_state, const char *path); - CFGFUN(popup_during_fullscreen, const char *value); - CFGFUN(color, const char *colorclass, const char *border, const char *background, const char *text, const char *indicator, const char *child_border); Index: patches/patch-include_ipc_h =================================================================== RCS file: /var/cvs/ports/x11/i3/patches/patch-include_ipc_h,v retrieving revision 1.5 diff -u -p -r1.5 patch-include_ipc_h --- patches/patch-include_ipc_h 18 Jan 2019 11:57:36 -0000 1.5 +++ patches/patch-include_ipc_h 19 Jan 2019 10:25:59 -0000 @@ -1,27 +1,35 @@ -$OpenBSD: patch-include_ipc_h,v 1.5 2019/01/18 11:57:36 giovanni Exp $ +$OpenBSD$ + +i3bar disappears when switch by mouse to workspace with lot of windows +https://github.com/i3/i3/issues/3579 Index: include/ipc.h --- include/ipc.h.orig +++ include/ipc.h -@@ -35,11 +35,6 @@ typedef struct ipc_client { +@@ -35,7 +35,8 @@ typedef struct ipc_client { * event has been sent by i3. */ bool first_tick_sent; - struct ev_io *callback; -- struct ev_timer *timeout; -- uint8_t *buffer; -- size_t buffer_size; -- - TAILQ_ENTRY(ipc_client) - clients; - } ipc_client; -@@ -129,9 +124,3 @@ void ipc_send_barconfig_update_event(Barconfig *barcon - * For the binding events, we send the serialized binding struct. ++ struct ev_io *read_callback; ++ struct ev_io *write_callback; + struct ev_timer *timeout; + uint8_t *buffer; + size_t buffer_size; +@@ -54,12 +55,12 @@ typedef struct ipc_client { + * message_type is the type of the message as the sender specified it. + * */ - void ipc_send_binding_event(const char *event_type, Binding *bind); -- --/** -- * Set the maximum duration that we allow for a connection with an unwriteable -- * socket. -- */ --void ipc_set_kill_timeout(ev_tstamp new); +-typedef void (*handler_t)(int, uint8_t *, int, uint32_t, uint32_t); ++typedef void (*handler_t)(ipc_client *, uint8_t *, int, uint32_t, uint32_t); + + /* Macro to declare a callback */ +-#define IPC_HANDLER(name) \ +- static void handle_##name(int fd, uint8_t *message, \ +- int size, uint32_t message_size, \ ++#define IPC_HANDLER(name) \ ++ static void handle_##name(ipc_client *client, uint8_t *message, \ ++ int size, uint32_t message_size, \ + uint32_t message_type) + + /** Index: patches/patch-include_libi3_h =================================================================== RCS file: patches/patch-include_libi3_h diff -N patches/patch-include_libi3_h --- patches/patch-include_libi3_h 18 Jan 2019 11:57:36 -0000 1.3 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,20 +0,0 @@ -$OpenBSD: patch-include_libi3_h,v 1.3 2019/01/18 11:57:36 giovanni Exp $ - -Index: include/libi3.h ---- include/libi3.h.orig -+++ include/libi3.h -@@ -167,14 +167,6 @@ int sasprintf(char **strp, const char *fmt, ...); - ssize_t writeall(int fd, const void *buf, size_t count); - - /** -- * Like writeall, but instead of retrying upon EAGAIN (returned when a write -- * would block), the function stops and returns the total number of bytes -- * written so far. -- * -- */ --ssize_t writeall_nonblock(int fd, const void *buf, size_t count); -- --/** - * Safe-wrapper around writeall which exits if it returns -1 (meaning that - * write failed) - * Index: patches/patch-libi3_safewrappers_c =================================================================== RCS file: patches/patch-libi3_safewrappers_c diff -N patches/patch-libi3_safewrappers_c --- patches/patch-libi3_safewrappers_c 18 Jan 2019 11:57:36 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,43 +0,0 @@ -$OpenBSD: patch-libi3_safewrappers_c,v 1.1 2019/01/18 11:57:36 giovanni Exp $ - -Index: libi3/safewrappers.c ---- libi3/safewrappers.c.orig -+++ libi3/safewrappers.c -@@ -68,9 +68,10 @@ int sasprintf(char **strp, const char *fmt, ...) { - - ssize_t writeall(int fd, const void *buf, size_t count) { - size_t written = 0; -+ ssize_t n = 0; - - while (written < count) { -- const ssize_t n = write(fd, ((char *)buf) + written, count - written); -+ n = write(fd, buf + written, count - written); - if (n == -1) { - if (errno == EINTR || errno == EAGAIN) - continue; -@@ -79,25 +80,6 @@ ssize_t writeall(int fd, const void *buf, size_t count - written += (size_t)n; - } - -- return written; --} -- --ssize_t writeall_nonblock(int fd, const void *buf, size_t count) { -- size_t written = 0; -- -- while (written < count) { -- const ssize_t n = write(fd, ((char *)buf) + written, count - written); -- if (n == -1) { -- if (errno == EAGAIN) { -- return written; -- } else if (errno == EINTR) { -- continue; -- } else { -- return n; -- } -- } -- written += (size_t)n; -- } - return written; - } - Index: patches/patch-parser-specs_config_spec =================================================================== RCS file: patches/patch-parser-specs_config_spec diff -N patches/patch-parser-specs_config_spec --- patches/patch-parser-specs_config_spec 18 Jan 2019 11:57:36 -0000 1.7 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,25 +0,0 @@ -$OpenBSD: patch-parser-specs_config_spec,v 1.7 2019/01/18 11:57:36 giovanni Exp $ - -Index: parser-specs/config.spec ---- parser-specs/config.spec.orig -+++ parser-specs/config.spec -@@ -49,7 +49,6 @@ state INITIAL: - 'show_marks' -> SHOW_MARKS - 'workspace' -> WORKSPACE - 'ipc_socket', 'ipc-socket' -> IPC_SOCKET -- 'ipc_kill_timeout' -> IPC_KILL_TIMEOUT - 'restart_state' -> RESTART_STATE - 'popup_during_fullscreen' -> POPUP_DURING_FULLSCREEN - exectype = 'exec_always', 'exec' -> EXEC -@@ -287,11 +286,6 @@ state WORKSPACE_OUTPUT_STR: - state IPC_SOCKET: - path = string - -> call cfg_ipc_socket($path) -- --# ipc_kill_timeout --state IPC_KILL_TIMEOUT: -- timeout = number -- -> call cfg_ipc_kill_timeout(&timeout) - - # restart_state <path> (for testcases) - state RESTART_STATE: Index: patches/patch-src_config_directives_c =================================================================== RCS file: patches/patch-src_config_directives_c diff -N patches/patch-src_config_directives_c --- patches/patch-src_config_directives_c 18 Jan 2019 11:57:36 -0000 1.5 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,16 +0,0 @@ -$OpenBSD: patch-src_config_directives_c,v 1.5 2019/01/18 11:57:36 giovanni Exp $ - -Index: src/config_directives.c ---- src/config_directives.c.orig -+++ src/config_directives.c -@@ -468,10 +468,6 @@ CFGFUN(no_focus) { - TAILQ_INSERT_TAIL(&assignments, assignment, assignments); - } - --CFGFUN(ipc_kill_timeout, const long timeout_ms) { -- ipc_set_kill_timeout(timeout_ms / 1000.0); --} -- - /******************************************************************************* - * Bar configuration (i3bar) - ******************************************************************************/ Index: patches/patch-src_ipc_c =================================================================== RCS file: /var/cvs/ports/x11/i3/patches/patch-src_ipc_c,v retrieving revision 1.18 diff -u -p -r1.18 patch-src_ipc_c --- patches/patch-src_ipc_c 18 Jan 2019 11:57:36 -0000 1.18 +++ patches/patch-src_ipc_c 19 Jan 2019 10:25:51 -0000 @@ -1,9 +1,12 @@ -$OpenBSD: patch-src_ipc_c,v 1.18 2019/01/18 11:57:36 giovanni Exp $ +$OpenBSD$ + +i3bar disappears when switch by mouse to workspace with lot of windows +https://github.com/i3/i3/issues/3579 Index: src/ipc.c --- src/ipc.c.orig +++ src/ipc.c -@@ -38,38 +38,8 @@ static void set_nonblock(int sockfd) { +@@ -38,46 +38,6 @@ static void set_nonblock(int sockfd) { err(-1, "Could not set O_NONBLOCK"); } @@ -27,8 +30,8 @@ Index: src/ipc.c - client->buffer_size += message_size; -} - - static void free_ipc_client(ipc_client *client) { - close(client->fd); +-static void free_ipc_client(ipc_client *client) { +- close(client->fd); - - ev_io_stop(main_loop, client->callback); - FREE(client->callback); @@ -39,171 +42,388 @@ Index: src/ipc.c - - free(client->buffer); - - for (int i = 0; i < client->num_events; i++) { - free(client->events[i]); - } -@@ -78,69 +48,7 @@ static void free_ipc_client(ipc_client *client) { - free(client); - } - --static void ipc_client_timeout(EV_P_ ev_timer *w, int revents); --static void ipc_socket_writeable_cb(EV_P_ struct ev_io *w, int revents); -- --static ev_tstamp kill_timeout = 10.0; -- --void ipc_set_kill_timeout(ev_tstamp new) { -- kill_timeout = new; +- for (int i = 0; i < client->num_events; i++) { +- free(client->events[i]); +- } +- free(client->events); +- TAILQ_REMOVE(&all_clients, client, clients); +- free(client); -} - + static void ipc_client_timeout(EV_P_ ev_timer *w, int revents); + static void ipc_socket_writeable_cb(EV_P_ struct ev_io *w, int revents); + +@@ -89,8 +49,8 @@ void ipc_set_kill_timeout(ev_tstamp new) { + /* -- * Try to write the contents of the pending buffer to the client's subscription + * Try to write the contents of the pending buffer to the client's subscription - * socket. Will set, reset or clear the timeout and io callbacks depending on - * the result of the write operation. -- * -- */ --static void ipc_push_pending(ipc_client *client) { -- const ssize_t result = writeall_nonblock(client->fd, client->buffer, client->buffer_size); -- if (result < 0) { -- return; -- } -- -- if ((size_t)result == client->buffer_size) { -- /* Everything was written successfully: clear the timer and stop the io -- * callback. */ -- FREE(client->buffer); -- client->buffer_size = 0; -- if (client->timeout) { -- ev_timer_stop(main_loop, client->timeout); -- FREE(client->timeout); -- } ++ * socket. Will set, reset or clear the timeout and io write callbacks depending ++ * on the result of the write operation. + * + */ + static void ipc_push_pending(ipc_client *client) { +@@ -108,13 +68,13 @@ static void ipc_push_pending(ipc_client *client) { + ev_timer_stop(main_loop, client->timeout); + FREE(client->timeout); + } - ev_io_stop(main_loop, client->callback); -- return; -- } -- -- /* Otherwise, make sure that the io callback is enabled and create a new -- * timer if needed. */ ++ ev_io_stop(main_loop, client->write_callback); + return; + } + + /* Otherwise, make sure that the io callback is enabled and create a new + * timer if needed. */ - ev_io_start(main_loop, client->callback); -- -- if (!client->timeout) { -- struct ev_timer *timeout = scalloc(1, sizeof(struct ev_timer)); -- ev_timer_init(timeout, ipc_client_timeout, kill_timeout, 0.); -- timeout->data = client; -- client->timeout = timeout; -- ev_set_priority(timeout, EV_MINPRI); -- ev_timer_start(main_loop, client->timeout); -- } else if (result > 0) { -- /* Keep the old timeout when nothing is written. Otherwise, we would -- * keep a dead connection by continuously renewing its timeouts. */ -- ev_timer_stop(main_loop, client->timeout); -- ev_timer_set(client->timeout, kill_timeout, 0.0); -- ev_timer_start(main_loop, client->timeout); -- } -- if (result == 0) { -- return; -- } -- -- /* Shift the buffer to the left and reduce the allocated space. */ -- client->buffer_size -= (size_t)result; -- memmove(client->buffer, client->buffer + result, client->buffer_size); -- client->buffer = srealloc(client->buffer, client->buffer_size); --} -- --/* ++ ev_io_start(main_loop, client->write_callback); + + if (!client->timeout) { + struct ev_timer *timeout = scalloc(1, sizeof(struct ev_timer)); +@@ -141,6 +101,54 @@ static void ipc_push_pending(ipc_client *client) { + } + + /* ++ * Given a message and a message type, create the corresponding header, merge it ++ * with the message and append it to the given client's output buffer. Also, ++ * send the message if the client's buffer was empty. ++ * ++ */ ++static void ipc_send_client_message(ipc_client *client, size_t size, const uint32_t message_type, const uint8_t *payload) { ++ const i3_ipc_header_t header = { ++ .magic = {'i', '3', '-', 'i', 'p', 'c'}, ++ .size = size, ++ .type = message_type}; ++ const size_t header_size = sizeof(i3_ipc_header_t); ++ const size_t message_size = header_size + size; ++ ++ const bool push_now = (client->buffer_size == 0); ++ client->buffer = srealloc(client->buffer, client->buffer_size + message_size); ++ memcpy(client->buffer + client->buffer_size, ((void *)&header), header_size); ++ memcpy(client->buffer + client->buffer_size + header_size, payload, size); ++ client->buffer_size += message_size; ++ ++ if (push_now) { ++ ipc_push_pending(client); ++ } ++} ++ ++static void free_ipc_client(ipc_client *client) { ++ DLOG("Disconnecting client on fd %d\n", client->fd); ++ close(client->fd); ++ ++ ev_io_stop(main_loop, client->read_callback); ++ FREE(client->read_callback); ++ ev_io_stop(main_loop, client->write_callback); ++ FREE(client->write_callback); ++ if (client->timeout) { ++ ev_timer_stop(main_loop, client->timeout); ++ FREE(client->timeout); ++ } ++ ++ free(client->buffer); ++ ++ for (int i = 0; i < client->num_events; i++) { ++ free(client->events[i]); ++ } ++ free(client->events); ++ TAILQ_REMOVE(&all_clients, client, clients); ++ free(client); ++} ++ ++/* * Sends the specified event to all IPC clients which are currently connected * and subscribed to this kind of event. * -@@ -159,11 +67,7 @@ void ipc_send_event(const char *event, uint32_t messag - if (!interested) - continue; - +@@ -148,22 +156,12 @@ static void ipc_push_pending(ipc_client *client) { + void ipc_send_event(const char *event, uint32_t message_type, const char *payload) { + ipc_client *current; + TAILQ_FOREACH(current, &all_clients, clients) { +- /* see if this client is interested in this event */ +- bool interested = false; + for (int i = 0; i < current->num_events; i++) { +- if (strcasecmp(current->events[i], event) != 0) +- continue; +- interested = true; +- break; ++ if (strcasecmp(current->events[i], event) == 0) { ++ ipc_send_client_message(current, strlen(payload), message_type, (uint8_t *)payload); ++ break; ++ } + } +- if (!interested) +- continue; +- - const bool push_now = (current->buffer_size == 0); - append_payload(current, message_type, payload); - if (push_now) { - ipc_push_pending(current); - } -+ ipc_send_message(current->fd, strlen(payload), message_type, (const uint8_t *)payload); } } -@@ -1382,62 +1286,6 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, - FREE(message); +@@ -234,8 +232,8 @@ IPC_HANDLER(run_command) { + ylength length; + yajl_gen_get_buf(gen, &reply, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND, +- (const uint8_t *)reply); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_COMMAND, ++ (const uint8_t *)reply); + + yajl_gen_free(gen); } +@@ -838,7 +836,7 @@ IPC_HANDLER(tree) { + ylength length; + y(get_buf, &payload, &length); --static void ipc_client_timeout(EV_P_ ev_timer *w, int revents) { -- /* No need to be polite and check for writeability, the other callback would -- * have been called by now. */ -- ipc_client *client = (ipc_client *)w->data; -- -- char *cmdline = NULL; --#if defined(__linux__) && defined(SO_PEERCRED) -- struct ucred peercred; -- socklen_t so_len = sizeof(peercred); -- if (getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0) { -- goto end; -- } -- char *exepath; -- sasprintf(&exepath, "/proc/%d/cmdline", peercred.pid); -- -- int fd = open(exepath, O_RDONLY); -- free(exepath); -- if (fd == -1) { -- goto end; -- } -- char buf[512] = {'\0'}; /* cut off cmdline for the error message. */ -- const ssize_t n = read(fd, buf, sizeof(buf)); -- close(fd); -- if (n < 0) { -- goto end; -- } -- for (char *walk = buf; walk < buf + n - 1; walk++) { -- if (*walk == '\0') { -- *walk = ' '; -- } -- } -- cmdline = buf; +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_TREE, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_TREE, payload); + y(free); + } + +@@ -902,7 +900,7 @@ IPC_HANDLER(get_workspaces) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload); + y(free); + } + +@@ -956,7 +954,7 @@ IPC_HANDLER(get_outputs) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload); + y(free); + } + +@@ -983,7 +981,7 @@ IPC_HANDLER(get_marks) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_MARKS, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_MARKS, payload); + y(free); + } + +@@ -1016,7 +1014,7 @@ IPC_HANDLER(get_version) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_VERSION, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_VERSION, payload); + y(free); + } + +@@ -1041,7 +1039,7 @@ IPC_HANDLER(get_bar_config) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); + y(free); + return; + } +@@ -1078,7 +1076,7 @@ IPC_HANDLER(get_bar_config) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload); + y(free); + } + +@@ -1100,7 +1098,7 @@ IPC_HANDLER(get_binding_modes) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BINDING_MODES, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BINDING_MODES, payload); + y(free); + } + +@@ -1139,22 +1137,7 @@ static int add_subscription(void *extra, const unsigne + IPC_HANDLER(subscribe) { + yajl_handle p; + yajl_status stat; +- ipc_client *current, *client = NULL; + +- /* Search the ipc_client structure for this connection */ +- TAILQ_FOREACH(current, &all_clients, clients) { +- if (current->fd != fd) +- continue; - -- if (cmdline) { -- ELOG("client %p with pid %d and cmdline '%s' on fd %d timed out, killing\n", client, peercred.pid, cmdline, client->fd); +- client = current; +- break; - } - --end: --#endif -- if (!cmdline) { -- ELOG("client %p on fd %d timed out, killing\n", client, client->fd); +- if (client == NULL) { +- ELOG("Could not find ipc_client data structure for fd %d\n", fd); +- return; - } - -- free_ipc_client(client); --} + /* Setup the JSON parser */ + static yajl_callbacks callbacks = { + .yajl_string = add_subscription, +@@ -1170,13 +1153,13 @@ IPC_HANDLER(subscribe) { + yajl_free_error(p, err); + + const char *reply = "{\"success\":false}"; +- ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply); ++ ipc_send_client_message(client, 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, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply); ++ ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply); + + if (client->first_tick_sent) { + return; +@@ -1195,7 +1178,7 @@ IPC_HANDLER(subscribe) { + + client->first_tick_sent = true; + const char *payload = "{\"first\":true,\"payload\":\"\"}"; +- ipc_send_message(client->fd, strlen(payload), I3_IPC_EVENT_TICK, (const uint8_t *)payload); ++ ipc_send_client_message(client, strlen(payload), I3_IPC_EVENT_TICK, (const uint8_t *)payload); + } + + /* +@@ -1215,7 +1198,7 @@ IPC_HANDLER(get_config) { + ylength length; + y(get_buf, &payload, &length); + +- ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_CONFIG, payload); ++ ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_CONFIG, payload); + y(free); + } + +@@ -1244,7 +1227,7 @@ IPC_HANDLER(send_tick) { + y(free); + + const char *reply = "{\"success\":true}"; +- ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_TICK, (const uint8_t *)reply); ++ ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_TICK, (const uint8_t *)reply); + DLOG("Sent tick event\n"); + } + +@@ -1295,7 +1278,7 @@ IPC_HANDLER(sync) { + yajl_free_error(p, err); + + const char *reply = "{\"success\":false}"; +- ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply); ++ ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply); + yajl_free(p); + return; + } +@@ -1304,7 +1287,7 @@ IPC_HANDLER(sync) { + DLOG("received IPC sync request (rnd = %d, window = 0x%08x)\n", state.rnd, state.window); + sync_respond(state.window, state.rnd); + const char *reply = "{\"success\":true}"; +- ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply); ++ ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply); + } + + /* The index of each callback function corresponds to the numeric +@@ -1338,6 +1321,8 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, + uint32_t message_type; + uint32_t message_length; + uint8_t *message = NULL; ++ ipc_client *client = (ipc_client *)w->data; ++ assert(client->fd == w->fd); + + int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message); + /* EOF or other error */ +@@ -1350,25 +1335,8 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, + + /* If not, there was some kind of error. We don’t bother and close the + * connection. Delete the client from the list of clients. */ +- bool closed = false; +- ipc_client *current; +- TAILQ_FOREACH(current, &all_clients, clients) { +- if (current->fd != w->fd) +- continue; +- +- free_ipc_client(current); +- closed = true; +- break; +- } +- if (!closed) { +- close(w->fd); +- } - --static void ipc_socket_writeable_cb(EV_P_ ev_io *w, int revents) { -- DLOG("fd %d writeable\n", w->fd); -- ipc_client *client = (ipc_client *)w->data; -- -- /* If this callback is called then there should be a corresponding active -- * timer. */ -- assert(client->timeout != NULL); -- ipc_push_pending(client); --} +- ev_io_stop(EV_A_ w); +- free(w); ++ free_ipc_client(client); + FREE(message); - - /* - * Handler for activity on the listening socket, meaning that a new client - * has just connected and we should accept() him. Sets up the event handler -@@ -1466,16 +1314,11 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents - ev_io_init(package, ipc_receive_message, client, EV_READ); - ev_io_start(EV_A_ package); +- DLOG("IPC: client disconnected\n"); + return; + } + +@@ -1376,7 +1344,7 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, + DLOG("Unhandled message type: %d\n", message_type); + else { + handler_t h = handlers[message_type]; +- h(w->fd, message, 0, message_length, message_type); ++ h(client, message, 0, message_length, message_type); + } + + FREE(message); +@@ -1448,36 +1416,33 @@ static void ipc_socket_writeable_cb(EV_P_ ev_io *w, in + void ipc_new_client(EV_P_ struct ev_io *w, int revents) { + struct sockaddr_un peer; + socklen_t len = sizeof(struct sockaddr_un); +- int client; +- if ((client = accept(w->fd, (struct sockaddr *)&peer, &len)) < 0) { +- if (errno == EINTR) +- return; +- else ++ int fd; ++ if ((fd = accept(w->fd, (struct sockaddr *)&peer, &len)) < 0) { ++ if (errno != EINTR) { + perror("accept()"); ++ } + return; + } + + /* Close this file descriptor on exec() */ +- (void)fcntl(client, F_SETFD, FD_CLOEXEC); ++ (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + +- set_nonblock(client); ++ set_nonblock(fd); + +- struct ev_io *package = scalloc(1, sizeof(struct ev_io)); +- ev_io_init(package, ipc_receive_message, client, EV_READ); +- ev_io_start(EV_A_ package); ++ ipc_client *client = scalloc(1, sizeof(ipc_client)); ++ client->fd = fd; - ipc_client *new = scalloc(1, sizeof(ipc_client)); -- ++ client->read_callback = scalloc(1, sizeof(struct ev_io)); ++ client->read_callback->data = client; ++ ev_io_init(client->read_callback, ipc_receive_message, fd, EV_READ); ++ ev_io_start(EV_A_ client->read_callback); + - package = scalloc(1, sizeof(struct ev_io)); - package->data = new; - ev_io_init(package, ipc_socket_writeable_cb, client, EV_WRITE); -- - DLOG("IPC: new client connected on fd %d\n", w->fd); ++ client->write_callback = scalloc(1, sizeof(struct ev_io)); ++ client->write_callback->data = client; ++ ev_io_init(client->write_callback, ipc_socket_writeable_cb, fd, EV_WRITE); -+ -+ ipc_client *new = scalloc(1, sizeof(ipc_client)); - new->fd = client; + DLOG("IPC: new client connected on fd %d\n", w->fd); +- +- new->fd = client; - new->callback = package; - - TAILQ_INSERT_TAIL(&all_clients, new, clients); +- +- TAILQ_INSERT_TAIL(&all_clients, new, clients); ++ TAILQ_INSERT_TAIL(&all_clients, client, clients); } + + /* Index: patches/patch-testcases_t_201-config-parser_t =================================================================== RCS file: patches/patch-testcases_t_201-config-parser_t diff -N patches/patch-testcases_t_201-config-parser_t --- patches/patch-testcases_t_201-config-parser_t 18 Jan 2019 11:57:36 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,13 +0,0 @@ -$OpenBSD: patch-testcases_t_201-config-parser_t,v 1.1 2019/01/18 11:57:36 giovanni Exp $ - -Index: testcases/t/201-config-parser.t ---- testcases/t/201-config-parser.t.orig -+++ testcases/t/201-config-parser.t -@@ -502,7 +502,6 @@ my $expected_all_tokens = "ERROR: CONFIG: Expected one - workspace - ipc_socket - ipc-socket -- ipc_kill_timeout - restart_state - popup_during_fullscreen - exec_always Index: patches/patch-testcases_t_298-ipc-misbehaving-connection_t =================================================================== RCS file: patches/patch-testcases_t_298-ipc-misbehaving-connection_t diff -N patches/patch-testcases_t_298-ipc-misbehaving-connection_t --- patches/patch-testcases_t_298-ipc-misbehaving-connection_t 18 Jan 2019 11:57:36 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,75 +0,0 @@ -$OpenBSD: patch-testcases_t_298-ipc-misbehaving-connection_t,v 1.1 2019/01/18 11:57:36 giovanni Exp $ - -Index: testcases/t/298-ipc-misbehaving-connection.t ---- testcases/t/298-ipc-misbehaving-connection.t.orig -+++ testcases/t/298-ipc-misbehaving-connection.t -@@ -1,69 +0,0 @@ --#!perl --# vim:ts=4:sw=4:expandtab --# --# Please read the following documents before working on tests: --# • https://build.i3wm.org/docs/testsuite.html --# (or docs/testsuite) --# --# • https://build.i3wm.org/docs/lib-i3test.html --# (alternatively: perldoc ./testcases/lib/i3test.pm) --# --# • https://build.i3wm.org/docs/ipc.html --# (or docs/ipc) --# --# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf --# (unless you are already familiar with Perl) --# --# Test that i3 will not hang if a connected client stops reading from its --# subscription socket and that the client is killed after a delay. --# Ticket: #2999 --# Bug still in: 4.15-180-g715cea61 --use i3test i3_config => <<EOT; --# i3 config file (v4) --font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 --# Set the timeout to 500ms to reduce the duration of this test. --ipc_kill_timeout 500 --EOT -- --# Manually connect to i3 so that we can choose to not read events --use IO::Socket::UNIX; --my $sock = IO::Socket::UNIX->new(Peer => get_socket_path()); --my $magic = "i3-ipc"; --my $payload = '["workspace"]'; --my $message = $magic . pack("LL", length($payload), 2) . $payload; --print $sock $message; -- --# Constantly switch between 2 workspaces to generate events. --fresh_workspace; --open_window; --fresh_workspace; --open_window; -- --eval { -- local $SIG{ALRM} = sub { die "Timeout\n" }; -- # 500 is an arbitrarily large number to make sure that the socket becomes -- # non-writeable. -- for (my $i = 0; $i < 500; $i++) { -- alarm 1; -- cmd 'workspace back_and_forth'; -- alarm 0; -- } --}; --ok(!$@, 'i3 didn\'t hang'); -- --# Wait for connection timeout --sleep 1; -- --use IO::Select; --my $s = IO::Select->new($sock); --my $reached_eof = 0; --while ($s->can_read(0.05)) { -- if (read($sock, my $buffer, 100) == 0) { -- $reached_eof = 1; -- last; -- } --} --ok($reached_eof, 'socket connection closed'); -- --close $sock; --done_testing;