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;

Reply via email to