summaryrefslogtreecommitdiffstats
path: root/sway/ipc-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/ipc-server.c')
-rw-r--r--sway/ipc-server.c108
1 files changed, 98 insertions, 10 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 5e1e93ce..4ce2b7eb 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -41,11 +41,15 @@ static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
41 41
42struct ipc_client { 42struct ipc_client {
43 struct wlc_event_source *event_source; 43 struct wlc_event_source *event_source;
44 struct wlc_event_source *writable_event_source;
44 int fd; 45 int fd;
45 uint32_t payload_length; 46 uint32_t payload_length;
46 uint32_t security_policy; 47 uint32_t security_policy;
47 enum ipc_command_type current_command; 48 enum ipc_command_type current_command;
48 enum ipc_command_type subscribed_events; 49 enum ipc_command_type subscribed_events;
50 size_t write_buffer_len;
51 size_t write_buffer_size;
52 char *write_buffer;
49}; 53};
50 54
51static list_t *ipc_get_pixel_requests = NULL; 55static list_t *ipc_get_pixel_requests = NULL;
@@ -72,6 +76,7 @@ struct get_clipboard_request {
72struct sockaddr_un *ipc_user_sockaddr(void); 76struct sockaddr_un *ipc_user_sockaddr(void);
73int ipc_handle_connection(int fd, uint32_t mask, void *data); 77int ipc_handle_connection(int fd, uint32_t mask, void *data);
74int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); 78int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
79int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
75void ipc_client_disconnect(struct ipc_client *client); 80void ipc_client_disconnect(struct ipc_client *client);
76void ipc_client_handle_command(struct ipc_client *client); 81void ipc_client_handle_command(struct ipc_client *client);
77bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); 82bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
@@ -182,6 +187,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
182 close(client_fd); 187 close(client_fd);
183 return 0; 188 return 0;
184 } 189 }
190 if ((flags = fcntl(client_fd, F_GETFL)) == -1
191 || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) {
192 sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
193 close(client_fd);
194 return 0;
195 }
185 196
186 struct ipc_client* client = malloc(sizeof(struct ipc_client)); 197 struct ipc_client* client = malloc(sizeof(struct ipc_client));
187 if (!client) { 198 if (!client) {
@@ -193,10 +204,22 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
193 client->fd = client_fd; 204 client->fd = client_fd;
194 client->subscribed_events = 0; 205 client->subscribed_events = 0;
195 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); 206 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
207 client->writable_event_source = NULL;
208
209 client->write_buffer_size = 128;
210 client->write_buffer_len = 0;
211 client->write_buffer = malloc(client->write_buffer_size);
212 if (!client->write_buffer) {
213 sway_log(L_ERROR, "Unable to allocate ipc client write buffer");
214 close(client_fd);
215 return 0;
216 }
196 217
197 pid_t pid = get_client_pid(client->fd); 218 pid_t pid = get_client_pid(client->fd);
198 client->security_policy = get_ipc_policy_mask(pid); 219 client->security_policy = get_ipc_policy_mask(pid);
199 220
221 sway_log(L_DEBUG, "New client: fd %d, pid %d", client_fd, pid);
222
200 list_add(ipc_client_list, client); 223 list_add(ipc_client_list, client);
201 224
202 return 0; 225 return 0;
@@ -219,6 +242,8 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
219 return 0; 242 return 0;
220 } 243 }
221 244
245 sway_log(L_DEBUG, "Client %d readable", client->fd);
246
222 int read_available; 247 int read_available;
223 if (ioctl(client_fd, FIONREAD, &read_available) == -1) { 248 if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
224 sway_log_errno(L_INFO, "Unable to read IPC socket buffer size"); 249 sway_log_errno(L_INFO, "Unable to read IPC socket buffer size");
@@ -240,6 +265,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
240 265
241 uint8_t buf[ipc_header_size]; 266 uint8_t buf[ipc_header_size];
242 uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic)); 267 uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic));
268 // Should be fully available, because read_available >= ipc_header_size
243 ssize_t received = recv(client_fd, buf, ipc_header_size, 0); 269 ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
244 if (received == -1) { 270 if (received == -1) {
245 sway_log_errno(L_INFO, "Unable to receive header from IPC client"); 271 sway_log_errno(L_INFO, "Unable to receive header from IPC client");
@@ -263,6 +289,48 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
263 return 0; 289 return 0;
264} 290}
265 291
292int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
293 struct ipc_client *client = data;
294
295 if (mask & WLC_EVENT_ERROR) {
296 sway_log(L_ERROR, "IPC Client socket error, removing client");
297 ipc_client_disconnect(client);
298 return 0;
299 }
300
301 if (mask & WLC_EVENT_HANGUP) {
302 sway_log(L_DEBUG, "Client %d hung up", client->fd);
303 ipc_client_disconnect(client);
304 return 0;
305 }
306
307 if (client->write_buffer_len <= 0) {
308 return 0;
309 }
310
311 sway_log(L_DEBUG, "Client %d writable", client->fd);
312
313 ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
314
315 if (written == -1 && errno == EAGAIN) {
316 return 0;
317 } else if (written == -1) {
318 sway_log_errno(L_INFO, "Unable to send data from queue to IPC client");
319 ipc_client_disconnect(client);
320 return 0;
321 }
322
323 memmove(client->write_buffer, client->write_buffer + written, client->write_buffer_len - written);
324 client->write_buffer_len -= written;
325
326 if (client->write_buffer_len == 0 && client->writable_event_source) {
327 wlc_event_source_remove(client->writable_event_source);
328 client->writable_event_source = NULL;
329 }
330
331 return 0;
332}
333
266void ipc_client_disconnect(struct ipc_client *client) { 334void ipc_client_disconnect(struct ipc_client *client) {
267 if (!sway_assert(client != NULL, "client != NULL")) { 335 if (!sway_assert(client != NULL, "client != NULL")) {
268 return; 336 return;
@@ -274,9 +342,13 @@ void ipc_client_disconnect(struct ipc_client *client) {
274 342
275 sway_log(L_INFO, "IPC Client %d disconnected", client->fd); 343 sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
276 wlc_event_source_remove(client->event_source); 344 wlc_event_source_remove(client->event_source);
345 if (client->writable_event_source) {
346 wlc_event_source_remove(client->writable_event_source);
347 }
277 int i = 0; 348 int i = 0;
278 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; 349 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++;
279 list_del(ipc_client_list, i); 350 list_del(ipc_client_list, i);
351 free(client->write_buffer);
280 close(client->fd); 352 close(client->fd);
281 free(client); 353 free(client);
282} 354}
@@ -608,6 +680,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
608 return; 680 return;
609 } 681 }
610 if (client->payload_length > 0) { 682 if (client->payload_length > 0) {
683 // Payload should be fully available
611 ssize_t received = recv(client->fd, buf, client->payload_length, 0); 684 ssize_t received = recv(client->fd, buf, client->payload_length, 0);
612 if (received == -1) 685 if (received == -1)
613 { 686 {
@@ -874,17 +947,36 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
874 data32[0] = payload_length; 947 data32[0] = payload_length;
875 data32[1] = client->current_command; 948 data32[1] = client->current_command;
876 949
877 if (write(client->fd, data, ipc_header_size) == -1) { 950 while (client->write_buffer_len + ipc_header_size + payload_length >=
878 sway_log_errno(L_INFO, "Unable to send header to IPC client"); 951 client->write_buffer_size) {
952 client->write_buffer_size *= 2;
953 }
954
955 // TODO: reduce the limit back to 4 MB when screenshooter is implemented
956 if (client->write_buffer_size > (1 << 28)) { // 256 MB
957 sway_log(L_ERROR, "Client write buffer too big, disconnecting client");
958 ipc_client_disconnect(client);
879 return false; 959 return false;
880 } 960 }
881 961
882 if (write(client->fd, payload, payload_length) == -1) { 962 char *new_buffer = realloc(client->write_buffer, client->write_buffer_size);
883 sway_log_errno(L_INFO, "Unable to send payload to IPC client"); 963 if (!new_buffer) {
964 sway_log(L_ERROR, "Unable to reallocate ipc client write buffer");
965 ipc_client_disconnect(client);
884 return false; 966 return false;
885 } 967 }
968 client->write_buffer = new_buffer;
969
970 memcpy(client->write_buffer + client->write_buffer_len, data, ipc_header_size);
971 client->write_buffer_len += ipc_header_size;
972 memcpy(client->write_buffer + client->write_buffer_len, payload, payload_length);
973 client->write_buffer_len += payload_length;
974
975 if (!client->writable_event_source) {
976 client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client);
977 }
886 978
887 sway_log(L_DEBUG, "Send IPC reply: %s", payload); 979 sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
888 980
889 return true; 981 return true;
890} 982}
@@ -984,11 +1076,7 @@ void ipc_event_window(swayc_t *window, const char *change) {
984 sway_log(L_DEBUG, "Sending window::%s event", change); 1076 sway_log(L_DEBUG, "Sending window::%s event", change);
985 json_object *obj = json_object_new_object(); 1077 json_object *obj = json_object_new_object();
986 json_object_object_add(obj, "change", json_object_new_string(change)); 1078 json_object_object_add(obj, "change", json_object_new_string(change));
987 if (strcmp(change, "close") == 0 || !window) { 1079 json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
988 json_object_object_add(obj, "container", NULL);
989 } else {
990 json_object_object_add(obj, "container", ipc_json_describe_container(window));
991 }
992 1080
993 const char *json_string = json_object_to_json_string(obj); 1081 const char *json_string = json_object_to_json_string(obj);
994 ipc_send_event(json_string, IPC_EVENT_WINDOW); 1082 ipc_send_event(json_string, IPC_EVENT_WINDOW);