dwm

Kris's build of dwm
git clone git clone https://git.krisyotam.com/krisyotam/dwm.git
Log | Files | Refs | README | LICENSE

ipc.c (34017B)


      1 #include "ipc.h"
      2 
      3 #include <errno.h>
      4 #include <fcntl.h>
      5 #include <inttypes.h>
      6 #include <stdarg.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <sys/epoll.h>
     10 #include <sys/socket.h>
     11 #include <sys/un.h>
     12 #include <unistd.h>
     13 #include <yajl/yajl_gen.h>
     14 #include <yajl/yajl_tree.h>
     15 
     16 #include "util.h"
     17 #include "yajl_dumps.h"
     18 
     19 static struct sockaddr_un sockaddr;
     20 static struct epoll_event sock_epoll_event;
     21 static IPCClientList ipc_clients = NULL;
     22 static int epoll_fd = -1;
     23 static int sock_fd = -1;
     24 static IPCCommand *ipc_commands;
     25 static unsigned int ipc_commands_len;
     26 // Max size is 1 MB
     27 static const uint32_t MAX_MESSAGE_SIZE = 1000000;
     28 static const int IPC_SOCKET_BACKLOG = 5;
     29 
     30 /**
     31  * Create IPC socket at specified path and return file descriptor to socket.
     32  * This initializes the static variable sockaddr.
     33  */
     34 static int
     35 ipc_create_socket(const char *filename)
     36 {
     37   char *normal_filename;
     38   char *parent;
     39   const size_t addr_size = sizeof(struct sockaddr_un);
     40   const int sock_type = SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
     41 
     42   normalizepath(filename, &normal_filename);
     43 
     44   // In case socket file exists
     45   unlink(normal_filename);
     46 
     47   // For portability clear the addr structure, since some implementations have
     48   // nonstandard fields in the structure
     49   memset(&sockaddr, 0, addr_size);
     50 
     51   parentdir(normal_filename, &parent);
     52   // Create parent directories
     53   mkdirp(parent);
     54   free(parent);
     55 
     56   sockaddr.sun_family = AF_LOCAL;
     57   strcpy(sockaddr.sun_path, normal_filename);
     58   free(normal_filename);
     59 
     60   sock_fd = socket(AF_LOCAL, sock_type, 0);
     61   if (sock_fd == -1) {
     62     fputs("Failed to create socket\n", stderr);
     63     return -1;
     64   }
     65 
     66   DEBUG("Created socket at %s\n", sockaddr.sun_path);
     67 
     68   if (bind(sock_fd, (const struct sockaddr *)&sockaddr, addr_size) == -1) {
     69     fputs("Failed to bind socket\n", stderr);
     70     return -1;
     71   }
     72 
     73   DEBUG("Socket binded\n");
     74 
     75   if (listen(sock_fd, IPC_SOCKET_BACKLOG) < 0) {
     76     fputs("Failed to listen for connections on socket\n", stderr);
     77     return -1;
     78   }
     79 
     80   DEBUG("Now listening for connections on socket\n");
     81 
     82   return sock_fd;
     83 }
     84 
     85 /**
     86  * Internal function used to receive IPC messages from a given file descriptor.
     87  *
     88  * Returns -1 on error reading (could be EAGAIN or EINTR)
     89  * Returns -2 if EOF before header could be read
     90  * Returns -3 if invalid IPC header
     91  * Returns -4 if message length exceeds MAX_MESSAGE_SIZE
     92  */
     93 static int
     94 ipc_recv_message(int fd, uint8_t *msg_type, uint32_t *reply_size,
     95                  uint8_t **reply)
     96 {
     97   uint32_t read_bytes = 0;
     98   const int32_t to_read = sizeof(dwm_ipc_header_t);
     99   char header[to_read];
    100   char *walk = header;
    101 
    102   // Try to read header
    103   while (read_bytes < to_read) {
    104     const ssize_t n = read(fd, header + read_bytes, to_read - read_bytes);
    105 
    106     if (n == 0) {
    107       if (read_bytes == 0) {
    108         fprintf(stderr, "Unexpectedly reached EOF while reading header.");
    109         fprintf(stderr,
    110                 "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
    111                 read_bytes, to_read);
    112         return -2;
    113       } else {
    114         fprintf(stderr, "Unexpectedly reached EOF while reading header.");
    115         fprintf(stderr,
    116                 "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
    117                 read_bytes, to_read);
    118         return -3;
    119       }
    120     } else if (n == -1) {
    121       // errno will still be set
    122       return -1;
    123     }
    124 
    125     read_bytes += n;
    126   }
    127 
    128   // Check if magic string in header matches
    129   if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) {
    130     fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n",
    131             IPC_MAGIC_LEN, walk, IPC_MAGIC);
    132     return -3;
    133   }
    134 
    135   walk += IPC_MAGIC_LEN;
    136 
    137   // Extract reply size
    138   memcpy(reply_size, walk, sizeof(uint32_t));
    139   walk += sizeof(uint32_t);
    140 
    141   if (*reply_size > MAX_MESSAGE_SIZE) {
    142     fprintf(stderr, "Message too long: %" PRIu32 " bytes. ", *reply_size);
    143     fprintf(stderr, "Maximum message size is: %d\n", MAX_MESSAGE_SIZE);
    144     return -4;
    145   }
    146 
    147   // Extract message type
    148   memcpy(msg_type, walk, sizeof(uint8_t));
    149   walk += sizeof(uint8_t);
    150 
    151   if (*reply_size > 0)
    152     (*reply) = malloc(*reply_size);
    153   else
    154     return 0;
    155 
    156   read_bytes = 0;
    157   while (read_bytes < *reply_size) {
    158     const ssize_t n = read(fd, *reply + read_bytes, *reply_size - read_bytes);
    159 
    160     if (n == 0) {
    161       fprintf(stderr, "Unexpectedly reached EOF while reading payload.");
    162       fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n",
    163               read_bytes, *reply_size);
    164       free(*reply);
    165       return -2;
    166     } else if (n == -1) {
    167       // TODO: Should we return and wait for another epoll event?
    168       // This would require saving the partial read in some way.
    169       if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue;
    170 
    171       free(*reply);
    172       return -1;
    173     }
    174 
    175     read_bytes += n;
    176   }
    177 
    178   return 0;
    179 }
    180 
    181 /**
    182  * Internal function used to write a buffer to a file descriptor
    183  *
    184  * Returns number of bytes written if successful write
    185  * Returns 0 if no bytes were written due to EAGAIN or EWOULDBLOCK
    186  * Returns -1 on unknown error trying to write, errno will carry over from
    187  *   write() call
    188  */
    189 static ssize_t
    190 ipc_write_message(int fd, const void *buf, size_t count)
    191 {
    192   size_t written = 0;
    193 
    194   while (written < count) {
    195     const ssize_t n = write(fd, (uint8_t *)buf + written, count - written);
    196 
    197     if (n == -1) {
    198       if (errno == EAGAIN || errno == EWOULDBLOCK)
    199         return written;
    200       else if (errno == EINTR)
    201         continue;
    202       else
    203         return n;
    204     }
    205 
    206     written += n;
    207     DEBUG("Wrote %zu/%zu to client at fd %d\n", written, count, fd);
    208   }
    209 
    210   return written;
    211 }
    212 
    213 /**
    214  * Initialization for generic event message. This is used to allocate the yajl
    215  * handle, set yajl options, and in the future any other initialization that
    216  * should occur for event messages.
    217  */
    218 static void
    219 ipc_event_init_message(yajl_gen *gen)
    220 {
    221   *gen = yajl_gen_alloc(NULL);
    222   yajl_gen_config(*gen, yajl_gen_beautify, 1);
    223 }
    224 
    225 /**
    226  * Prepares buffers of IPC subscribers of specified event using buffer from yajl
    227  * handle.
    228  */
    229 static void
    230 ipc_event_prepare_send_message(yajl_gen gen, IPCEvent event)
    231 {
    232   const unsigned char *buffer;
    233   size_t len = 0;
    234 
    235   yajl_gen_get_buf(gen, &buffer, &len);
    236   len++;  // For null char
    237 
    238   for (IPCClient *c = ipc_clients; c; c = c->next) {
    239     if (c->subscriptions & event) {
    240       DEBUG("Sending selected client change event to fd %d\n", c->fd);
    241       ipc_prepare_send_message(c, IPC_TYPE_EVENT, len, (char *)buffer);
    242     }
    243   }
    244 
    245   // Not documented, but this frees temp_buffer
    246   yajl_gen_free(gen);
    247 }
    248 
    249 /**
    250  * Initialization for generic reply message. This is used to allocate the yajl
    251  * handle, set yajl options, and in the future any other initialization that
    252  * should occur for reply messages.
    253  */
    254 static void
    255 ipc_reply_init_message(yajl_gen *gen)
    256 {
    257   *gen = yajl_gen_alloc(NULL);
    258   yajl_gen_config(*gen, yajl_gen_beautify, 1);
    259 }
    260 
    261 /**
    262  * Prepares the IPC client's buffer with a message using the buffer of the yajl
    263  * handle.
    264  */
    265 static void
    266 ipc_reply_prepare_send_message(yajl_gen gen, IPCClient *c,
    267                                IPCMessageType msg_type)
    268 {
    269   const unsigned char *buffer;
    270   size_t len = 0;
    271 
    272   yajl_gen_get_buf(gen, &buffer, &len);
    273   len++;  // For null char
    274 
    275   ipc_prepare_send_message(c, msg_type, len, (const char *)buffer);
    276 
    277   // Not documented, but this frees temp_buffer
    278   yajl_gen_free(gen);
    279 }
    280 
    281 /**
    282  * Find the IPCCommand with the specified name
    283  *
    284  * Returns 0 if a command with the specified name was found
    285  * Returns -1 if a command with the specified name could not be found
    286  */
    287 static int
    288 ipc_get_ipc_command(const char *name, IPCCommand *ipc_command)
    289 {
    290   for (int i = 0; i < ipc_commands_len; i++) {
    291     if (strcmp(ipc_commands[i].name, name) == 0) {
    292       *ipc_command = ipc_commands[i];
    293       return 0;
    294     }
    295   }
    296 
    297   return -1;
    298 }
    299 
    300 /**
    301  * Parse a IPC_TYPE_RUN_COMMAND message from a client. This function extracts
    302  * the arguments, argument count, argument types, and command name and returns
    303  * the parsed information as an IPCParsedCommand. If this function returns
    304  * successfully, the parsed_command must be freed using
    305  * ipc_free_parsed_command_members.
    306  *
    307  * Returns 0 if the message was successfully parsed
    308  * Returns -1 otherwise
    309  */
    310 static int
    311 ipc_parse_run_command(char *msg, IPCParsedCommand *parsed_command)
    312 {
    313   char error_buffer[1000];
    314   yajl_val parent = yajl_tree_parse(msg, error_buffer, 1000);
    315 
    316   if (parent == NULL) {
    317     fputs("Failed to parse command from client\n", stderr);
    318     fprintf(stderr, "%s\n", error_buffer);
    319     fprintf(stderr, "Tried to parse: %s\n", msg);
    320     return -1;
    321   }
    322 
    323   // Format:
    324   // {
    325   //   "command": "<command name>"
    326   //   "args": [ "arg1", "arg2", ... ]
    327   // }
    328   const char *command_path[] = {"command", 0};
    329   yajl_val command_val = yajl_tree_get(parent, command_path, yajl_t_string);
    330 
    331   if (command_val == NULL) {
    332     fputs("No command key found in client message\n", stderr);
    333     yajl_tree_free(parent);
    334     return -1;
    335   }
    336 
    337   const char *command_name = YAJL_GET_STRING(command_val);
    338   size_t command_name_len = strlen(command_name);
    339   parsed_command->name = (char *)malloc((command_name_len + 1) * sizeof(char));
    340   strcpy(parsed_command->name, command_name);
    341 
    342   DEBUG("Received command: %s\n", parsed_command->name);
    343 
    344   const char *args_path[] = {"args", 0};
    345   yajl_val args_val = yajl_tree_get(parent, args_path, yajl_t_array);
    346 
    347   if (args_val == NULL) {
    348     fputs("No args key found in client message\n", stderr);
    349     yajl_tree_free(parent);
    350     return -1;
    351   }
    352 
    353   unsigned int *argc = &parsed_command->argc;
    354   Arg **args = &parsed_command->args;
    355   ArgType **arg_types = &parsed_command->arg_types;
    356 
    357   *argc = args_val->u.array.len;
    358 
    359   // If no arguments are specified, make a dummy argument to pass to the
    360   // function. This is just the way dwm's void(Arg*) functions are setup.
    361   if (*argc == 0) {
    362     *args = (Arg *)malloc(sizeof(Arg));
    363     *arg_types = (ArgType *)malloc(sizeof(ArgType));
    364     (*arg_types)[0] = ARG_TYPE_NONE;
    365     (*args)[0].f = 0;
    366     (*argc)++;
    367   } else if (*argc > 0) {
    368     *args = (Arg *)calloc(*argc, sizeof(Arg));
    369     *arg_types = (ArgType *)malloc(*argc * sizeof(ArgType));
    370 
    371     for (int i = 0; i < *argc; i++) {
    372       yajl_val arg_val = args_val->u.array.values[i];
    373 
    374       if (YAJL_IS_NUMBER(arg_val)) {
    375         if (YAJL_IS_INTEGER(arg_val)) {
    376           // Any values below 0 must be a signed int
    377           if (YAJL_GET_INTEGER(arg_val) < 0) {
    378             (*args)[i].i = YAJL_GET_INTEGER(arg_val);
    379             (*arg_types)[i] = ARG_TYPE_SINT;
    380             DEBUG("i=%ld\n", (*args)[i].i);
    381             // Any values above 0 should be an unsigned int
    382           } else if (YAJL_GET_INTEGER(arg_val) >= 0) {
    383             (*args)[i].ui = YAJL_GET_INTEGER(arg_val);
    384             (*arg_types)[i] = ARG_TYPE_UINT;
    385             DEBUG("ui=%ld\n", (*args)[i].i);
    386           }
    387           // If the number is not an integer, it must be a float
    388         } else {
    389           (*args)[i].f = (float)YAJL_GET_DOUBLE(arg_val);
    390           (*arg_types)[i] = ARG_TYPE_FLOAT;
    391           DEBUG("f=%f\n", (*args)[i].f);
    392           // If argument is not a number, it must be a string
    393         }
    394       } else if (YAJL_IS_STRING(arg_val)) {
    395         char *arg_s = YAJL_GET_STRING(arg_val);
    396         size_t arg_s_size = (strlen(arg_s) + 1) * sizeof(char);
    397         (*args)[i].v = (char *)malloc(arg_s_size);
    398         (*arg_types)[i] = ARG_TYPE_STR;
    399         strcpy((char *)(*args)[i].v, arg_s);
    400       }
    401     }
    402   }
    403 
    404   yajl_tree_free(parent);
    405 
    406   return 0;
    407 }
    408 
    409 /**
    410  * Free the members of a IPCParsedCommand struct
    411  */
    412 static void
    413 ipc_free_parsed_command_members(IPCParsedCommand *command)
    414 {
    415   for (int i = 0; i < command->argc; i++) {
    416     if (command->arg_types[i] == ARG_TYPE_STR) free((void *)command->args[i].v);
    417   }
    418   free(command->args);
    419   free(command->arg_types);
    420   free(command->name);
    421 }
    422 
    423 /**
    424  * Check if the given arguments are the correct length and type. Also do any
    425  * casting to correct the types.
    426  *
    427  * Returns 0 if the arguments were the correct length and types
    428  * Returns -1 if the argument count doesn't match
    429  * Returns -2 if the argument types don't match
    430  */
    431 static int
    432 ipc_validate_run_command(IPCParsedCommand *parsed, const IPCCommand actual)
    433 {
    434   if (actual.argc != parsed->argc) return -1;
    435 
    436   for (int i = 0; i < parsed->argc; i++) {
    437     ArgType ptype = parsed->arg_types[i];
    438     ArgType atype = actual.arg_types[i];
    439 
    440     if (ptype != atype) {
    441       if (ptype == ARG_TYPE_UINT && atype == ARG_TYPE_PTR)
    442         // If this argument is supposed to be a void pointer, cast it
    443         parsed->args[i].v = (void *)parsed->args[i].ui;
    444       else if (ptype == ARG_TYPE_UINT && atype == ARG_TYPE_SINT)
    445         // If this argument is supposed to be a signed int, cast it
    446         parsed->args[i].i = parsed->args[i].ui;
    447       else
    448         return -2;
    449     }
    450   }
    451 
    452   return 0;
    453 }
    454 
    455 /**
    456  * Convert event name to their IPCEvent equivalent enum value
    457  *
    458  * Returns 0 if a valid event name was given
    459  * Returns -1 otherwise
    460  */
    461 static int
    462 ipc_event_stoi(const char *subscription, IPCEvent *event)
    463 {
    464   if (strcmp(subscription, "tag_change_event") == 0)
    465     *event = IPC_EVENT_TAG_CHANGE;
    466   else if (strcmp(subscription, "client_focus_change_event") == 0)
    467     *event = IPC_EVENT_CLIENT_FOCUS_CHANGE;
    468   else if (strcmp(subscription, "layout_change_event") == 0)
    469     *event = IPC_EVENT_LAYOUT_CHANGE;
    470   else if (strcmp(subscription, "monitor_focus_change_event") == 0)
    471     *event = IPC_EVENT_MONITOR_FOCUS_CHANGE;
    472   else if (strcmp(subscription, "focused_title_change_event") == 0)
    473     *event = IPC_EVENT_FOCUSED_TITLE_CHANGE;
    474   else if (strcmp(subscription, "focused_state_change_event") == 0)
    475     *event = IPC_EVENT_FOCUSED_STATE_CHANGE;
    476   else
    477     return -1;
    478   return 0;
    479 }
    480 
    481 /**
    482  * Parse a IPC_TYPE_SUBSCRIBE message from a client. This function extracts the
    483  * event name and the subscription action from the message.
    484  *
    485  * Returns 0 if message was successfully parsed
    486  * Returns -1 otherwise
    487  */
    488 static int
    489 ipc_parse_subscribe(const char *msg, IPCSubscriptionAction *subscribe,
    490                     IPCEvent *event)
    491 {
    492   char error_buffer[100];
    493   yajl_val parent = yajl_tree_parse((char *)msg, error_buffer, 100);
    494 
    495   if (parent == NULL) {
    496     fputs("Failed to parse command from client\n", stderr);
    497     fprintf(stderr, "%s\n", error_buffer);
    498     return -1;
    499   }
    500 
    501   // Format:
    502   // {
    503   //   "event": "<event name>"
    504   //   "action": "<subscribe|unsubscribe>"
    505   // }
    506   const char *event_path[] = {"event", 0};
    507   yajl_val event_val = yajl_tree_get(parent, event_path, yajl_t_string);
    508 
    509   if (event_val == NULL) {
    510     fputs("No 'event' key found in client message\n", stderr);
    511     return -1;
    512   }
    513 
    514   const char *event_str = YAJL_GET_STRING(event_val);
    515   DEBUG("Received event: %s\n", event_str);
    516 
    517   if (ipc_event_stoi(event_str, event) < 0) return -1;
    518 
    519   const char *action_path[] = {"action", 0};
    520   yajl_val action_val = yajl_tree_get(parent, action_path, yajl_t_string);
    521 
    522   if (action_val == NULL) {
    523     fputs("No 'action' key found in client message\n", stderr);
    524     return -1;
    525   }
    526 
    527   const char *action = YAJL_GET_STRING(action_val);
    528 
    529   if (strcmp(action, "subscribe") == 0)
    530     *subscribe = IPC_ACTION_SUBSCRIBE;
    531   else if (strcmp(action, "unsubscribe") == 0)
    532     *subscribe = IPC_ACTION_UNSUBSCRIBE;
    533   else {
    534     fputs("Invalid action specified for subscription\n", stderr);
    535     return -1;
    536   }
    537 
    538   yajl_tree_free(parent);
    539 
    540   return 0;
    541 }
    542 
    543 /**
    544  * Parse an IPC_TYPE_GET_DWM_CLIENT message from a client. This function
    545  * extracts the window id from the message.
    546  *
    547  * Returns 0 if message was successfully parsed
    548  * Returns -1 otherwise
    549  */
    550 static int
    551 ipc_parse_get_dwm_client(const char *msg, Window *win)
    552 {
    553   char error_buffer[100];
    554 
    555   yajl_val parent = yajl_tree_parse(msg, error_buffer, 100);
    556 
    557   if (parent == NULL) {
    558     fputs("Failed to parse message from client\n", stderr);
    559     fprintf(stderr, "%s\n", error_buffer);
    560     return -1;
    561   }
    562 
    563   // Format:
    564   // {
    565   //   "client_window_id": <client window id>
    566   // }
    567   const char *win_path[] = {"client_window_id", 0};
    568   yajl_val win_val = yajl_tree_get(parent, win_path, yajl_t_number);
    569 
    570   if (win_val == NULL) {
    571     fputs("No client window id found in client message\n", stderr);
    572     return -1;
    573   }
    574 
    575   *win = YAJL_GET_INTEGER(win_val);
    576 
    577   yajl_tree_free(parent);
    578 
    579   return 0;
    580 }
    581 
    582 /**
    583  * Called when an IPC_TYPE_RUN_COMMAND message is received from a client. This
    584  * function parses, executes the given command, and prepares a reply message to
    585  * the client indicating success/failure.
    586  *
    587  * NOTE: There is currently no check for argument validity beyond the number of
    588  * arguments given and types of arguments. There is also no way to check if the
    589  * function succeeded based on dwm's void(const Arg*) function types. Pointer
    590  * arguments can cause crashes if they are not validated in the function itself.
    591  *
    592  * Returns 0 if message was successfully parsed
    593  * Returns -1 on failure parsing message
    594  */
    595 static int
    596 ipc_run_command(IPCClient *ipc_client, char *msg)
    597 {
    598   IPCParsedCommand parsed_command;
    599   IPCCommand ipc_command;
    600 
    601   // Initialize struct
    602   memset(&parsed_command, 0, sizeof(IPCParsedCommand));
    603 
    604   if (ipc_parse_run_command(msg, &parsed_command) < 0) {
    605     ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
    606                               "Failed to parse run command");
    607     return -1;
    608   }
    609 
    610   if (ipc_get_ipc_command(parsed_command.name, &ipc_command) < 0) {
    611     ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
    612                               "Command %s not found", parsed_command.name);
    613     ipc_free_parsed_command_members(&parsed_command);
    614     return -1;
    615   }
    616 
    617   int res = ipc_validate_run_command(&parsed_command, ipc_command);
    618   if (res < 0) {
    619     if (res == -1)
    620       ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
    621                                 "%u arguments provided, %u expected",
    622                                 parsed_command.argc, ipc_command.argc);
    623     else if (res == -2)
    624       ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND,
    625                                 "Type mismatch");
    626     ipc_free_parsed_command_members(&parsed_command);
    627     return -1;
    628   }
    629 
    630   if (parsed_command.argc == 1)
    631     ipc_command.func.single_param(parsed_command.args);
    632   else if (parsed_command.argc > 1)
    633     ipc_command.func.array_param(parsed_command.args, parsed_command.argc);
    634 
    635   DEBUG("Called function for command %s\n", parsed_command.name);
    636 
    637   ipc_free_parsed_command_members(&parsed_command);
    638 
    639   ipc_prepare_reply_success(ipc_client, IPC_TYPE_RUN_COMMAND);
    640   return 0;
    641 }
    642 
    643 /**
    644  * Called when an IPC_TYPE_GET_MONITORS message is received from a client. It
    645  * prepares a reply with the properties of all of the monitors in JSON.
    646  */
    647 static void
    648 ipc_get_monitors(IPCClient *c, Monitor *mons, Monitor *selmon)
    649 {
    650   yajl_gen gen;
    651   ipc_reply_init_message(&gen);
    652   dump_monitors(gen, mons, selmon);
    653 
    654   ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_MONITORS);
    655 }
    656 
    657 /**
    658  * Called when an IPC_TYPE_GET_TAGS message is received from a client. It
    659  * prepares a reply with info about all the tags in JSON.
    660  */
    661 static void
    662 ipc_get_tags(IPCClient *c, const int tags_len)
    663 {
    664   yajl_gen gen;
    665   ipc_reply_init_message(&gen);
    666 
    667   dump_tags(gen, tags_len);
    668 
    669   ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_TAGS);
    670 }
    671 
    672 /**
    673  * Called when an IPC_TYPE_GET_LAYOUTS message is received from a client. It
    674  * prepares a reply with a JSON array of available layouts
    675  */
    676 static void
    677 ipc_get_layouts(IPCClient *c, const Layout layouts[], const int layouts_len)
    678 {
    679   yajl_gen gen;
    680   ipc_reply_init_message(&gen);
    681 
    682   dump_layouts(gen, layouts, layouts_len);
    683 
    684   ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_LAYOUTS);
    685 }
    686 
    687 /**
    688  * Called when an IPC_TYPE_GET_DWM_CLIENT message is received from a client. It
    689  * prepares a JSON reply with the properties of the client with the specified
    690  * window XID.
    691  *
    692  * Returns 0 if the message was successfully parsed and if the client with the
    693  *   specified window XID was found
    694  * Returns -1 if the message could not be parsed
    695  */
    696 static int
    697 ipc_get_dwm_client(IPCClient *ipc_client, const char *msg, const Monitor *mons)
    698 {
    699   Window win;
    700 
    701   if (ipc_parse_get_dwm_client(msg, &win) < 0) return -1;
    702 
    703   // Find client with specified window XID
    704   for (const Monitor *m = mons; m; m = m->next)
    705     for (Client *c = m->clients; c; c = c->next)
    706       if (c->win == win) {
    707         yajl_gen gen;
    708         ipc_reply_init_message(&gen);
    709 
    710         dump_client(gen, c);
    711 
    712         ipc_reply_prepare_send_message(gen, ipc_client,
    713                                        IPC_TYPE_GET_DWM_CLIENT);
    714 
    715         return 0;
    716       }
    717 
    718   ipc_prepare_reply_failure(ipc_client, IPC_TYPE_GET_DWM_CLIENT,
    719                             "Client with window id %d not found", win);
    720   return -1;
    721 }
    722 
    723 /**
    724  * Called when an IPC_TYPE_SUBSCRIBE message is received from a client. It
    725  * subscribes/unsubscribes the client from the specified event and replies with
    726  * the result.
    727  *
    728  * Returns 0 if the message was successfully parsed.
    729  * Returns -1 if the message could not be parsed
    730  */
    731 static int
    732 ipc_subscribe(IPCClient *c, const char *msg)
    733 {
    734   IPCSubscriptionAction action = IPC_ACTION_SUBSCRIBE;
    735   IPCEvent event = 0;
    736 
    737   if (ipc_parse_subscribe(msg, &action, &event)) {
    738     ipc_prepare_reply_failure(c, IPC_TYPE_SUBSCRIBE, "Event does not exist");
    739     return -1;
    740   }
    741 
    742   if (action == IPC_ACTION_SUBSCRIBE) {
    743     DEBUG("Subscribing client on fd %d to %d\n", c->fd, event);
    744     c->subscriptions |= event;
    745   } else if (action == IPC_ACTION_UNSUBSCRIBE) {
    746     DEBUG("Unsubscribing client on fd %d to %d\n", c->fd, event);
    747     c->subscriptions ^= event;
    748   } else {
    749     ipc_prepare_reply_failure(c, IPC_TYPE_SUBSCRIBE,
    750                               "Invalid subscription action");
    751     return -1;
    752   }
    753 
    754   ipc_prepare_reply_success(c, IPC_TYPE_SUBSCRIBE);
    755   return 0;
    756 }
    757 
    758 int
    759 ipc_init(const char *socket_path, const int p_epoll_fd, IPCCommand commands[],
    760          const int commands_len)
    761 {
    762   // Initialize struct to 0
    763   memset(&sock_epoll_event, 0, sizeof(sock_epoll_event));
    764 
    765   int socket_fd = ipc_create_socket(socket_path);
    766   if (socket_fd < 0) return -1;
    767 
    768   ipc_commands = commands;
    769   ipc_commands_len = commands_len;
    770 
    771   epoll_fd = p_epoll_fd;
    772 
    773   // Wake up to incoming connection requests
    774   sock_epoll_event.data.fd = socket_fd;
    775   sock_epoll_event.events = EPOLLIN;
    776   if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &sock_epoll_event)) {
    777     fputs("Failed to add sock file descriptor to epoll", stderr);
    778     return -1;
    779   }
    780 
    781   return socket_fd;
    782 }
    783 
    784 void
    785 ipc_cleanup()
    786 {
    787   IPCClient *c = ipc_clients;
    788   // Free clients and their buffers
    789   while (c) {
    790     ipc_drop_client(c);
    791     c = ipc_clients;
    792   }
    793 
    794   // Stop waking up for socket events
    795   epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sock_fd, &sock_epoll_event);
    796 
    797   // Uninitialize all static variables
    798   epoll_fd = -1;
    799   sock_fd = -1;
    800   ipc_commands = NULL;
    801   ipc_commands_len = 0;
    802   memset(&sock_epoll_event, 0, sizeof(struct epoll_event));
    803   memset(&sockaddr, 0, sizeof(struct sockaddr_un));
    804 
    805   // Delete socket
    806   unlink(sockaddr.sun_path);
    807 
    808   shutdown(sock_fd, SHUT_RDWR);
    809   close(sock_fd);
    810 }
    811 
    812 int
    813 ipc_get_sock_fd()
    814 {
    815   return sock_fd;
    816 }
    817 
    818 IPCClient *
    819 ipc_get_client(int fd)
    820 {
    821   return ipc_list_get_client(ipc_clients, fd);
    822 }
    823 
    824 int
    825 ipc_is_client_registered(int fd)
    826 {
    827   return (ipc_get_client(fd) != NULL);
    828 }
    829 
    830 int
    831 ipc_accept_client()
    832 {
    833   int fd = -1;
    834 
    835   struct sockaddr_un client_addr;
    836   socklen_t len = 0;
    837 
    838   // For portability clear the addr structure, since some implementations
    839   // have nonstandard fields in the structure
    840   memset(&client_addr, 0, sizeof(struct sockaddr_un));
    841 
    842   fd = accept(sock_fd, (struct sockaddr *)&client_addr, &len);
    843   if (fd < 0 && errno != EINTR) {
    844     fputs("Failed to accept IPC connection from client", stderr);
    845     return -1;
    846   }
    847 
    848   if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
    849     shutdown(fd, SHUT_RDWR);
    850     close(fd);
    851     fputs("Failed to set flags on new client fd", stderr);
    852   }
    853 
    854   IPCClient *nc = ipc_client_new(fd);
    855   if (nc == NULL) return -1;
    856 
    857   // Wake up to messages from this client
    858   nc->event.data.fd = fd;
    859   nc->event.events = EPOLLIN | EPOLLHUP;
    860   epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &nc->event);
    861 
    862   ipc_list_add_client(&ipc_clients, nc);
    863 
    864   DEBUG("%s%d\n", "New client at fd: ", fd);
    865 
    866   return fd;
    867 }
    868 
    869 int
    870 ipc_drop_client(IPCClient *c)
    871 {
    872   int fd = c->fd;
    873   shutdown(fd, SHUT_RDWR);
    874   int res = close(fd);
    875 
    876   if (res == 0) {
    877     struct epoll_event ev;
    878 
    879     // Stop waking up to messages from this client
    880     epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
    881     ipc_list_remove_client(&ipc_clients, c);
    882 
    883     free(c->buffer);
    884     free(c);
    885 
    886     DEBUG("Successfully removed client on fd %d\n", fd);
    887   } else if (res < 0 && res != EINTR) {
    888     fprintf(stderr, "Failed to close fd %d\n", fd);
    889   }
    890 
    891   return res;
    892 }
    893 
    894 int
    895 ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size,
    896                 char **msg)
    897 {
    898   int fd = c->fd;
    899   int ret =
    900       ipc_recv_message(fd, (uint8_t *)msg_type, msg_size, (uint8_t **)msg);
    901 
    902   if (ret < 0) {
    903     // This will happen if these errors occur while reading header
    904     if (ret == -1 &&
    905         (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
    906       return -2;
    907 
    908     fprintf(stderr, "Error reading message: dropping client at fd %d\n", fd);
    909     ipc_drop_client(c);
    910 
    911     return -1;
    912   }
    913 
    914   // Make sure receive message is null terminated to avoid parsing issues
    915   if (*msg_size > 0) {
    916     size_t len = *msg_size;
    917     nullterminate(msg, &len);
    918     *msg_size = len;
    919   }
    920 
    921   DEBUG("[fd %d] ", fd);
    922   if (*msg_size > 0)
    923     DEBUG("Received message: '%.*s' ", *msg_size, *msg);
    924   else
    925     DEBUG("Received empty message ");
    926   DEBUG("Message type: %" PRIu8 " ", (uint8_t)*msg_type);
    927   DEBUG("Message size: %" PRIu32 "\n", *msg_size);
    928 
    929   return 0;
    930 }
    931 
    932 ssize_t
    933 ipc_write_client(IPCClient *c)
    934 {
    935   const ssize_t n = ipc_write_message(c->fd, c->buffer, c->buffer_size);
    936 
    937   if (n < 0) return n;
    938 
    939   // TODO: Deal with client timeouts
    940 
    941   if (n == c->buffer_size) {
    942     c->buffer_size = 0;
    943     free(c->buffer);
    944     // No dangling pointers!
    945     c->buffer = NULL;
    946     // Stop waking up when client is ready to receive messages
    947     if (c->event.events & EPOLLOUT) {
    948       c->event.events -= EPOLLOUT;
    949       epoll_ctl(epoll_fd, EPOLL_CTL_MOD, c->fd, &c->event);
    950     }
    951     return n;
    952   }
    953 
    954   // Shift unwritten buffer to beginning of buffer and reallocate
    955   c->buffer_size -= n;
    956   memmove(c->buffer, c->buffer + n, c->buffer_size);
    957   c->buffer = (char *)realloc(c->buffer, c->buffer_size);
    958 
    959   return n;
    960 }
    961 
    962 void
    963 ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type,
    964                          const uint32_t msg_size, const char *msg)
    965 {
    966   dwm_ipc_header_t header = {
    967       .magic = IPC_MAGIC_ARR, .type = msg_type, .size = msg_size};
    968 
    969   uint32_t header_size = sizeof(dwm_ipc_header_t);
    970   uint32_t packet_size = header_size + msg_size;
    971 
    972   if (c->buffer == NULL)
    973     c->buffer = (char *)malloc(c->buffer_size + packet_size);
    974   else
    975     c->buffer = (char *)realloc(c->buffer, c->buffer_size + packet_size);
    976 
    977   // Copy header to end of client buffer
    978   memcpy(c->buffer + c->buffer_size, &header, header_size);
    979   c->buffer_size += header_size;
    980 
    981   // Copy message to end of client buffer
    982   memcpy(c->buffer + c->buffer_size, msg, msg_size);
    983   c->buffer_size += msg_size;
    984 
    985   // Wake up when client is ready to receive messages
    986   c->event.events |= EPOLLOUT;
    987   epoll_ctl(epoll_fd, EPOLL_CTL_MOD, c->fd, &c->event);
    988 }
    989 
    990 void
    991 ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type,
    992                           const char *format, ...)
    993 {
    994   yajl_gen gen;
    995   va_list args;
    996 
    997   // Get output size
    998   va_start(args, format);
    999   size_t len = vsnprintf(NULL, 0, format, args);
   1000   va_end(args);
   1001   char *buffer = (char *)malloc((len + 1) * sizeof(char));
   1002 
   1003   ipc_reply_init_message(&gen);
   1004 
   1005   va_start(args, format);
   1006   vsnprintf(buffer, len + 1, format, args);
   1007   va_end(args);
   1008   dump_error_message(gen, buffer);
   1009 
   1010   ipc_reply_prepare_send_message(gen, c, msg_type);
   1011   fprintf(stderr, "[fd %d] Error: %s\n", c->fd, buffer);
   1012 
   1013   free(buffer);
   1014 }
   1015 
   1016 void
   1017 ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type)
   1018 {
   1019   const char *success_msg = "{\"result\":\"success\"}";
   1020   const size_t msg_len = strlen(success_msg) + 1;  // +1 for null char
   1021 
   1022   ipc_prepare_send_message(c, msg_type, msg_len, success_msg);
   1023 }
   1024 
   1025 void
   1026 ipc_tag_change_event(int mon_num, TagState old_state, TagState new_state)
   1027 {
   1028   yajl_gen gen;
   1029   ipc_event_init_message(&gen);
   1030   dump_tag_event(gen, mon_num, old_state, new_state);
   1031   ipc_event_prepare_send_message(gen, IPC_EVENT_TAG_CHANGE);
   1032 }
   1033 
   1034 void
   1035 ipc_client_focus_change_event(int mon_num, Client *old_client,
   1036                               Client *new_client)
   1037 {
   1038   yajl_gen gen;
   1039   ipc_event_init_message(&gen);
   1040   dump_client_focus_change_event(gen, old_client, new_client, mon_num);
   1041   ipc_event_prepare_send_message(gen, IPC_EVENT_CLIENT_FOCUS_CHANGE);
   1042 }
   1043 
   1044 void
   1045 ipc_layout_change_event(const int mon_num, const char *old_symbol,
   1046                         const Layout *old_layout, const char *new_symbol,
   1047                         const Layout *new_layout)
   1048 {
   1049   yajl_gen gen;
   1050   ipc_event_init_message(&gen);
   1051   dump_layout_change_event(gen, mon_num, old_symbol, old_layout, new_symbol,
   1052                            new_layout);
   1053   ipc_event_prepare_send_message(gen, IPC_EVENT_LAYOUT_CHANGE);
   1054 }
   1055 
   1056 void
   1057 ipc_monitor_focus_change_event(const int last_mon_num, const int new_mon_num)
   1058 {
   1059   yajl_gen gen;
   1060   ipc_event_init_message(&gen);
   1061   dump_monitor_focus_change_event(gen, last_mon_num, new_mon_num);
   1062   ipc_event_prepare_send_message(gen, IPC_EVENT_MONITOR_FOCUS_CHANGE);
   1063 }
   1064 
   1065 void
   1066 ipc_focused_title_change_event(const int mon_num, const Window client_id,
   1067                                const char *old_name, const char *new_name)
   1068 {
   1069   yajl_gen gen;
   1070   ipc_event_init_message(&gen);
   1071   dump_focused_title_change_event(gen, mon_num, client_id, old_name, new_name);
   1072   ipc_event_prepare_send_message(gen, IPC_EVENT_FOCUSED_TITLE_CHANGE);
   1073 }
   1074 
   1075 void
   1076 ipc_focused_state_change_event(const int mon_num, const Window client_id,
   1077                                const ClientState *old_state,
   1078                                const ClientState *new_state)
   1079 {
   1080   yajl_gen gen;
   1081   ipc_event_init_message(&gen);
   1082   dump_focused_state_change_event(gen, mon_num, client_id, old_state,
   1083                                   new_state);
   1084   ipc_event_prepare_send_message(gen, IPC_EVENT_FOCUSED_STATE_CHANGE);
   1085 }
   1086 
   1087 void
   1088 ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon)
   1089 {
   1090   for (Monitor *m = mons; m; m = m->next) {
   1091     unsigned int urg = 0, occ = 0, tagset = 0;
   1092 
   1093     for (Client *c = m->clients; c; c = c->next) {
   1094       occ |= c->tags;
   1095 
   1096       if (c->isurgent) urg |= c->tags;
   1097     }
   1098     tagset = m->tagset[m->seltags];
   1099 
   1100     TagState new_state = {.selected = tagset, .occupied = occ, .urgent = urg};
   1101 
   1102     if (memcmp(&m->tagstate, &new_state, sizeof(TagState)) != 0) {
   1103       ipc_tag_change_event(m->num, m->tagstate, new_state);
   1104       m->tagstate = new_state;
   1105     }
   1106 
   1107     if (m->lastsel != m->sel) {
   1108       ipc_client_focus_change_event(m->num, m->lastsel, m->sel);
   1109       m->lastsel = m->sel;
   1110     }
   1111 
   1112     if (strcmp(m->ltsymbol, m->lastltsymbol) != 0 ||
   1113         m->lastlt != m->lt[m->sellt]) {
   1114       ipc_layout_change_event(m->num, m->lastltsymbol, m->lastlt, m->ltsymbol,
   1115                               m->lt[m->sellt]);
   1116       strcpy(m->lastltsymbol, m->ltsymbol);
   1117       m->lastlt = m->lt[m->sellt];
   1118     }
   1119 
   1120     if (*lastselmon != selmon) {
   1121       if (*lastselmon != NULL)
   1122         ipc_monitor_focus_change_event((*lastselmon)->num, selmon->num);
   1123       *lastselmon = selmon;
   1124     }
   1125 
   1126     Client *sel = m->sel;
   1127     if (!sel) continue;
   1128     ClientState *o = &m->sel->prevstate;
   1129     ClientState n = {.oldstate = sel->oldstate,
   1130                      .isfixed = sel->isfixed,
   1131                      .isfloating = sel->isfloating,
   1132                      .isfullscreen = sel->isfullscreen,
   1133                      .isurgent = sel->isurgent,
   1134                      .neverfocus = sel->neverfocus};
   1135     if (memcmp(o, &n, sizeof(ClientState)) != 0) {
   1136       ipc_focused_state_change_event(m->num, m->sel->win, o, &n);
   1137       *o = n;
   1138     }
   1139   }
   1140 }
   1141 
   1142 int
   1143 ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons,
   1144                               Monitor **lastselmon, Monitor *selmon, const int tags_len,
   1145                               const Layout *layouts, const int layouts_len)
   1146 {
   1147   int fd = ev->data.fd;
   1148   IPCClient *c = ipc_get_client(fd);
   1149 
   1150   if (ev->events & EPOLLHUP) {
   1151     DEBUG("EPOLLHUP received from client at fd %d\n", fd);
   1152     ipc_drop_client(c);
   1153   } else if (ev->events & EPOLLOUT) {
   1154     DEBUG("Sending message to client at fd %d...\n", fd);
   1155     if (c->buffer_size) ipc_write_client(c);
   1156   } else if (ev->events & EPOLLIN) {
   1157     IPCMessageType msg_type = 0;
   1158     uint32_t msg_size = 0;
   1159     char *msg = NULL;
   1160 
   1161     DEBUG("Received message from fd %d\n", fd);
   1162     if (ipc_read_client(c, &msg_type, &msg_size, &msg) < 0) return -1;
   1163 
   1164     if (msg_type == IPC_TYPE_GET_MONITORS)
   1165       ipc_get_monitors(c, mons, selmon);
   1166     else if (msg_type == IPC_TYPE_GET_TAGS)
   1167       ipc_get_tags(c, tags_len);
   1168     else if (msg_type == IPC_TYPE_GET_LAYOUTS)
   1169       ipc_get_layouts(c, layouts, layouts_len);
   1170     else if (msg_type == IPC_TYPE_RUN_COMMAND) {
   1171       if (ipc_run_command(c, msg) < 0) return -1;
   1172       ipc_send_events(mons, lastselmon, selmon);
   1173     } else if (msg_type == IPC_TYPE_GET_DWM_CLIENT) {
   1174       if (ipc_get_dwm_client(c, msg, mons) < 0) return -1;
   1175     } else if (msg_type == IPC_TYPE_SUBSCRIBE) {
   1176       if (ipc_subscribe(c, msg) < 0) return -1;
   1177     } else {
   1178       fprintf(stderr, "Invalid message type received from fd %d", fd);
   1179       ipc_prepare_reply_failure(c, msg_type, "Invalid message type: %d",
   1180                                 msg_type);
   1181     }
   1182     free(msg);
   1183   } else {
   1184     fprintf(stderr, "Epoll event returned %d from fd %d\n", ev->events, fd);
   1185     return -1;
   1186   }
   1187 
   1188   return 0;
   1189 }
   1190 
   1191 int
   1192 ipc_handle_socket_epoll_event(struct epoll_event *ev)
   1193 {
   1194   if (!(ev->events & EPOLLIN)) return -1;
   1195 
   1196   // EPOLLIN means incoming client connection request
   1197   fputs("Received EPOLLIN event on socket\n", stderr);
   1198   int new_fd = ipc_accept_client();
   1199 
   1200   return new_fd;
   1201 }
   1202