]> git.sur5r.net Git - i3/i3/blob - src/ipc.c
Merge branch 'fix-coords'
[i3/i3] / src / ipc.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
8  *
9  */
10 #include "all.h"
11
12 #include <sys/socket.h>
13 #include <sys/un.h>
14 #include <fcntl.h>
15 #include <libgen.h>
16 #include <ev.h>
17 #include <yajl/yajl_gen.h>
18 #include <yajl/yajl_parse.h>
19 #include <yajl/yajl_version.h>
20
21 char *current_socketpath = NULL;
22
23 /* Shorter names for all those yajl_gen_* functions */
24 #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__)
25 #define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str))
26
27 TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients);
28
29 /*
30  * Puts the given socket file descriptor into non-blocking mode or dies if
31  * setting O_NONBLOCK failed. Non-blocking sockets are a good idea for our
32  * IPC model because we should by no means block the window manager.
33  *
34  */
35 static void set_nonblock(int sockfd) {
36     int flags = fcntl(sockfd, F_GETFL, 0);
37     flags |= O_NONBLOCK;
38     if (fcntl(sockfd, F_SETFL, flags) < 0)
39         err(-1, "Could not set O_NONBLOCK");
40 }
41
42 /*
43  * Emulates mkdir -p (creates any missing folders)
44  *
45  */
46 static bool mkdirp(const char *path) {
47     if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
48         return true;
49     if (errno != ENOENT) {
50         ELOG("mkdir(%s) failed: %s\n", path, strerror(errno));
51         return false;
52     }
53     char *copy = strdup(path);
54     /* strip trailing slashes, if any */
55     while (copy[strlen(copy)-1] == '/')
56         copy[strlen(copy)-1] = '\0';
57
58     char *sep = strrchr(copy, '/');
59     if (sep == NULL) {
60         FREE(copy);
61         return false;
62     }
63     *sep = '\0';
64     bool result = false;
65     if (mkdirp(copy))
66         result = mkdirp(path);
67     free(copy);
68
69     return result;
70 }
71
72 /*
73  * Sends the specified event to all IPC clients which are currently connected
74  * and subscribed to this kind of event.
75  *
76  */
77 void ipc_send_event(const char *event, uint32_t message_type, const char *payload) {
78     ipc_client *current;
79     TAILQ_FOREACH(current, &all_clients, clients) {
80         /* see if this client is interested in this event */
81         bool interested = false;
82         for (int i = 0; i < current->num_events; i++) {
83             if (strcasecmp(current->events[i], event) != 0)
84                 continue;
85             interested = true;
86             break;
87         }
88         if (!interested)
89             continue;
90
91         ipc_send_message(current->fd, strlen(payload), message_type, (const uint8_t*)payload);
92     }
93 }
94
95 /*
96  * Calls shutdown() on each socket and closes it. This function to be called
97  * when exiting or restarting only!
98  *
99  */
100 void ipc_shutdown(void) {
101     ipc_client *current;
102     while (!TAILQ_EMPTY(&all_clients)) {
103         current = TAILQ_FIRST(&all_clients);
104         shutdown(current->fd, SHUT_RDWR);
105         close(current->fd);
106         TAILQ_REMOVE(&all_clients, current, clients);
107         free(current);
108     }
109 }
110
111 /*
112  * Executes the command and returns whether it could be successfully parsed
113  * or not (at the moment, always returns true).
114  *
115  */
116 IPC_HANDLER(command) {
117     /* To get a properly terminated buffer, we copy
118      * message_size bytes out of the buffer */
119     char *command = scalloc(message_size + 1);
120     strncpy(command, (const char*)message, message_size);
121     LOG("IPC: received: *%s*\n", command);
122     struct CommandResult *command_output = parse_command((const char*)command);
123     free(command);
124
125     if (command_output->needs_tree_render)
126         tree_render();
127
128     const unsigned char *reply;
129 #if YAJL_MAJOR >= 2
130     size_t length;
131 #else
132     unsigned int length;
133 #endif
134     yajl_gen_get_buf(command_output->json_gen, &reply, &length);
135
136     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_COMMAND,
137                      (const uint8_t*)reply);
138
139     yajl_gen_free(command_output->json_gen);
140 }
141
142 static void dump_rect(yajl_gen gen, const char *name, Rect r) {
143     ystr(name);
144     y(map_open);
145     ystr("x");
146     y(integer, r.x);
147     ystr("y");
148     y(integer, r.y);
149     ystr("width");
150     y(integer, r.width);
151     ystr("height");
152     y(integer, r.height);
153     y(map_close);
154 }
155
156 void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
157     y(map_open);
158     ystr("id");
159     y(integer, (long int)con);
160
161     ystr("type");
162     y(integer, con->type);
163
164     ystr("orientation");
165     switch (con->orientation) {
166         case NO_ORIENTATION:
167             ystr("none");
168             break;
169         case HORIZ:
170             ystr("horizontal");
171             break;
172         case VERT:
173             ystr("vertical");
174             break;
175     }
176
177     ystr("scratchpad_state");
178     switch (con->scratchpad_state) {
179         case SCRATCHPAD_NONE:
180             ystr("none");
181             break;
182         case SCRATCHPAD_FRESH:
183             ystr("fresh");
184             break;
185         case SCRATCHPAD_CHANGED:
186             ystr("changed");
187             break;
188     }
189
190     ystr("percent");
191     if (con->percent == 0.0)
192         y(null);
193     else y(double, con->percent);
194
195     ystr("urgent");
196     y(bool, con->urgent);
197
198     if (con->mark != NULL) {
199         ystr("mark");
200         ystr(con->mark);
201     }
202
203     ystr("focused");
204     y(bool, (con == focused));
205
206     ystr("layout");
207     switch (con->layout) {
208         case L_DEFAULT:
209             ystr("default");
210             break;
211         case L_STACKED:
212             ystr("stacked");
213             break;
214         case L_TABBED:
215             ystr("tabbed");
216             break;
217         case L_DOCKAREA:
218             ystr("dockarea");
219             break;
220         case L_OUTPUT:
221             ystr("output");
222             break;
223     }
224
225     ystr("border");
226     switch (con->border_style) {
227         case BS_NORMAL:
228             ystr("normal");
229             break;
230         case BS_NONE:
231             ystr("none");
232             break;
233         case BS_1PIXEL:
234             ystr("1pixel");
235             break;
236     }
237
238     dump_rect(gen, "rect", con->rect);
239     dump_rect(gen, "window_rect", con->window_rect);
240     dump_rect(gen, "geometry", con->geometry);
241
242     ystr("name");
243     if (con->window && con->window->name_json)
244         ystr(con->window->name_json);
245     else
246         ystr(con->name);
247
248     if (con->type == CT_WORKSPACE) {
249         ystr("num");
250         y(integer, con->num);
251     }
252
253     ystr("window");
254     if (con->window)
255         y(integer, con->window->id);
256     else y(null);
257
258     ystr("nodes");
259     y(array_open);
260     Con *node;
261     if (con->type != CT_DOCKAREA || !inplace_restart) {
262         TAILQ_FOREACH(node, &(con->nodes_head), nodes) {
263             dump_node(gen, node, inplace_restart);
264         }
265     }
266     y(array_close);
267
268     ystr("floating_nodes");
269     y(array_open);
270     TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
271         dump_node(gen, node, inplace_restart);
272     }
273     y(array_close);
274
275     ystr("focus");
276     y(array_open);
277     TAILQ_FOREACH(node, &(con->focus_head), focused) {
278         y(integer, (long int)node);
279     }
280     y(array_close);
281
282     ystr("fullscreen_mode");
283     y(integer, con->fullscreen_mode);
284
285     ystr("floating");
286     switch (con->floating) {
287         case FLOATING_AUTO_OFF:
288             ystr("auto_off");
289             break;
290         case FLOATING_AUTO_ON:
291             ystr("auto_on");
292             break;
293         case FLOATING_USER_OFF:
294             ystr("user_off");
295             break;
296         case FLOATING_USER_ON:
297             ystr("user_on");
298             break;
299     }
300
301     ystr("swallows");
302     y(array_open);
303     Match *match;
304     TAILQ_FOREACH(match, &(con->swallow_head), matches) {
305         if (match->dock != -1) {
306             y(map_open);
307             ystr("dock");
308             y(integer, match->dock);
309             ystr("insert_where");
310             y(integer, match->insert_where);
311             y(map_close);
312         }
313
314         /* TODO: the other swallow keys */
315     }
316
317     if (inplace_restart) {
318         if (con->window != NULL) {
319             y(map_open);
320             ystr("id");
321             y(integer, con->window->id);
322             ystr("restart_mode");
323             y(bool, true);
324             y(map_close);
325         }
326     }
327     y(array_close);
328
329     y(map_close);
330 }
331
332 IPC_HANDLER(tree) {
333     setlocale(LC_NUMERIC, "C");
334 #if YAJL_MAJOR >= 2
335     yajl_gen gen = yajl_gen_alloc(NULL);
336 #else
337     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
338 #endif
339     dump_node(gen, croot, false);
340     setlocale(LC_NUMERIC, "");
341
342     const unsigned char *payload;
343 #if YAJL_MAJOR >= 2
344     size_t length;
345 #else
346     unsigned int length;
347 #endif
348     y(get_buf, &payload, &length);
349
350     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_TREE, payload);
351     y(free);
352 }
353
354
355 /*
356  * Formats the reply message for a GET_WORKSPACES request and sends it to the
357  * client
358  *
359  */
360 IPC_HANDLER(get_workspaces) {
361 #if YAJL_MAJOR >= 2
362     yajl_gen gen = yajl_gen_alloc(NULL);
363 #else
364     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
365 #endif
366     y(array_open);
367
368     Con *focused_ws = con_get_workspace(focused);
369
370     Con *output;
371     TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
372         if (output->name[0] == '_' && output->name[1] == '_')
373             continue;
374         Con *ws;
375         TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
376             assert(ws->type == CT_WORKSPACE);
377             y(map_open);
378
379             ystr("num");
380             if (ws->num == -1)
381                 y(null);
382             else y(integer, ws->num);
383
384             ystr("name");
385             ystr(ws->name);
386
387             ystr("visible");
388             y(bool, workspace_is_visible(ws));
389
390             ystr("focused");
391             y(bool, ws == focused_ws);
392
393             ystr("rect");
394             y(map_open);
395             ystr("x");
396             y(integer, ws->rect.x);
397             ystr("y");
398             y(integer, ws->rect.y);
399             ystr("width");
400             y(integer, ws->rect.width);
401             ystr("height");
402             y(integer, ws->rect.height);
403             y(map_close);
404
405             ystr("output");
406             ystr(output->name);
407
408             ystr("urgent");
409             y(bool, ws->urgent);
410
411             y(map_close);
412         }
413     }
414
415     y(array_close);
416
417     const unsigned char *payload;
418 #if YAJL_MAJOR >= 2
419     size_t length;
420 #else
421     unsigned int length;
422 #endif
423     y(get_buf, &payload, &length);
424
425     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload);
426     y(free);
427 }
428
429 /*
430  * Formats the reply message for a GET_OUTPUTS request and sends it to the
431  * client
432  *
433  */
434 IPC_HANDLER(get_outputs) {
435 #if YAJL_MAJOR >= 2
436     yajl_gen gen = yajl_gen_alloc(NULL);
437 #else
438     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
439 #endif
440     y(array_open);
441
442     Output *output;
443     TAILQ_FOREACH(output, &outputs, outputs) {
444         y(map_open);
445
446         ystr("name");
447         ystr(output->name);
448
449         ystr("active");
450         y(bool, output->active);
451
452         ystr("primary");
453         y(bool, output->primary);
454
455         ystr("rect");
456         y(map_open);
457         ystr("x");
458         y(integer, output->rect.x);
459         ystr("y");
460         y(integer, output->rect.y);
461         ystr("width");
462         y(integer, output->rect.width);
463         ystr("height");
464         y(integer, output->rect.height);
465         y(map_close);
466
467         ystr("current_workspace");
468         Con *ws = NULL;
469         if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT)))
470             ystr(ws->name);
471         else y(null);
472
473         y(map_close);
474     }
475
476     y(array_close);
477
478     const unsigned char *payload;
479 #if YAJL_MAJOR >= 2
480     size_t length;
481 #else
482     unsigned int length;
483 #endif
484     y(get_buf, &payload, &length);
485
486     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload);
487     y(free);
488 }
489
490 /*
491  * Formats the reply message for a GET_MARKS request and sends it to the
492  * client
493  *
494  */
495 IPC_HANDLER(get_marks) {
496 #if YAJL_MAJOR >= 2
497     yajl_gen gen = yajl_gen_alloc(NULL);
498 #else
499     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
500 #endif
501     y(array_open);
502
503     Con *con;
504     TAILQ_FOREACH(con, &all_cons, all_cons)
505         if (con->mark != NULL)
506             ystr(con->mark);
507
508     y(array_close);
509
510     const unsigned char *payload;
511 #if YAJL_MAJOR >= 2
512     size_t length;
513 #else
514     unsigned int length;
515 #endif
516     y(get_buf, &payload, &length);
517
518     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_MARKS, payload);
519     y(free);
520 }
521
522 /*
523  * Formats the reply message for a GET_BAR_CONFIG request and sends it to the
524  * client.
525  *
526  */
527 IPC_HANDLER(get_bar_config) {
528 #if YAJL_MAJOR >= 2
529     yajl_gen gen = yajl_gen_alloc(NULL);
530 #else
531     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
532 #endif
533
534     /* If no ID was passed, we return a JSON array with all IDs */
535     if (message_size == 0) {
536         y(array_open);
537         Barconfig *current;
538         TAILQ_FOREACH(current, &barconfigs, configs) {
539             ystr(current->id);
540         }
541         y(array_close);
542
543         const unsigned char *payload;
544 #if YAJL_MAJOR >= 2
545         size_t length;
546 #else
547         unsigned int length;
548 #endif
549         y(get_buf, &payload, &length);
550
551         ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
552         y(free);
553         return;
554     }
555
556     /* To get a properly terminated buffer, we copy
557      * message_size bytes out of the buffer */
558     char *bar_id = scalloc(message_size + 1);
559     strncpy(bar_id, (const char*)message, message_size);
560     LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id);
561     Barconfig *current, *config = NULL;
562     TAILQ_FOREACH(current, &barconfigs, configs) {
563         if (strcmp(current->id, bar_id) != 0)
564             continue;
565
566         config = current;
567         break;
568     }
569
570     y(map_open);
571
572     if (!config) {
573         /* If we did not find a config for the given ID, the reply will contain
574          * a null 'id' field. */
575         ystr("id");
576         y(null);
577     } else {
578         ystr("id");
579         ystr(config->id);
580
581         if (config->num_outputs > 0) {
582             ystr("outputs");
583             y(array_open);
584             for (int c = 0; c < config->num_outputs; c++)
585                 ystr(config->outputs[c]);
586             y(array_close);
587         }
588
589 #define YSTR_IF_SET(name) \
590         do { \
591             if (config->name) { \
592                 ystr( # name); \
593                 ystr(config->name); \
594             } \
595         } while (0)
596
597         YSTR_IF_SET(tray_output);
598         YSTR_IF_SET(socket_path);
599
600         ystr("mode");
601         if (config->mode == M_HIDE)
602             ystr("hide");
603         else ystr("dock");
604
605         ystr("modifier");
606         switch (config->modifier) {
607             case M_CONTROL:
608                 ystr("ctrl");
609                 break;
610             case M_SHIFT:
611                 ystr("shift");
612                 break;
613             case M_MOD1:
614                 ystr("Mod1");
615                 break;
616             case M_MOD2:
617                 ystr("Mod2");
618                 break;
619             case M_MOD3:
620                 ystr("Mod3");
621                 break;
622             /*
623             case M_MOD4:
624                 ystr("Mod4");
625                 break;
626             */
627             case M_MOD5:
628                 ystr("Mod5");
629                 break;
630             default:
631                 ystr("Mod4");
632                 break;
633         }
634
635         ystr("position");
636         if (config->position == P_BOTTOM)
637             ystr("bottom");
638         else ystr("top");
639
640         YSTR_IF_SET(status_command);
641         YSTR_IF_SET(font);
642
643         ystr("workspace_buttons");
644         y(bool, !config->hide_workspace_buttons);
645
646         ystr("verbose");
647         y(bool, config->verbose);
648
649 #undef YSTR_IF_SET
650 #define YSTR_IF_SET(name) \
651         do { \
652             if (config->colors.name) { \
653                 ystr( # name); \
654                 ystr(config->colors.name); \
655             } \
656         } while (0)
657
658         ystr("colors");
659         y(map_open);
660         YSTR_IF_SET(background);
661         YSTR_IF_SET(statusline);
662         YSTR_IF_SET(focused_workspace_border);
663         YSTR_IF_SET(focused_workspace_bg);
664         YSTR_IF_SET(focused_workspace_text);
665         YSTR_IF_SET(active_workspace_border);
666         YSTR_IF_SET(active_workspace_bg);
667         YSTR_IF_SET(active_workspace_text);
668         YSTR_IF_SET(inactive_workspace_border);
669         YSTR_IF_SET(inactive_workspace_bg);
670         YSTR_IF_SET(inactive_workspace_text);
671         YSTR_IF_SET(urgent_workspace_border);
672         YSTR_IF_SET(urgent_workspace_bg);
673         YSTR_IF_SET(urgent_workspace_text);
674         y(map_close);
675
676 #undef YSTR_IF_SET
677     }
678
679     y(map_close);
680
681     const unsigned char *payload;
682 #if YAJL_MAJOR >= 2
683     size_t length;
684 #else
685     unsigned int length;
686 #endif
687     y(get_buf, &payload, &length);
688
689     ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
690     y(free);
691 }
692
693 /*
694  * Callback for the YAJL parser (will be called when a string is parsed).
695  *
696  */
697 #if YAJL_MAJOR < 2
698 static int add_subscription(void *extra, const unsigned char *s,
699                             unsigned int len) {
700 #else
701 static int add_subscription(void *extra, const unsigned char *s,
702                             size_t len) {
703 #endif
704     ipc_client *client = extra;
705
706     DLOG("should add subscription to extra %p, sub %.*s\n", client, len, s);
707     int event = client->num_events;
708
709     client->num_events++;
710     client->events = realloc(client->events, client->num_events * sizeof(char*));
711     /* We copy the string because it is not null-terminated and strndup()
712      * is missing on some BSD systems */
713     client->events[event] = scalloc(len+1);
714     memcpy(client->events[event], s, len);
715
716     DLOG("client is now subscribed to:\n");
717     for (int i = 0; i < client->num_events; i++)
718         DLOG("event %s\n", client->events[i]);
719     DLOG("(done)\n");
720
721     return 1;
722 }
723
724 /*
725  * Subscribes this connection to the event types which were given as a JSON
726  * serialized array in the payload field of the message.
727  *
728  */
729 IPC_HANDLER(subscribe) {
730     yajl_handle p;
731     yajl_callbacks callbacks;
732     yajl_status stat;
733     ipc_client *current, *client = NULL;
734
735     /* Search the ipc_client structure for this connection */
736     TAILQ_FOREACH(current, &all_clients, clients) {
737         if (current->fd != fd)
738             continue;
739
740         client = current;
741         break;
742     }
743
744     if (client == NULL) {
745         ELOG("Could not find ipc_client data structure for fd %d\n", fd);
746         return;
747     }
748
749     /* Setup the JSON parser */
750     memset(&callbacks, 0, sizeof(yajl_callbacks));
751     callbacks.yajl_string = add_subscription;
752
753 #if YAJL_MAJOR >= 2
754     p = yajl_alloc(&callbacks, NULL, (void*)client);
755 #else
756     p = yajl_alloc(&callbacks, NULL, NULL, (void*)client);
757 #endif
758     stat = yajl_parse(p, (const unsigned char*)message, message_size);
759     if (stat != yajl_status_ok) {
760         unsigned char *err;
761         err = yajl_get_error(p, true, (const unsigned char*)message,
762                              message_size);
763         ELOG("YAJL parse error: %s\n", err);
764         yajl_free_error(p, err);
765
766         const char *reply = "{\"success\":false}";
767         ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t*)reply);
768         yajl_free(p);
769         return;
770     }
771     yajl_free(p);
772     const char *reply = "{\"success\":true}";
773     ipc_send_message(fd, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t*)reply);
774 }
775
776 /* The index of each callback function corresponds to the numeric
777  * value of the message type (see include/i3/ipc.h) */
778 handler_t handlers[7] = {
779     handle_command,
780     handle_get_workspaces,
781     handle_subscribe,
782     handle_get_outputs,
783     handle_tree,
784     handle_get_marks,
785     handle_get_bar_config,
786 };
787
788 /*
789  * Handler for activity on a client connection, receives a message from a
790  * client.
791  *
792  * For now, the maximum message size is 2048. I’m not sure for what the
793  * IPC interface will be used in the future, thus I’m not implementing a
794  * mechanism for arbitrarily long messages, as it seems like overkill
795  * at the moment.
796  *
797  */
798 static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
799     char buf[2048];
800     int n = read(w->fd, buf, sizeof(buf));
801
802     /* On error or an empty message, we close the connection */
803     if (n <= 0) {
804 #if 0
805         /* FIXME: I get these when closing a client socket,
806          * therefore we just treat them as an error. Is this
807          * correct? */
808         if (errno == EAGAIN || errno == EWOULDBLOCK)
809                 return;
810 #endif
811
812         /* If not, there was some kind of error. We don’t bother
813          * and close the connection */
814         close(w->fd);
815
816         /* Delete the client from the list of clients */
817         ipc_client *current;
818         TAILQ_FOREACH(current, &all_clients, clients) {
819             if (current->fd != w->fd)
820                 continue;
821
822             for (int i = 0; i < current->num_events; i++)
823                 free(current->events[i]);
824             /* We can call TAILQ_REMOVE because we break out of the
825              * TAILQ_FOREACH afterwards */
826             TAILQ_REMOVE(&all_clients, current, clients);
827             free(current);
828             break;
829         }
830
831         ev_io_stop(EV_A_ w);
832         free(w);
833
834         DLOG("IPC: client disconnected\n");
835         return;
836     }
837
838     /* Terminate the message correctly */
839     buf[n] = '\0';
840
841     /* Check if the message starts with the i3 IPC magic code */
842     if (n < strlen(I3_IPC_MAGIC)) {
843         DLOG("IPC: message too short, ignoring\n");
844         return;
845     }
846
847     if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
848         DLOG("IPC: message does not start with the IPC magic\n");
849         return;
850     }
851
852     uint8_t *message = (uint8_t*)buf;
853     while (n > 0) {
854         DLOG("IPC: n = %d\n", n);
855         message += strlen(I3_IPC_MAGIC);
856         n -= strlen(I3_IPC_MAGIC);
857
858         /* The next 32 bit after the magic are the message size */
859         uint32_t message_size;
860         memcpy(&message_size, (uint32_t*)message, sizeof(uint32_t));
861         message += sizeof(uint32_t);
862         n -= sizeof(uint32_t);
863
864         if (message_size > n) {
865             DLOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n");
866             return;
867         }
868
869         /* The last 32 bits of the header are the message type */
870         uint32_t message_type;
871         memcpy(&message_type, (uint32_t*)message, sizeof(uint32_t));
872         message += sizeof(uint32_t);
873         n -= sizeof(uint32_t);
874
875         if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
876             DLOG("Unhandled message type: %d\n", message_type);
877         else {
878             handler_t h = handlers[message_type];
879             h(w->fd, message, n, message_size, message_type);
880         }
881         n -= message_size;
882         message += message_size;
883     }
884 }
885
886 /*
887  * Handler for activity on the listening socket, meaning that a new client
888  * has just connected and we should accept() him. Sets up the event handler
889  * for activity on the new connection and inserts the file descriptor into
890  * the list of clients.
891  *
892  */
893 void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
894     struct sockaddr_un peer;
895     socklen_t len = sizeof(struct sockaddr_un);
896     int client;
897     if ((client = accept(w->fd, (struct sockaddr*)&peer, &len)) < 0) {
898         if (errno == EINTR)
899             return;
900         else perror("accept()");
901         return;
902     }
903
904     /* Close this file descriptor on exec() */
905     (void)fcntl(client, F_SETFD, FD_CLOEXEC);
906
907     set_nonblock(client);
908
909     struct ev_io *package = scalloc(sizeof(struct ev_io));
910     ev_io_init(package, ipc_receive_message, client, EV_READ);
911     ev_io_start(EV_A_ package);
912
913     DLOG("IPC: new client connected on fd %d\n", w->fd);
914
915     ipc_client *new = scalloc(sizeof(ipc_client));
916     new->fd = client;
917
918     TAILQ_INSERT_TAIL(&all_clients, new, clients);
919 }
920
921 /*
922  * Creates the UNIX domain socket at the given path, sets it to non-blocking
923  * mode, bind()s and listen()s on it.
924  *
925  */
926 int ipc_create_socket(const char *filename) {
927     int sockfd;
928
929     FREE(current_socketpath);
930
931     char *resolved = resolve_tilde(filename);
932     DLOG("Creating IPC-socket at %s\n", resolved);
933     char *copy = sstrdup(resolved);
934     const char *dir = dirname(copy);
935     if (!path_exists(dir))
936         mkdirp(dir);
937     free(copy);
938
939     /* Unlink the unix domain socket before */
940     unlink(resolved);
941
942     if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
943         perror("socket()");
944         free(resolved);
945         return -1;
946     }
947
948     (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
949
950     struct sockaddr_un addr;
951     memset(&addr, 0, sizeof(struct sockaddr_un));
952     addr.sun_family = AF_LOCAL;
953     strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1);
954     if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) {
955         perror("bind()");
956         free(resolved);
957         return -1;
958     }
959
960     set_nonblock(sockfd);
961
962     if (listen(sockfd, 5) < 0) {
963         perror("listen()");
964         free(resolved);
965         return -1;
966     }
967
968     current_socketpath = resolved;
969     return sockfd;
970 }