]> git.sur5r.net Git - i3/i3/blob - src/ipc.c
Fix unaligned memory access on sparc (Thanks David Coppa)
[i3/i3] / src / ipc.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  *
6  * © 2009-2011 Michael Stapelberg and contributors
7  *
8  * See file LICENSE for license information.
9  *
10  * ipc.c: Everything about the UNIX domain sockets for IPC
11  *
12  */
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <fcntl.h>
16 #include <libgen.h>
17 #include <ev.h>
18 #include <yajl/yajl_gen.h>
19 #include <yajl/yajl_parse.h>
20 #include <yajl/yajl_version.h>
21
22 #include "all.h"
23
24 char *current_socketpath = NULL;
25
26 /* Shorter names for all those yajl_gen_* functions */
27 #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__)
28 #define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str))
29
30 TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients);
31
32 /*
33  * Puts the given socket file descriptor into non-blocking mode or dies if
34  * setting O_NONBLOCK failed. Non-blocking sockets are a good idea for our
35  * IPC model because we should by no means block the window manager.
36  *
37  */
38 static void set_nonblock(int sockfd) {
39     int flags = fcntl(sockfd, F_GETFL, 0);
40     flags |= O_NONBLOCK;
41     if (fcntl(sockfd, F_SETFL, flags) < 0)
42         err(-1, "Could not set O_NONBLOCK");
43 }
44
45 /*
46  * Emulates mkdir -p (creates any missing folders)
47  *
48  */
49 static bool mkdirp(const char *path) {
50     if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
51         return true;
52     if (errno != ENOENT) {
53         ELOG("mkdir(%s) failed: %s\n", path, strerror(errno));
54         return false;
55     }
56     char *copy = strdup(path);
57     /* strip trailing slashes, if any */
58     while (copy[strlen(copy)-1] == '/')
59         copy[strlen(copy)-1] = '\0';
60
61     char *sep = strrchr(copy, '/');
62     if (sep == NULL)
63         return false;
64     *sep = '\0';
65     bool result = false;
66     if (mkdirp(copy))
67         result = mkdirp(path);
68     free(copy);
69
70     return result;
71 }
72
73 static void ipc_send_message(int fd, const unsigned char *payload,
74                              int message_type, int message_size) {
75     int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) +
76                       sizeof(uint32_t) + message_size;
77     char msg[buffer_size];
78     char *walk = msg;
79
80     strcpy(walk, "i3-ipc");
81     walk += strlen("i3-ipc");
82     memcpy(walk, &message_size, sizeof(uint32_t));
83     walk += sizeof(uint32_t);
84     memcpy(walk, &message_type, sizeof(uint32_t));
85     walk += sizeof(uint32_t);
86     memcpy(walk, payload, message_size);
87
88     int sent_bytes = 0;
89     int bytes_to_go = buffer_size;
90     while (sent_bytes < bytes_to_go) {
91         int n = write(fd, msg + sent_bytes, bytes_to_go);
92         if (n == -1) {
93             DLOG("write() failed: %s\n", strerror(errno));
94             return;
95         }
96
97         sent_bytes += n;
98         bytes_to_go -= n;
99     }
100 }
101
102 /*
103  * Sends the specified event to all IPC clients which are currently connected
104  * and subscribed to this kind of event.
105  *
106  */
107 void ipc_send_event(const char *event, uint32_t message_type, const char *payload) {
108     ipc_client *current;
109     TAILQ_FOREACH(current, &all_clients, clients) {
110         /* see if this client is interested in this event */
111         bool interested = false;
112         for (int i = 0; i < current->num_events; i++) {
113             if (strcasecmp(current->events[i], event) != 0)
114                 continue;
115             interested = true;
116             break;
117         }
118         if (!interested)
119             continue;
120
121         ipc_send_message(current->fd, (const unsigned char*)payload,
122                          message_type, strlen(payload));
123     }
124 }
125
126 /*
127  * Calls shutdown() on each socket and closes it. This function to be called
128  * when exiting or restarting only!
129  *
130  */
131 void ipc_shutdown() {
132     ipc_client *current;
133     TAILQ_FOREACH(current, &all_clients, clients) {
134         shutdown(current->fd, SHUT_RDWR);
135         close(current->fd);
136     }
137 }
138
139 /*
140  * Executes the command and returns whether it could be successfully parsed
141  * or not (at the moment, always returns true).
142  *
143  */
144 IPC_HANDLER(command) {
145     /* To get a properly terminated buffer, we copy
146      * message_size bytes out of the buffer */
147     char *command = scalloc(message_size + 1);
148     strncpy(command, (const char*)message, message_size);
149     LOG("IPC: received: *%s*\n", command);
150     const char *reply = parse_cmd((const char*)command);
151     tree_render();
152     free(command);
153
154     /* If no reply was provided, we just use the default success message */
155     if (reply == NULL)
156         reply = "{\"success\":true}";
157     ipc_send_message(fd, (const unsigned char*)reply,
158                      I3_IPC_REPLY_TYPE_COMMAND, strlen(reply));
159 }
160
161 static void dump_rect(yajl_gen gen, const char *name, Rect r) {
162     ystr(name);
163     y(map_open);
164     ystr("x");
165     y(integer, r.x);
166     ystr("y");
167     y(integer, r.y);
168     ystr("width");
169     y(integer, r.width);
170     ystr("height");
171     y(integer, r.height);
172     y(map_close);
173 }
174
175 void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
176     y(map_open);
177     ystr("id");
178     y(integer, (long int)con);
179
180     ystr("type");
181     y(integer, con->type);
182
183     ystr("orientation");
184     switch (con->orientation) {
185         case NO_ORIENTATION:
186             ystr("none");
187             break;
188         case HORIZ:
189             ystr("horizontal");
190             break;
191         case VERT:
192             ystr("vertical");
193             break;
194     }
195
196     ystr("percent");
197     y(double, con->percent);
198
199     ystr("urgent");
200     y(integer, con->urgent);
201
202     ystr("focused");
203     y(integer, (con == focused));
204
205     ystr("layout");
206     y(integer, con->layout);
207
208     ystr("border");
209     y(integer, con->border_style);
210
211     dump_rect(gen, "rect", con->rect);
212     dump_rect(gen, "window_rect", con->window_rect);
213     dump_rect(gen, "geometry", con->geometry);
214
215     ystr("name");
216     ystr(con->name);
217
218     if (con->type == CT_WORKSPACE) {
219         ystr("num");
220         y(integer, con->num);
221     }
222
223     ystr("window");
224     if (con->window)
225         y(integer, con->window->id);
226     else y(null);
227
228     ystr("nodes");
229     y(array_open);
230     Con *node;
231     if (con->type != CT_DOCKAREA || !inplace_restart) {
232         TAILQ_FOREACH(node, &(con->nodes_head), nodes) {
233             dump_node(gen, node, inplace_restart);
234         }
235     }
236     y(array_close);
237
238     ystr("floating_nodes");
239     y(array_open);
240     TAILQ_FOREACH(node, &(con->floating_head), floating_windows) {
241         dump_node(gen, node, inplace_restart);
242     }
243     y(array_close);
244
245     ystr("focus");
246     y(array_open);
247     TAILQ_FOREACH(node, &(con->focus_head), nodes) {
248         y(integer, (long int)node);
249     }
250     y(array_close);
251
252     ystr("fullscreen_mode");
253     y(integer, con->fullscreen_mode);
254
255     ystr("swallows");
256     y(array_open);
257     Match *match;
258     TAILQ_FOREACH(match, &(con->swallow_head), matches) {
259         if (match->dock != -1) {
260             y(map_open);
261             ystr("dock");
262             y(integer, match->dock);
263             ystr("insert_where");
264             y(integer, match->insert_where);
265             y(map_close);
266         }
267
268         /* TODO: the other swallow keys */
269     }
270
271     if (inplace_restart) {
272         if (con->window != NULL) {
273             y(map_open);
274             ystr("id");
275             y(integer, con->window->id);
276             y(map_close);
277         }
278     }
279     y(array_close);
280
281     y(map_close);
282 }
283
284 IPC_HANDLER(tree) {
285     setlocale(LC_NUMERIC, "C");
286 #if YAJL_MAJOR >= 2
287     yajl_gen gen = yajl_gen_alloc(NULL);
288 #else
289     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
290 #endif
291     dump_node(gen, croot, false);
292     setlocale(LC_NUMERIC, "");
293
294     const unsigned char *payload;
295 #if YAJL_MAJOR >= 2
296     size_t length;
297 #else
298     unsigned int length;
299 #endif
300     y(get_buf, &payload, &length);
301
302     ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_TREE, length);
303     y(free);
304 }
305
306 /*
307  * Formats the reply message for a GET_WORKSPACES request and sends it to the
308  * client
309  *
310  */
311 IPC_HANDLER(get_workspaces) {
312 #if YAJL_MAJOR >= 2
313     yajl_gen gen = yajl_gen_alloc(NULL);
314 #else
315     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
316 #endif
317     y(array_open);
318
319     Con *focused_ws = con_get_workspace(focused);
320
321     Con *output;
322     TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
323         Con *ws;
324         TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
325             assert(ws->type == CT_WORKSPACE);
326             y(map_open);
327
328             ystr("num");
329             if (ws->num == -1)
330                 y(null);
331             else y(integer, ws->num);
332
333             ystr("name");
334             ystr(ws->name);
335
336             ystr("visible");
337             y(bool, workspace_is_visible(ws));
338
339             ystr("focused");
340             y(bool, ws == focused_ws);
341
342             ystr("rect");
343             y(map_open);
344             ystr("x");
345             y(integer, ws->rect.x);
346             ystr("y");
347             y(integer, ws->rect.y);
348             ystr("width");
349             y(integer, ws->rect.width);
350             ystr("height");
351             y(integer, ws->rect.height);
352             y(map_close);
353
354             ystr("output");
355             ystr(output->name);
356
357             ystr("urgent");
358             y(bool, ws->urgent);
359
360             y(map_close);
361         }
362     }
363
364     y(array_close);
365
366     const unsigned char *payload;
367 #if YAJL_MAJOR >= 2
368     size_t length;
369 #else
370     unsigned int length;
371 #endif
372     y(get_buf, &payload, &length);
373
374     ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_WORKSPACES, length);
375     y(free);
376 }
377
378 /*
379  * Formats the reply message for a GET_OUTPUTS request and sends it to the
380  * client
381  *
382  */
383 IPC_HANDLER(get_outputs) {
384 #if YAJL_MAJOR >= 2
385     yajl_gen gen = yajl_gen_alloc(NULL);
386 #else
387     yajl_gen gen = yajl_gen_alloc(NULL, NULL);
388 #endif
389     y(array_open);
390
391     Output *output;
392     TAILQ_FOREACH(output, &outputs, outputs) {
393         y(map_open);
394
395         ystr("name");
396         ystr(output->name);
397
398         ystr("active");
399         y(bool, output->active);
400
401         ystr("rect");
402         y(map_open);
403         ystr("x");
404         y(integer, output->rect.x);
405         ystr("y");
406         y(integer, output->rect.y);
407         ystr("width");
408         y(integer, output->rect.width);
409         ystr("height");
410         y(integer, output->rect.height);
411         y(map_close);
412
413         ystr("current_workspace");
414         Con *ws = NULL;
415         if (output->con && (ws = con_get_fullscreen_con(output->con)))
416             ystr(ws->name);
417         else y(null);
418
419         y(map_close);
420     }
421
422     y(array_close);
423
424     const unsigned char *payload;
425 #if YAJL_MAJOR >= 2
426     size_t length;
427 #else
428     unsigned int length;
429 #endif
430     y(get_buf, &payload, &length);
431
432     ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_OUTPUTS, length);
433     y(free);
434 }
435
436 /*
437  * Callback for the YAJL parser (will be called when a string is parsed).
438  *
439  */
440 #if YAJL_MAJOR < 2
441 static int add_subscription(void *extra, const unsigned char *s,
442                             unsigned int len) {
443 #else
444 static int add_subscription(void *extra, const unsigned char *s,
445                             size_t len) {
446 #endif
447     ipc_client *client = extra;
448
449     DLOG("should add subscription to extra %p, sub %.*s\n", client, len, s);
450     int event = client->num_events;
451
452     client->num_events++;
453     client->events = realloc(client->events, client->num_events * sizeof(char*));
454     /* We copy the string because it is not null-terminated and strndup()
455      * is missing on some BSD systems */
456     client->events[event] = scalloc(len+1);
457     memcpy(client->events[event], s, len);
458
459     DLOG("client is now subscribed to:\n");
460     for (int i = 0; i < client->num_events; i++)
461         DLOG("event %s\n", client->events[i]);
462     DLOG("(done)\n");
463
464     return 1;
465 }
466
467 /*
468  * Subscribes this connection to the event types which were given as a JSON
469  * serialized array in the payload field of the message.
470  *
471  */
472 IPC_HANDLER(subscribe) {
473     yajl_handle p;
474     yajl_callbacks callbacks;
475     yajl_status stat;
476     ipc_client *current, *client = NULL;
477
478     /* Search the ipc_client structure for this connection */
479     TAILQ_FOREACH(current, &all_clients, clients) {
480         if (current->fd != fd)
481             continue;
482
483         client = current;
484         break;
485     }
486
487     if (client == NULL) {
488         ELOG("Could not find ipc_client data structure for fd %d\n", fd);
489         return;
490     }
491
492     /* Setup the JSON parser */
493     memset(&callbacks, 0, sizeof(yajl_callbacks));
494     callbacks.yajl_string = add_subscription;
495
496 #if YAJL_MAJOR >= 2
497     p = yajl_alloc(&callbacks, NULL, (void*)client);
498 #else
499     p = yajl_alloc(&callbacks, NULL, NULL, (void*)client);
500 #endif
501     stat = yajl_parse(p, (const unsigned char*)message, message_size);
502     if (stat != yajl_status_ok) {
503         unsigned char *err;
504         err = yajl_get_error(p, true, (const unsigned char*)message,
505                              message_size);
506         ELOG("YAJL parse error: %s\n", err);
507         yajl_free_error(p, err);
508
509         const char *reply = "{\"success\":false}";
510         ipc_send_message(fd, (const unsigned char*)reply,
511                          I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply));
512         yajl_free(p);
513         return;
514     }
515     yajl_free(p);
516     const char *reply = "{\"success\":true}";
517     ipc_send_message(fd, (const unsigned char*)reply,
518                      I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply));
519 }
520
521 /* The index of each callback function corresponds to the numeric
522  * value of the message type (see include/i3/ipc.h) */
523 handler_t handlers[5] = {
524     handle_command,
525     handle_get_workspaces,
526     handle_subscribe,
527     handle_get_outputs,
528     handle_tree
529 };
530
531 /*
532  * Handler for activity on a client connection, receives a message from a
533  * client.
534  *
535  * For now, the maximum message size is 2048. I’m not sure for what the
536  * IPC interface will be used in the future, thus I’m not implementing a
537  * mechanism for arbitrarily long messages, as it seems like overkill
538  * at the moment.
539  *
540  */
541 static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
542     char buf[2048];
543     int n = read(w->fd, buf, sizeof(buf));
544
545     /* On error or an empty message, we close the connection */
546     if (n <= 0) {
547 #if 0
548         /* FIXME: I get these when closing a client socket,
549          * therefore we just treat them as an error. Is this
550          * correct? */
551         if (errno == EAGAIN || errno == EWOULDBLOCK)
552                 return;
553 #endif
554
555         /* If not, there was some kind of error. We don’t bother
556          * and close the connection */
557         close(w->fd);
558
559         /* Delete the client from the list of clients */
560         ipc_client *current;
561         TAILQ_FOREACH(current, &all_clients, clients) {
562             if (current->fd != w->fd)
563                 continue;
564
565             for (int i = 0; i < current->num_events; i++)
566                 free(current->events[i]);
567             /* We can call TAILQ_REMOVE because we break out of the
568              * TAILQ_FOREACH afterwards */
569             TAILQ_REMOVE(&all_clients, current, clients);
570             break;
571         }
572
573         ev_io_stop(EV_A_ w);
574
575         DLOG("IPC: client disconnected\n");
576         return;
577     }
578
579     /* Terminate the message correctly */
580     buf[n] = '\0';
581
582     /* Check if the message starts with the i3 IPC magic code */
583     if (n < strlen(I3_IPC_MAGIC)) {
584         DLOG("IPC: message too short, ignoring\n");
585         return;
586     }
587
588     if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) {
589         DLOG("IPC: message does not start with the IPC magic\n");
590         return;
591     }
592
593     uint8_t *message = (uint8_t*)buf;
594     while (n > 0) {
595         DLOG("IPC: n = %d\n", n);
596         message += strlen(I3_IPC_MAGIC);
597         n -= strlen(I3_IPC_MAGIC);
598
599         /* The next 32 bit after the magic are the message size */
600         uint32_t message_size;
601         memcpy(&message_size, (uint32_t*)message, sizeof(uint32_t));
602         message += sizeof(uint32_t);
603         n -= sizeof(uint32_t);
604
605         if (message_size > n) {
606             DLOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n");
607             return;
608         }
609
610         /* The last 32 bits of the header are the message type */
611         uint32_t message_type;
612         memcpy(&message_type, (uint32_t*)message, sizeof(uint32_t));
613         message += sizeof(uint32_t);
614         n -= sizeof(uint32_t);
615
616         if (message_type >= (sizeof(handlers) / sizeof(handler_t)))
617             DLOG("Unhandled message type: %d\n", message_type);
618         else {
619             handler_t h = handlers[message_type];
620             h(w->fd, message, n, message_size, message_type);
621         }
622         n -= message_size;
623         message += message_size;
624     }
625 }
626
627 /*
628  * Handler for activity on the listening socket, meaning that a new client
629  * has just connected and we should accept() him. Sets up the event handler
630  * for activity on the new connection and inserts the file descriptor into
631  * the list of clients.
632  *
633  */
634 void ipc_new_client(EV_P_ struct ev_io *w, int revents) {
635     struct sockaddr_un peer;
636     socklen_t len = sizeof(struct sockaddr_un);
637     int client;
638     if ((client = accept(w->fd, (struct sockaddr*)&peer, &len)) < 0) {
639         if (errno == EINTR)
640             return;
641         else perror("accept()");
642         return;
643     }
644
645     set_nonblock(client);
646
647     struct ev_io *package = scalloc(sizeof(struct ev_io));
648     ev_io_init(package, ipc_receive_message, client, EV_READ);
649     ev_io_start(EV_A_ package);
650
651     DLOG("IPC: new client connected\n");
652
653     ipc_client *new = scalloc(sizeof(ipc_client));
654     new->fd = client;
655
656     TAILQ_INSERT_TAIL(&all_clients, new, clients);
657 }
658
659 /*
660  * Creates the UNIX domain socket at the given path, sets it to non-blocking
661  * mode, bind()s and listen()s on it.
662  *
663  */
664 int ipc_create_socket(const char *filename) {
665     int sockfd;
666
667     FREE(current_socketpath);
668
669     char *resolved = resolve_tilde(filename);
670     DLOG("Creating IPC-socket at %s\n", resolved);
671     char *copy = sstrdup(resolved);
672     const char *dir = dirname(copy);
673     if (!path_exists(dir))
674         mkdirp(dir);
675     free(copy);
676
677     /* Unlink the unix domain socket before */
678     unlink(resolved);
679
680     if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
681         perror("socket()");
682         free(resolved);
683         return -1;
684     }
685
686     (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC);
687
688     struct sockaddr_un addr;
689     memset(&addr, 0, sizeof(struct sockaddr_un));
690     addr.sun_family = AF_LOCAL;
691     strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1);
692     if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) {
693         perror("bind()");
694         free(resolved);
695         return -1;
696     }
697
698     set_nonblock(sockfd);
699
700     if (listen(sockfd, 5) < 0) {
701         perror("listen()");
702         free(resolved);
703         return -1;
704     }
705
706     current_socketpath = resolved;
707     return sockfd;
708 }