diff options
Diffstat (limited to 'sway/ipc-server.c')
-rw-r--r-- | sway/ipc-server.c | 198 |
1 files changed, 125 insertions, 73 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 241fe742..be703915 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include <wayland-server.h> | 18 | #include <wayland-server.h> |
19 | #include "sway/commands.h" | 19 | #include "sway/commands.h" |
20 | #include "sway/config.h" | ||
21 | #include "sway/desktop/transaction.h" | ||
20 | #include "sway/ipc-json.h" | 22 | #include "sway/ipc-json.h" |
21 | #include "sway/ipc-server.h" | 23 | #include "sway/ipc-server.h" |
22 | #include "sway/output.h" | 24 | #include "sway/output.h" |
@@ -31,6 +33,7 @@ static int ipc_socket = -1; | |||
31 | static struct wl_event_source *ipc_event_source = NULL; | 33 | static struct wl_event_source *ipc_event_source = NULL; |
32 | static struct sockaddr_un *ipc_sockaddr = NULL; | 34 | static struct sockaddr_un *ipc_sockaddr = NULL; |
33 | static list_t *ipc_client_list = NULL; | 35 | static list_t *ipc_client_list = NULL; |
36 | static struct wl_listener ipc_display_destroy; | ||
34 | 37 | ||
35 | static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; | 38 | static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; |
36 | 39 | ||
@@ -56,6 +59,26 @@ void ipc_client_disconnect(struct ipc_client *client); | |||
56 | void ipc_client_handle_command(struct ipc_client *client); | 59 | void ipc_client_handle_command(struct ipc_client *client); |
57 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); | 60 | bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); |
58 | 61 | ||
62 | static void handle_display_destroy(struct wl_listener *listener, void *data) { | ||
63 | if (ipc_event_source) { | ||
64 | wl_event_source_remove(ipc_event_source); | ||
65 | } | ||
66 | close(ipc_socket); | ||
67 | unlink(ipc_sockaddr->sun_path); | ||
68 | |||
69 | while (ipc_client_list->length) { | ||
70 | struct ipc_client *client = ipc_client_list->items[0]; | ||
71 | ipc_client_disconnect(client); | ||
72 | } | ||
73 | list_free(ipc_client_list); | ||
74 | |||
75 | if (ipc_sockaddr) { | ||
76 | free(ipc_sockaddr); | ||
77 | } | ||
78 | |||
79 | wl_list_remove(&ipc_display_destroy.link); | ||
80 | } | ||
81 | |||
59 | void ipc_init(struct sway_server *server) { | 82 | void ipc_init(struct sway_server *server) { |
60 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); | 83 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); |
61 | if (ipc_socket == -1) { | 84 | if (ipc_socket == -1) { |
@@ -85,24 +108,13 @@ void ipc_init(struct sway_server *server) { | |||
85 | 108 | ||
86 | ipc_client_list = create_list(); | 109 | ipc_client_list = create_list(); |
87 | 110 | ||
111 | ipc_display_destroy.notify = handle_display_destroy; | ||
112 | wl_display_add_destroy_listener(server->wl_display, &ipc_display_destroy); | ||
113 | |||
88 | ipc_event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc_socket, | 114 | ipc_event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc_socket, |
89 | WL_EVENT_READABLE, ipc_handle_connection, server); | 115 | WL_EVENT_READABLE, ipc_handle_connection, server); |
90 | } | 116 | } |
91 | 117 | ||
92 | void ipc_terminate(void) { | ||
93 | if (ipc_event_source) { | ||
94 | wl_event_source_remove(ipc_event_source); | ||
95 | } | ||
96 | close(ipc_socket); | ||
97 | unlink(ipc_sockaddr->sun_path); | ||
98 | |||
99 | list_free(ipc_client_list); | ||
100 | |||
101 | if (ipc_sockaddr) { | ||
102 | free(ipc_sockaddr); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | struct sockaddr_un *ipc_user_sockaddr(void) { | 118 | struct sockaddr_un *ipc_user_sockaddr(void) { |
107 | struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un)); | 119 | struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un)); |
108 | if (ipc_sockaddr == NULL) { | 120 | if (ipc_sockaddr == NULL) { |
@@ -128,32 +140,32 @@ struct sockaddr_un *ipc_user_sockaddr(void) { | |||
128 | int ipc_handle_connection(int fd, uint32_t mask, void *data) { | 140 | int ipc_handle_connection(int fd, uint32_t mask, void *data) { |
129 | (void) fd; | 141 | (void) fd; |
130 | struct sway_server *server = data; | 142 | struct sway_server *server = data; |
131 | wlr_log(L_DEBUG, "Event on IPC listening socket"); | 143 | wlr_log(WLR_DEBUG, "Event on IPC listening socket"); |
132 | assert(mask == WL_EVENT_READABLE); | 144 | assert(mask == WL_EVENT_READABLE); |
133 | 145 | ||
134 | int client_fd = accept(ipc_socket, NULL, NULL); | 146 | int client_fd = accept(ipc_socket, NULL, NULL); |
135 | if (client_fd == -1) { | 147 | if (client_fd == -1) { |
136 | wlr_log_errno(L_ERROR, "Unable to accept IPC client connection"); | 148 | wlr_log_errno(WLR_ERROR, "Unable to accept IPC client connection"); |
137 | return 0; | 149 | return 0; |
138 | } | 150 | } |
139 | 151 | ||
140 | int flags; | 152 | int flags; |
141 | if ((flags = fcntl(client_fd, F_GETFD)) == -1 | 153 | if ((flags = fcntl(client_fd, F_GETFD)) == -1 |
142 | || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { | 154 | || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { |
143 | wlr_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); | 155 | wlr_log_errno(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket"); |
144 | close(client_fd); | 156 | close(client_fd); |
145 | return 0; | 157 | return 0; |
146 | } | 158 | } |
147 | if ((flags = fcntl(client_fd, F_GETFL)) == -1 | 159 | if ((flags = fcntl(client_fd, F_GETFL)) == -1 |
148 | || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { | 160 | || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { |
149 | wlr_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket"); | 161 | wlr_log_errno(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket"); |
150 | close(client_fd); | 162 | close(client_fd); |
151 | return 0; | 163 | return 0; |
152 | } | 164 | } |
153 | 165 | ||
154 | struct ipc_client *client = malloc(sizeof(struct ipc_client)); | 166 | struct ipc_client *client = malloc(sizeof(struct ipc_client)); |
155 | if (!client) { | 167 | if (!client) { |
156 | wlr_log(L_ERROR, "Unable to allocate ipc client"); | 168 | wlr_log(WLR_ERROR, "Unable to allocate ipc client"); |
157 | close(client_fd); | 169 | close(client_fd); |
158 | return 0; | 170 | return 0; |
159 | } | 171 | } |
@@ -169,12 +181,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
169 | client->write_buffer_len = 0; | 181 | client->write_buffer_len = 0; |
170 | client->write_buffer = malloc(client->write_buffer_size); | 182 | client->write_buffer = malloc(client->write_buffer_size); |
171 | if (!client->write_buffer) { | 183 | if (!client->write_buffer) { |
172 | wlr_log(L_ERROR, "Unable to allocate ipc client write buffer"); | 184 | wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer"); |
173 | close(client_fd); | 185 | close(client_fd); |
174 | return 0; | 186 | return 0; |
175 | } | 187 | } |
176 | 188 | ||
177 | wlr_log(L_DEBUG, "New client: fd %d", client_fd); | 189 | wlr_log(WLR_DEBUG, "New client: fd %d", client_fd); |
178 | list_add(ipc_client_list, client); | 190 | list_add(ipc_client_list, client); |
179 | return 0; | 191 | return 0; |
180 | } | 192 | } |
@@ -185,22 +197,22 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
185 | struct ipc_client *client = data; | 197 | struct ipc_client *client = data; |
186 | 198 | ||
187 | if (mask & WL_EVENT_ERROR) { | 199 | if (mask & WL_EVENT_ERROR) { |
188 | wlr_log(L_ERROR, "IPC Client socket error, removing client"); | 200 | wlr_log(WLR_ERROR, "IPC Client socket error, removing client"); |
189 | ipc_client_disconnect(client); | 201 | ipc_client_disconnect(client); |
190 | return 0; | 202 | return 0; |
191 | } | 203 | } |
192 | 204 | ||
193 | if (mask & WL_EVENT_HANGUP) { | 205 | if (mask & WL_EVENT_HANGUP) { |
194 | wlr_log(L_DEBUG, "Client %d hung up", client->fd); | 206 | wlr_log(WLR_DEBUG, "Client %d hung up", client->fd); |
195 | ipc_client_disconnect(client); | 207 | ipc_client_disconnect(client); |
196 | return 0; | 208 | return 0; |
197 | } | 209 | } |
198 | 210 | ||
199 | wlr_log(L_DEBUG, "Client %d readable", client->fd); | 211 | wlr_log(WLR_DEBUG, "Client %d readable", client->fd); |
200 | 212 | ||
201 | int read_available; | 213 | int read_available; |
202 | if (ioctl(client_fd, FIONREAD, &read_available) == -1) { | 214 | if (ioctl(client_fd, FIONREAD, &read_available) == -1) { |
203 | wlr_log_errno(L_INFO, "Unable to read IPC socket buffer size"); | 215 | wlr_log_errno(WLR_INFO, "Unable to read IPC socket buffer size"); |
204 | ipc_client_disconnect(client); | 216 | ipc_client_disconnect(client); |
205 | return 0; | 217 | return 0; |
206 | } | 218 | } |
@@ -222,13 +234,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
222 | // Should be fully available, because read_available >= ipc_header_size | 234 | // Should be fully available, because read_available >= ipc_header_size |
223 | ssize_t received = recv(client_fd, buf, ipc_header_size, 0); | 235 | ssize_t received = recv(client_fd, buf, ipc_header_size, 0); |
224 | if (received == -1) { | 236 | if (received == -1) { |
225 | wlr_log_errno(L_INFO, "Unable to receive header from IPC client"); | 237 | wlr_log_errno(WLR_INFO, "Unable to receive header from IPC client"); |
226 | ipc_client_disconnect(client); | 238 | ipc_client_disconnect(client); |
227 | return 0; | 239 | return 0; |
228 | } | 240 | } |
229 | 241 | ||
230 | if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) { | 242 | if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) { |
231 | wlr_log(L_DEBUG, "IPC header check failed"); | 243 | wlr_log(WLR_DEBUG, "IPC header check failed"); |
232 | ipc_client_disconnect(client); | 244 | ipc_client_disconnect(client); |
233 | return 0; | 245 | return 0; |
234 | } | 246 | } |
@@ -262,8 +274,11 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event) | |||
262 | } | 274 | } |
263 | client->current_command = event; | 275 | client->current_command = event; |
264 | if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) { | 276 | if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) { |
265 | wlr_log_errno(L_INFO, "Unable to send reply to IPC client"); | 277 | wlr_log_errno(WLR_INFO, "Unable to send reply to IPC client"); |
266 | ipc_client_disconnect(client); | 278 | /* ipc_send_reply destroys client on error, which also |
279 | * removes it from the list, so we need to process | ||
280 | * current index again */ | ||
281 | i--; | ||
267 | } | 282 | } |
268 | } | 283 | } |
269 | } | 284 | } |
@@ -273,7 +288,7 @@ void ipc_event_workspace(struct sway_container *old, | |||
273 | if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { | 288 | if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { |
274 | return; | 289 | return; |
275 | } | 290 | } |
276 | wlr_log(L_DEBUG, "Sending workspace::%s event", change); | 291 | wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); |
277 | json_object *obj = json_object_new_object(); | 292 | json_object *obj = json_object_new_object(); |
278 | json_object_object_add(obj, "change", json_object_new_string(change)); | 293 | json_object_object_add(obj, "change", json_object_new_string(change)); |
279 | if (strcmp("focus", change) == 0) { | 294 | if (strcmp("focus", change) == 0) { |
@@ -301,7 +316,7 @@ void ipc_event_window(struct sway_container *window, const char *change) { | |||
301 | if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) { | 316 | if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) { |
302 | return; | 317 | return; |
303 | } | 318 | } |
304 | wlr_log(L_DEBUG, "Sending window::%s event", change); | 319 | wlr_log(WLR_DEBUG, "Sending window::%s event", change); |
305 | json_object *obj = json_object_new_object(); | 320 | json_object *obj = json_object_new_object(); |
306 | json_object_object_add(obj, "change", json_object_new_string(change)); | 321 | json_object_object_add(obj, "change", json_object_new_string(change)); |
307 | json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); | 322 | json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); |
@@ -315,7 +330,7 @@ void ipc_event_barconfig_update(struct bar_config *bar) { | |||
315 | if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) { | 330 | if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) { |
316 | return; | 331 | return; |
317 | } | 332 | } |
318 | wlr_log(L_DEBUG, "Sending barconfig_update event"); | 333 | wlr_log(WLR_DEBUG, "Sending barconfig_update event"); |
319 | json_object *json = ipc_json_describe_bar_config(bar); | 334 | json_object *json = ipc_json_describe_bar_config(bar); |
320 | 335 | ||
321 | const char *json_string = json_object_to_json_string(json); | 336 | const char *json_string = json_object_to_json_string(json); |
@@ -323,13 +338,15 @@ void ipc_event_barconfig_update(struct bar_config *bar) { | |||
323 | json_object_put(json); | 338 | json_object_put(json); |
324 | } | 339 | } |
325 | 340 | ||
326 | void ipc_event_mode(const char *mode) { | 341 | void ipc_event_mode(const char *mode, bool pango) { |
327 | if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { | 342 | if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { |
328 | return; | 343 | return; |
329 | } | 344 | } |
330 | wlr_log(L_DEBUG, "Sending mode::%s event", mode); | 345 | wlr_log(WLR_DEBUG, "Sending mode::%s event", mode); |
331 | json_object *obj = json_object_new_object(); | 346 | json_object *obj = json_object_new_object(); |
332 | json_object_object_add(obj, "change", json_object_new_string(mode)); | 347 | json_object_object_add(obj, "change", json_object_new_string(mode)); |
348 | json_object_object_add(obj, "pango_markup", | ||
349 | json_object_new_boolean(pango)); | ||
333 | 350 | ||
334 | const char *json_string = json_object_to_json_string(obj); | 351 | const char *json_string = json_object_to_json_string(obj); |
335 | ipc_send_event(json_string, IPC_EVENT_MODE); | 352 | ipc_send_event(json_string, IPC_EVENT_MODE); |
@@ -340,13 +357,13 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { | |||
340 | struct ipc_client *client = data; | 357 | struct ipc_client *client = data; |
341 | 358 | ||
342 | if (mask & WL_EVENT_ERROR) { | 359 | if (mask & WL_EVENT_ERROR) { |
343 | wlr_log(L_ERROR, "IPC Client socket error, removing client"); | 360 | wlr_log(WLR_ERROR, "IPC Client socket error, removing client"); |
344 | ipc_client_disconnect(client); | 361 | ipc_client_disconnect(client); |
345 | return 0; | 362 | return 0; |
346 | } | 363 | } |
347 | 364 | ||
348 | if (mask & WL_EVENT_HANGUP) { | 365 | if (mask & WL_EVENT_HANGUP) { |
349 | wlr_log(L_DEBUG, "Client %d hung up", client->fd); | 366 | wlr_log(WLR_DEBUG, "Client %d hung up", client->fd); |
350 | ipc_client_disconnect(client); | 367 | ipc_client_disconnect(client); |
351 | return 0; | 368 | return 0; |
352 | } | 369 | } |
@@ -355,14 +372,14 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { | |||
355 | return 0; | 372 | return 0; |
356 | } | 373 | } |
357 | 374 | ||
358 | wlr_log(L_DEBUG, "Client %d writable", client->fd); | 375 | wlr_log(WLR_DEBUG, "Client %d writable", client->fd); |
359 | 376 | ||
360 | ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); | 377 | ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); |
361 | 378 | ||
362 | if (written == -1 && errno == EAGAIN) { | 379 | if (written == -1 && errno == EAGAIN) { |
363 | return 0; | 380 | return 0; |
364 | } else if (written == -1) { | 381 | } else if (written == -1) { |
365 | wlr_log_errno(L_INFO, "Unable to send data from queue to IPC client"); | 382 | wlr_log_errno(WLR_INFO, "Unable to send data from queue to IPC client"); |
366 | ipc_client_disconnect(client); | 383 | ipc_client_disconnect(client); |
367 | return 0; | 384 | return 0; |
368 | } | 385 | } |
@@ -383,11 +400,9 @@ void ipc_client_disconnect(struct ipc_client *client) { | |||
383 | return; | 400 | return; |
384 | } | 401 | } |
385 | 402 | ||
386 | if (client->fd != -1) { | 403 | shutdown(client->fd, SHUT_RDWR); |
387 | shutdown(client->fd, SHUT_RDWR); | ||
388 | } | ||
389 | 404 | ||
390 | wlr_log(L_INFO, "IPC Client %d disconnected", client->fd); | 405 | wlr_log(WLR_INFO, "IPC Client %d disconnected", client->fd); |
391 | wl_event_source_remove(client->event_source); | 406 | wl_event_source_remove(client->event_source); |
392 | if (client->writable_event_source) { | 407 | if (client->writable_event_source) { |
393 | wl_event_source_remove(client->writable_event_source); | 408 | wl_event_source_remove(client->writable_event_source); |
@@ -448,7 +463,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
448 | 463 | ||
449 | char *buf = malloc(client->payload_length + 1); | 464 | char *buf = malloc(client->payload_length + 1); |
450 | if (!buf) { | 465 | if (!buf) { |
451 | wlr_log_errno(L_INFO, "Unable to allocate IPC payload"); | 466 | wlr_log_errno(WLR_INFO, "Unable to allocate IPC payload"); |
452 | ipc_client_disconnect(client); | 467 | ipc_client_disconnect(client); |
453 | return; | 468 | return; |
454 | } | 469 | } |
@@ -457,7 +472,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
457 | ssize_t received = recv(client->fd, buf, client->payload_length, 0); | 472 | ssize_t received = recv(client->fd, buf, client->payload_length, 0); |
458 | if (received == -1) | 473 | if (received == -1) |
459 | { | 474 | { |
460 | wlr_log_errno(L_INFO, "Unable to receive payload from IPC client"); | 475 | wlr_log_errno(WLR_INFO, "Unable to receive payload from IPC client"); |
461 | ipc_client_disconnect(client); | 476 | ipc_client_disconnect(client); |
462 | free(buf); | 477 | free(buf); |
463 | return; | 478 | return; |
@@ -465,16 +480,16 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
465 | } | 480 | } |
466 | buf[client->payload_length] = '\0'; | 481 | buf[client->payload_length] = '\0'; |
467 | 482 | ||
468 | const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }"; | 483 | bool client_valid = true; |
469 | |||
470 | switch (client->current_command) { | 484 | switch (client->current_command) { |
471 | case IPC_COMMAND: | 485 | case IPC_COMMAND: |
472 | { | 486 | { |
473 | struct cmd_results *results = execute_command(buf, NULL); | 487 | struct cmd_results *results = execute_command(buf, NULL); |
474 | const char *json = cmd_results_to_json(results); | 488 | transaction_commit_dirty(); |
475 | char reply[256]; | 489 | char *json = cmd_results_to_json(results); |
476 | int length = snprintf(reply, sizeof(reply), "%s", json); | 490 | int length = strlen(json); |
477 | ipc_send_reply(client, reply, (uint32_t) length); | 491 | client_valid = ipc_send_reply(client, json, (uint32_t)length); |
492 | free(json); | ||
478 | free_cmd_results(results); | 493 | free_cmd_results(results); |
479 | goto exit_cleanup; | 494 | goto exit_cleanup; |
480 | } | 495 | } |
@@ -497,7 +512,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
497 | } | 512 | } |
498 | } | 513 | } |
499 | const char *json_string = json_object_to_json_string(outputs); | 514 | const char *json_string = json_object_to_json_string(outputs); |
500 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | 515 | client_valid = |
516 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
501 | json_object_put(outputs); // free | 517 | json_object_put(outputs); // free |
502 | goto exit_cleanup; | 518 | goto exit_cleanup; |
503 | } | 519 | } |
@@ -508,7 +524,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
508 | container_for_each_descendant_dfs(&root_container, | 524 | container_for_each_descendant_dfs(&root_container, |
509 | ipc_get_workspaces_callback, workspaces); | 525 | ipc_get_workspaces_callback, workspaces); |
510 | const char *json_string = json_object_to_json_string(workspaces); | 526 | const char *json_string = json_object_to_json_string(workspaces); |
511 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | 527 | client_valid = |
528 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
512 | json_object_put(workspaces); // free | 529 | json_object_put(workspaces); // free |
513 | goto exit_cleanup; | 530 | goto exit_cleanup; |
514 | } | 531 | } |
@@ -518,8 +535,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
518 | // TODO: Check if they're permitted to use these events | 535 | // TODO: Check if they're permitted to use these events |
519 | struct json_object *request = json_tokener_parse(buf); | 536 | struct json_object *request = json_tokener_parse(buf); |
520 | if (request == NULL) { | 537 | if (request == NULL) { |
521 | ipc_send_reply(client, "{\"success\": false}", 18); | 538 | client_valid = ipc_send_reply(client, "{\"success\": false}", 18); |
522 | wlr_log_errno(L_INFO, "Failed to read request"); | 539 | wlr_log_errno(WLR_INFO, "Failed to read request"); |
523 | goto exit_cleanup; | 540 | goto exit_cleanup; |
524 | } | 541 | } |
525 | 542 | ||
@@ -539,15 +556,16 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
539 | } else if (strcmp(event_type, "binding") == 0) { | 556 | } else if (strcmp(event_type, "binding") == 0) { |
540 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); | 557 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); |
541 | } else { | 558 | } else { |
542 | ipc_send_reply(client, "{\"success\": false}", 18); | 559 | client_valid = |
560 | ipc_send_reply(client, "{\"success\": false}", 18); | ||
543 | json_object_put(request); | 561 | json_object_put(request); |
544 | wlr_log_errno(L_INFO, "Failed to parse request"); | 562 | wlr_log_errno(WLR_INFO, "Failed to parse request"); |
545 | goto exit_cleanup; | 563 | goto exit_cleanup; |
546 | } | 564 | } |
547 | } | 565 | } |
548 | 566 | ||
549 | json_object_put(request); | 567 | json_object_put(request); |
550 | ipc_send_reply(client, "{\"success\": true}", 17); | 568 | client_valid = ipc_send_reply(client, "{\"success\": true}", 17); |
551 | goto exit_cleanup; | 569 | goto exit_cleanup; |
552 | } | 570 | } |
553 | 571 | ||
@@ -559,7 +577,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
559 | json_object_array_add(inputs, ipc_json_describe_input(device)); | 577 | json_object_array_add(inputs, ipc_json_describe_input(device)); |
560 | } | 578 | } |
561 | const char *json_string = json_object_to_json_string(inputs); | 579 | const char *json_string = json_object_to_json_string(inputs); |
562 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 580 | client_valid = |
581 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
563 | json_object_put(inputs); // free | 582 | json_object_put(inputs); // free |
564 | goto exit_cleanup; | 583 | goto exit_cleanup; |
565 | } | 584 | } |
@@ -572,7 +591,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
572 | json_object_array_add(seats, ipc_json_describe_seat(seat)); | 591 | json_object_array_add(seats, ipc_json_describe_seat(seat)); |
573 | } | 592 | } |
574 | const char *json_string = json_object_to_json_string(seats); | 593 | const char *json_string = json_object_to_json_string(seats); |
575 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 594 | client_valid = |
595 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
576 | json_object_put(seats); // free | 596 | json_object_put(seats); // free |
577 | goto exit_cleanup; | 597 | goto exit_cleanup; |
578 | } | 598 | } |
@@ -582,7 +602,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
582 | json_object *tree = | 602 | json_object *tree = |
583 | ipc_json_describe_container_recursive(&root_container); | 603 | ipc_json_describe_container_recursive(&root_container); |
584 | const char *json_string = json_object_to_json_string(tree); | 604 | const char *json_string = json_object_to_json_string(tree); |
585 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | 605 | client_valid = |
606 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | ||
586 | json_object_put(tree); | 607 | json_object_put(tree); |
587 | goto exit_cleanup; | 608 | goto exit_cleanup; |
588 | } | 609 | } |
@@ -593,7 +614,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
593 | container_descendants(&root_container, C_VIEW, ipc_get_marks_callback, | 614 | container_descendants(&root_container, C_VIEW, ipc_get_marks_callback, |
594 | marks); | 615 | marks); |
595 | const char *json_string = json_object_to_json_string(marks); | 616 | const char *json_string = json_object_to_json_string(marks); |
596 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 617 | client_valid = |
618 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
597 | json_object_put(marks); | 619 | json_object_put(marks); |
598 | goto exit_cleanup; | 620 | goto exit_cleanup; |
599 | } | 621 | } |
@@ -602,7 +624,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
602 | { | 624 | { |
603 | json_object *version = ipc_json_get_version(); | 625 | json_object *version = ipc_json_get_version(); |
604 | const char *json_string = json_object_to_json_string(version); | 626 | const char *json_string = json_object_to_json_string(version); |
605 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 627 | client_valid = |
628 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
606 | json_object_put(version); // free | 629 | json_object_put(version); // free |
607 | goto exit_cleanup; | 630 | goto exit_cleanup; |
608 | } | 631 | } |
@@ -617,7 +640,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
617 | json_object_array_add(bars, json_object_new_string(bar->id)); | 640 | json_object_array_add(bars, json_object_new_string(bar->id)); |
618 | } | 641 | } |
619 | const char *json_string = json_object_to_json_string(bars); | 642 | const char *json_string = json_object_to_json_string(bars); |
620 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 643 | client_valid = |
644 | ipc_send_reply(client, json_string, | ||
645 | (uint32_t)strlen(json_string)); | ||
621 | json_object_put(bars); // free | 646 | json_object_put(bars); // free |
622 | } else { | 647 | } else { |
623 | // Send particular bar's details | 648 | // Send particular bar's details |
@@ -631,27 +656,54 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
631 | } | 656 | } |
632 | if (!bar) { | 657 | if (!bar) { |
633 | const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }"; | 658 | const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }"; |
634 | ipc_send_reply(client, error, (uint32_t)strlen(error)); | 659 | client_valid = |
660 | ipc_send_reply(client, error, (uint32_t)strlen(error)); | ||
635 | goto exit_cleanup; | 661 | goto exit_cleanup; |
636 | } | 662 | } |
637 | json_object *json = ipc_json_describe_bar_config(bar); | 663 | json_object *json = ipc_json_describe_bar_config(bar); |
638 | const char *json_string = json_object_to_json_string(json); | 664 | const char *json_string = json_object_to_json_string(json); |
639 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 665 | client_valid = |
666 | ipc_send_reply(client, json_string, | ||
667 | (uint32_t)strlen(json_string)); | ||
640 | json_object_put(json); // free | 668 | json_object_put(json); // free |
641 | } | 669 | } |
642 | goto exit_cleanup; | 670 | goto exit_cleanup; |
643 | } | 671 | } |
644 | 672 | ||
645 | default: | 673 | case IPC_GET_BINDING_MODES: |
646 | wlr_log(L_INFO, "Unknown IPC command type %i", client->current_command); | 674 | { |
675 | json_object *modes = json_object_new_array(); | ||
676 | for (int i = 0; i < config->modes->length; i++) { | ||
677 | struct sway_mode *mode = config->modes->items[i]; | ||
678 | json_object_array_add(modes, json_object_new_string(mode->name)); | ||
679 | } | ||
680 | const char *json_string = json_object_to_json_string(modes); | ||
681 | client_valid = | ||
682 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
683 | json_object_put(modes); // free | ||
647 | goto exit_cleanup; | 684 | goto exit_cleanup; |
648 | } | 685 | } |
649 | 686 | ||
650 | ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); | 687 | case IPC_GET_CONFIG: |
651 | wlr_log(L_DEBUG, "Denied IPC client access to %i", client->current_command); | 688 | { |
689 | json_object *json = json_object_new_object(); | ||
690 | json_object_object_add(json, "config", json_object_new_string(config->current_config)); | ||
691 | const char *json_string = json_object_to_json_string(json); | ||
692 | client_valid = | ||
693 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | ||
694 | json_object_put(json); // free | ||
695 | goto exit_cleanup; | ||
696 | } | ||
697 | |||
698 | default: | ||
699 | wlr_log(WLR_INFO, "Unknown IPC command type %i", client->current_command); | ||
700 | goto exit_cleanup; | ||
701 | } | ||
652 | 702 | ||
653 | exit_cleanup: | 703 | exit_cleanup: |
654 | client->payload_length = 0; | 704 | if (client_valid) { |
705 | client->payload_length = 0; | ||
706 | } | ||
655 | free(buf); | 707 | free(buf); |
656 | return; | 708 | return; |
657 | } | 709 | } |
@@ -672,14 +724,14 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay | |||
672 | } | 724 | } |
673 | 725 | ||
674 | if (client->write_buffer_size > 4e6) { // 4 MB | 726 | if (client->write_buffer_size > 4e6) { // 4 MB |
675 | wlr_log(L_ERROR, "Client write buffer too big, disconnecting client"); | 727 | wlr_log(WLR_ERROR, "Client write buffer too big, disconnecting client"); |
676 | ipc_client_disconnect(client); | 728 | ipc_client_disconnect(client); |
677 | return false; | 729 | return false; |
678 | } | 730 | } |
679 | 731 | ||
680 | char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); | 732 | char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); |
681 | if (!new_buffer) { | 733 | if (!new_buffer) { |
682 | wlr_log(L_ERROR, "Unable to reallocate ipc client write buffer"); | 734 | wlr_log(WLR_ERROR, "Unable to reallocate ipc client write buffer"); |
683 | ipc_client_disconnect(client); | 735 | ipc_client_disconnect(client); |
684 | return false; | 736 | return false; |
685 | } | 737 | } |
@@ -696,6 +748,6 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay | |||
696 | ipc_client_handle_writable, client); | 748 | ipc_client_handle_writable, client); |
697 | } | 749 | } |
698 | 750 | ||
699 | wlr_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); | 751 | wlr_log(WLR_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); |
700 | return true; | 752 | return true; |
701 | } | 753 | } |