i3
|
00001 /* 00002 * vim:ts=8:expandtab 00003 * 00004 * i3 - an improved dynamic tiling window manager 00005 * 00006 * © 2009-2010 Michael Stapelberg and contributors 00007 * 00008 * See file LICENSE for license information. 00009 * 00010 * ipc.c: Everything about the UNIX domain sockets for IPC 00011 * 00012 */ 00013 #include <sys/types.h> 00014 #include <sys/socket.h> 00015 #include <sys/stat.h> 00016 #include <sys/un.h> 00017 #include <fcntl.h> 00018 #include <unistd.h> 00019 #include <string.h> 00020 #include <errno.h> 00021 #include <err.h> 00022 #include <stdlib.h> 00023 #include <stdint.h> 00024 #include <stdio.h> 00025 #include <libgen.h> 00026 #include <ev.h> 00027 #include <yajl/yajl_gen.h> 00028 #include <yajl/yajl_parse.h> 00029 00030 #include "queue.h" 00031 #include "ipc.h" 00032 #include "i3.h" 00033 #include "util.h" 00034 #include "commands.h" 00035 #include "log.h" 00036 #include "table.h" 00037 #include "randr.h" 00038 #include "config.h" 00039 00040 /* Shorter names for all those yajl_gen_* functions */ 00041 #define y(x, ...) yajl_gen_ ## x (gen, ##__VA_ARGS__) 00042 #define ystr(str) yajl_gen_string(gen, (unsigned char*)str, strlen(str)) 00043 00044 TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients); 00045 00046 /* 00047 * Puts the given socket file descriptor into non-blocking mode or dies if 00048 * setting O_NONBLOCK failed. Non-blocking sockets are a good idea for our 00049 * IPC model because we should by no means block the window manager. 00050 * 00051 */ 00052 static void set_nonblock(int sockfd) { 00053 int flags = fcntl(sockfd, F_GETFL, 0); 00054 flags |= O_NONBLOCK; 00055 if (fcntl(sockfd, F_SETFL, flags) < 0) 00056 err(-1, "Could not set O_NONBLOCK"); 00057 } 00058 00059 /* 00060 * Emulates mkdir -p (creates any missing folders) 00061 * 00062 */ 00063 static bool mkdirp(const char *path) { 00064 if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) 00065 return true; 00066 if (errno != ENOENT) { 00067 ELOG("mkdir(%s) failed: %s\n", path, strerror(errno)); 00068 return false; 00069 } 00070 char *copy = strdup(path); 00071 /* strip trailing slashes, if any */ 00072 while (copy[strlen(copy)-1] == '/') 00073 copy[strlen(copy)-1] = '\0'; 00074 00075 char *sep = strrchr(copy, '/'); 00076 if (sep == NULL) 00077 return false; 00078 *sep = '\0'; 00079 bool result = false; 00080 if (mkdirp(copy)) 00081 result = mkdirp(path); 00082 free(copy); 00083 00084 return result; 00085 } 00086 00087 static void ipc_send_message(int fd, const unsigned char *payload, 00088 int message_type, int message_size) { 00089 int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) + 00090 sizeof(uint32_t) + message_size; 00091 char msg[buffer_size]; 00092 char *walk = msg; 00093 00094 strcpy(walk, "i3-ipc"); 00095 walk += strlen("i3-ipc"); 00096 memcpy(walk, &message_size, sizeof(uint32_t)); 00097 walk += sizeof(uint32_t); 00098 memcpy(walk, &message_type, sizeof(uint32_t)); 00099 walk += sizeof(uint32_t); 00100 memcpy(walk, payload, message_size); 00101 00102 int sent_bytes = 0; 00103 int bytes_to_go = buffer_size; 00104 while (sent_bytes < bytes_to_go) { 00105 int n = write(fd, msg + sent_bytes, bytes_to_go); 00106 if (n == -1) { 00107 DLOG("write() failed: %s\n", strerror(errno)); 00108 return; 00109 } 00110 00111 sent_bytes += n; 00112 bytes_to_go -= n; 00113 } 00114 } 00115 00116 /* 00117 * Sends the specified event to all IPC clients which are currently connected 00118 * and subscribed to this kind of event. 00119 * 00120 */ 00121 void ipc_send_event(const char *event, uint32_t message_type, const char *payload) { 00122 ipc_client *current; 00123 TAILQ_FOREACH(current, &all_clients, clients) { 00124 /* see if this client is interested in this event */ 00125 bool interested = false; 00126 for (int i = 0; i < current->num_events; i++) { 00127 if (strcasecmp(current->events[i], event) != 0) 00128 continue; 00129 interested = true; 00130 break; 00131 } 00132 if (!interested) 00133 continue; 00134 00135 ipc_send_message(current->fd, (const unsigned char*)payload, 00136 message_type, strlen(payload)); 00137 } 00138 } 00139 00140 /* 00141 * Calls shutdown() on each socket and closes it. This function to be called 00142 * when exiting or restarting only! 00143 * 00144 */ 00145 void ipc_shutdown() { 00146 ipc_client *current; 00147 TAILQ_FOREACH(current, &all_clients, clients) { 00148 shutdown(current->fd, SHUT_RDWR); 00149 close(current->fd); 00150 } 00151 } 00152 00153 /* 00154 * Executes the command and returns whether it could be successfully parsed 00155 * or not (at the moment, always returns true). 00156 * 00157 */ 00158 IPC_HANDLER(command) { 00159 /* To get a properly terminated buffer, we copy 00160 * message_size bytes out of the buffer */ 00161 char *command = scalloc(message_size); 00162 strncpy(command, (const char*)message, message_size); 00163 parse_command(global_conn, (const char*)command); 00164 free(command); 00165 00166 /* For now, every command gets a positive acknowledge 00167 * (will change with the new command parser) */ 00168 const char *reply = "{\"success\":true}"; 00169 ipc_send_message(fd, (const unsigned char*)reply, 00170 I3_IPC_REPLY_TYPE_COMMAND, strlen(reply)); 00171 } 00172 00173 /* 00174 * Formats the reply message for a GET_WORKSPACES request and sends it to the 00175 * client 00176 * 00177 */ 00178 IPC_HANDLER(get_workspaces) { 00179 Workspace *ws; 00180 00181 Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack)); 00182 if (last_focused == SLIST_END(&(c_ws->focus_stack))) 00183 last_focused = NULL; 00184 00185 yajl_gen gen = yajl_gen_alloc(NULL, NULL); 00186 y(array_open); 00187 00188 TAILQ_FOREACH(ws, workspaces, workspaces) { 00189 if (ws->output == NULL) 00190 continue; 00191 00192 y(map_open); 00193 ystr("num"); 00194 y(integer, ws->num + 1); 00195 00196 ystr("name"); 00197 ystr(ws->utf8_name); 00198 00199 ystr("visible"); 00200 y(bool, ws->output->current_workspace == ws); 00201 00202 ystr("focused"); 00203 y(bool, c_ws == ws); 00204 00205 ystr("rect"); 00206 y(map_open); 00207 ystr("x"); 00208 y(integer, ws->rect.x); 00209 ystr("y"); 00210 y(integer, ws->rect.y); 00211 ystr("width"); 00212 y(integer, ws->rect.width); 00213 ystr("height"); 00214 y(integer, ws->rect.height); 00215 y(map_close); 00216 00217 ystr("output"); 00218 ystr(ws->output->name); 00219 00220 ystr("urgent"); 00221 y(bool, ws->urgent); 00222 00223 y(map_close); 00224 } 00225 00226 y(array_close); 00227 00228 const unsigned char *payload; 00229 unsigned int length; 00230 y(get_buf, &payload, &length); 00231 00232 ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_WORKSPACES, length); 00233 y(free); 00234 } 00235 00236 /* 00237 * Formats the reply message for a GET_OUTPUTS request and sends it to the 00238 * client 00239 * 00240 */ 00241 IPC_HANDLER(get_outputs) { 00242 Output *output; 00243 00244 yajl_gen gen = yajl_gen_alloc(NULL, NULL); 00245 y(array_open); 00246 00247 TAILQ_FOREACH(output, &outputs, outputs) { 00248 y(map_open); 00249 00250 ystr("name"); 00251 ystr(output->name); 00252 00253 ystr("active"); 00254 y(bool, output->active); 00255 00256 ystr("rect"); 00257 y(map_open); 00258 ystr("x"); 00259 y(integer, output->rect.x); 00260 ystr("y"); 00261 y(integer, output->rect.y); 00262 ystr("width"); 00263 y(integer, output->rect.width); 00264 ystr("height"); 00265 y(integer, output->rect.height); 00266 y(map_close); 00267 00268 ystr("current_workspace"); 00269 if (output->current_workspace == NULL) 00270 y(null); 00271 else y(integer, output->current_workspace->num + 1); 00272 00273 y(map_close); 00274 } 00275 00276 y(array_close); 00277 00278 const unsigned char *payload; 00279 unsigned int length; 00280 y(get_buf, &payload, &length); 00281 00282 ipc_send_message(fd, payload, I3_IPC_REPLY_TYPE_OUTPUTS, length); 00283 y(free); 00284 } 00285 00286 /* 00287 * Callback for the YAJL parser (will be called when a string is parsed). 00288 * 00289 */ 00290 static int add_subscription(void *extra, const unsigned char *s, 00291 unsigned int len) { 00292 ipc_client *client = extra; 00293 00294 DLOG("should add subscription to extra %p, sub %.*s\n", client, len, s); 00295 int event = client->num_events; 00296 00297 client->num_events++; 00298 client->events = realloc(client->events, client->num_events * sizeof(char*)); 00299 /* We copy the string because it is not null-terminated and strndup() 00300 * is missing on some BSD systems */ 00301 client->events[event] = scalloc(len+1); 00302 memcpy(client->events[event], s, len); 00303 00304 DLOG("client is now subscribed to:\n"); 00305 for (int i = 0; i < client->num_events; i++) 00306 DLOG("event %s\n", client->events[i]); 00307 DLOG("(done)\n"); 00308 00309 return 1; 00310 } 00311 00312 /* 00313 * Subscribes this connection to the event types which were given as a JSON 00314 * serialized array in the payload field of the message. 00315 * 00316 */ 00317 IPC_HANDLER(subscribe) { 00318 yajl_handle p; 00319 yajl_callbacks callbacks; 00320 yajl_status stat; 00321 ipc_client *current, *client = NULL; 00322 00323 /* Search the ipc_client structure for this connection */ 00324 TAILQ_FOREACH(current, &all_clients, clients) { 00325 if (current->fd != fd) 00326 continue; 00327 00328 client = current; 00329 break; 00330 } 00331 00332 if (client == NULL) { 00333 ELOG("Could not find ipc_client data structure for fd %d\n", fd); 00334 return; 00335 } 00336 00337 /* Setup the JSON parser */ 00338 memset(&callbacks, 0, sizeof(yajl_callbacks)); 00339 callbacks.yajl_string = add_subscription; 00340 00341 p = yajl_alloc(&callbacks, NULL, NULL, (void*)client); 00342 stat = yajl_parse(p, (const unsigned char*)message, message_size); 00343 if (stat != yajl_status_ok) { 00344 unsigned char *err; 00345 err = yajl_get_error(p, true, (const unsigned char*)message, 00346 message_size); 00347 ELOG("YAJL parse error: %s\n", err); 00348 yajl_free_error(p, err); 00349 00350 const char *reply = "{\"success\":false}"; 00351 ipc_send_message(fd, (const unsigned char*)reply, 00352 I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply)); 00353 yajl_free(p); 00354 return; 00355 } 00356 yajl_free(p); 00357 const char *reply = "{\"success\":true}"; 00358 ipc_send_message(fd, (const unsigned char*)reply, 00359 I3_IPC_REPLY_TYPE_SUBSCRIBE, strlen(reply)); 00360 } 00361 00362 /* The index of each callback function corresponds to the numeric 00363 * value of the message type (see include/i3/ipc.h) */ 00364 handler_t handlers[4] = { 00365 handle_command, 00366 handle_get_workspaces, 00367 handle_subscribe, 00368 handle_get_outputs 00369 }; 00370 00371 /* 00372 * Handler for activity on a client connection, receives a message from a 00373 * client. 00374 * 00375 * For now, the maximum message size is 2048. I’m not sure for what the 00376 * IPC interface will be used in the future, thus I’m not implementing a 00377 * mechanism for arbitrarily long messages, as it seems like overkill 00378 * at the moment. 00379 * 00380 */ 00381 static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { 00382 char buf[2048]; 00383 int n = read(w->fd, buf, sizeof(buf)); 00384 00385 /* On error or an empty message, we close the connection */ 00386 if (n <= 0) { 00387 #if 0 00388 /* FIXME: I get these when closing a client socket, 00389 * therefore we just treat them as an error. Is this 00390 * correct? */ 00391 if (errno == EAGAIN || errno == EWOULDBLOCK) 00392 return; 00393 #endif 00394 00395 /* If not, there was some kind of error. We don’t bother 00396 * and close the connection */ 00397 close(w->fd); 00398 00399 /* Delete the client from the list of clients */ 00400 ipc_client *current; 00401 TAILQ_FOREACH(current, &all_clients, clients) { 00402 if (current->fd != w->fd) 00403 continue; 00404 00405 for (int i = 0; i < current->num_events; i++) 00406 free(current->events[i]); 00407 /* We can call TAILQ_REMOVE because we break out of the 00408 * TAILQ_FOREACH afterwards */ 00409 TAILQ_REMOVE(&all_clients, current, clients); 00410 break; 00411 } 00412 00413 ev_io_stop(EV_A_ w); 00414 00415 DLOG("IPC: client disconnected\n"); 00416 return; 00417 } 00418 00419 /* Terminate the message correctly */ 00420 buf[n] = '\0'; 00421 00422 /* Check if the message starts with the i3 IPC magic code */ 00423 if (n < strlen(I3_IPC_MAGIC)) { 00424 DLOG("IPC: message too short, ignoring\n"); 00425 return; 00426 } 00427 00428 if (strncmp(buf, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0) { 00429 DLOG("IPC: message does not start with the IPC magic\n"); 00430 return; 00431 } 00432 00433 uint8_t *message = (uint8_t*)buf; 00434 while (n > 0) { 00435 DLOG("IPC: n = %d\n", n); 00436 message += strlen(I3_IPC_MAGIC); 00437 n -= strlen(I3_IPC_MAGIC); 00438 00439 /* The next 32 bit after the magic are the message size */ 00440 uint32_t message_size = *((uint32_t*)message); 00441 message += sizeof(uint32_t); 00442 n -= sizeof(uint32_t); 00443 00444 if (message_size > n) { 00445 DLOG("IPC: Either the message size was wrong or the message was not read completely, dropping\n"); 00446 return; 00447 } 00448 00449 /* The last 32 bits of the header are the message type */ 00450 uint32_t message_type = *((uint32_t*)message); 00451 message += sizeof(uint32_t); 00452 n -= sizeof(uint32_t); 00453 00454 if (message_type >= (sizeof(handlers) / sizeof(handler_t))) 00455 DLOG("Unhandled message type: %d\n", message_type); 00456 else { 00457 handler_t h = handlers[message_type]; 00458 h(w->fd, message, n, message_size, message_type); 00459 } 00460 n -= message_size; 00461 message += message_size; 00462 } 00463 } 00464 00465 /* 00466 * Handler for activity on the listening socket, meaning that a new client 00467 * has just connected and we should accept() him. Sets up the event handler 00468 * for activity on the new connection and inserts the file descriptor into 00469 * the list of clients. 00470 * 00471 */ 00472 void ipc_new_client(EV_P_ struct ev_io *w, int revents) { 00473 struct sockaddr_un peer; 00474 socklen_t len = sizeof(struct sockaddr_un); 00475 int client; 00476 if ((client = accept(w->fd, (struct sockaddr*)&peer, &len)) < 0) { 00477 if (errno == EINTR) 00478 return; 00479 else perror("accept()"); 00480 return; 00481 } 00482 00483 set_nonblock(client); 00484 00485 struct ev_io *package = scalloc(sizeof(struct ev_io)); 00486 ev_io_init(package, ipc_receive_message, client, EV_READ); 00487 ev_io_start(EV_A_ package); 00488 00489 DLOG("IPC: new client connected\n"); 00490 00491 ipc_client *new = scalloc(sizeof(ipc_client)); 00492 new->fd = client; 00493 00494 TAILQ_INSERT_TAIL(&all_clients, new, clients); 00495 } 00496 00497 /* 00498 * Creates the UNIX domain socket at the given path, sets it to non-blocking 00499 * mode, bind()s and listen()s on it. 00500 * 00501 */ 00502 int ipc_create_socket(const char *filename) { 00503 int sockfd; 00504 00505 char *globbed = glob_path(filename); 00506 DLOG("Creating IPC-socket at %s\n", globbed); 00507 char *copy = sstrdup(globbed); 00508 const char *dir = dirname(copy); 00509 if (!path_exists(dir)) 00510 mkdirp(dir); 00511 free(copy); 00512 00513 /* Unlink the unix domain socket before */ 00514 unlink(globbed); 00515 00516 if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { 00517 perror("socket()"); 00518 free(globbed); 00519 return -1; 00520 } 00521 00522 (void)fcntl(sockfd, F_SETFD, FD_CLOEXEC); 00523 00524 struct sockaddr_un addr; 00525 memset(&addr, 0, sizeof(struct sockaddr_un)); 00526 addr.sun_family = AF_LOCAL; 00527 strcpy(addr.sun_path, globbed); 00528 if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) { 00529 perror("bind()"); 00530 free(globbed); 00531 return -1; 00532 } 00533 00534 free(globbed); 00535 set_nonblock(sockfd); 00536 00537 if (listen(sockfd, 5) < 0) { 00538 perror("listen()"); 00539 return -1; 00540 } 00541 00542 return sockfd; 00543 }