Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1201 lines
33 KiB

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