Add timeout; Fix receive loop & style issues

master
nyorain 8 years ago
parent f0463dab32
commit 727215c907

@ -59,9 +59,13 @@ struct get_pixels_request {
struct get_clipboard_request { struct get_clipboard_request {
struct ipc_client *client; struct ipc_client *client;
json_object *json; json_object *json;
struct wlc_event_source *event_source; struct wlc_event_source *fd_event_source;
struct wlc_event_source *timer_event_source;
char *type; char *type;
unsigned int *pending; unsigned int *pending;
char *buf;
size_t buf_size;
size_t buf_position;
}; };
struct sockaddr_un *ipc_user_sockaddr(void); struct sockaddr_un *ipc_user_sockaddr(void);
@ -339,54 +343,69 @@ static bool is_text_target(const char *target) {
|| strcmp(target, "COMPOUND_TEXT") == 0); || strcmp(target, "COMPOUND_TEXT") == 0);
} }
static void release_clipboard_request(struct get_clipboard_request *req) {
if (--(*req->pending) == 0) {
const char *str = json_object_to_json_string(req->json);
ipc_send_reply(req->client, str, (uint32_t)strlen(str));
json_object_put(req->json);
}
free(req->type);
free(req->buf);
wlc_event_source_remove(req->fd_event_source);
wlc_event_source_remove(req->timer_event_source);
free(req);
}
static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) { static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
assert(data); assert(data);
struct get_clipboard_request *req = (struct get_clipboard_request *)data; struct get_clipboard_request *req = (struct get_clipboard_request *)data;
if (mask & WLC_EVENT_ERROR) { if (mask & WLC_EVENT_ERROR) {
sway_log(L_ERROR, "Selection data fd error"); sway_log(L_ERROR, "Selection data fd error");
goto cleanup; goto release;
} }
if (mask & WLC_EVENT_READABLE) { if (mask & WLC_EVENT_READABLE) {
static const int max_size = 8192 * 1000; static const unsigned int max_size = 8192 * 1024;
int len = 512; int amt = 0;
int i = 0;
char *buf = malloc(len); do {
int size = req->buf_size - req->buf_position;
int amt = read(fd, req->buf + req->buf_position, size - 1);
if (amt < 0) {
if (errno == EAGAIN) {
return 0;
}
// read data as long as there is data avilable sway_log_errno(L_INFO, "Failed to read from clipboard data fd");
// grow the buffer step_size in every iteration goto release;
for(;;) { }
int amt = read(fd, buf + i, len - i - 1);
if (amt <= 0)
break;
i += amt; req->buf_position += amt;
if (i >= len - 1) { if (req->buf_position >= req->buf_size - 1) {
if (len >= max_size) { if (req->buf_size >= max_size) {
sway_log(L_ERROR, "selection data too large"); sway_log(L_ERROR, "get_clipbard: selection data too large");
free(buf); goto release;
goto cleanup;
} }
char *next = realloc(buf, (len *= 2)); char *next = realloc(req->buf, req->buf_size *= 2);
if (!next) { if (!next) {
sway_log_errno(L_ERROR, "relloc failed"); sway_log_errno(L_ERROR, "get_clipboard: realloc data buffer failed");
free(buf); goto release;
goto cleanup;
} }
buf = next; req->buf = next;
}
} }
} while(amt != 0);
buf[i] = '\0'; req->buf[req->buf_position] = '\0';
if (is_text_target(req->type)) { if (is_text_target(req->type)) {
json_object_object_add(req->json, req->type, json_object_object_add(req->json, req->type,
json_object_new_string(buf)); json_object_new_string(req->buf));
} else { } else {
size_t outlen; size_t outlen;
char *b64 = b64_encode(buf, i, &outlen); char *b64 = b64_encode(req->buf, req->buf_position, &outlen);
char *type = malloc(strlen(req->type) + 8); char *type = malloc(strlen(req->type) + 8);
strcat(type, ";base64"); strcat(type, ";base64");
json_object_object_add(req->json, type, json_object_object_add(req->json, type,
@ -394,22 +413,19 @@ static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
free(type); free(type);
free(b64); free(b64);
} }
free(buf);
} }
cleanup: release:
close(fd); release_clipboard_request(req);
return 0;
}
if (--(*req->pending) == 0) { static int ipc_selection_timer_cb(void *data) {
const char *str = json_object_to_json_string(req->json); assert(data);
ipc_send_reply(req->client, str, (uint32_t)strlen(str)); struct get_clipboard_request *req = (struct get_clipboard_request *)data;
json_object_put(req->json);
}
free(req->type); sway_log(L_INFO, "get_clipbard: timeout for type %s", req->type);
wlc_event_source_remove(req->event_source); release_clipboard_request(req);
free(req);
return 0; return 0;
} }
@ -471,18 +487,21 @@ void ipc_get_clipboard(struct ipc_client *client, char *buf) {
const char *pattern = requested->items[l]; const char *pattern = requested->items[l];
bool found = false; bool found = false;
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
if (mime_type_matches(types[i], pattern)) { if (!mime_type_matches(types[i], pattern)) {
continue;
}
found = true; found = true;
struct get_clipboard_request *req = malloc(sizeof(*req)); struct get_clipboard_request *req = malloc(sizeof(*req));
if (!req) { if (!req) {
sway_log(L_ERROR, "Cannot allocate get_clipboard_request"); sway_log(L_ERROR, "get_clipboard: request malloc failed");
goto data_error; goto data_error;
} }
int pipes[2]; int pipes[2];
if (pipe(pipes) == -1) { if (pipe(pipes) == -1) {
sway_log_errno(L_ERROR, "pipe call failed"); sway_log_errno(L_ERROR, "get_clipboard: pipe call failed");
free(req); free(req);
goto data_error; goto data_error;
} }
@ -494,7 +513,16 @@ void ipc_get_clipboard(struct ipc_client *client, char *buf) {
close(pipes[0]); close(pipes[0]);
close(pipes[1]); close(pipes[1]);
free(req); free(req);
sway_log(L_ERROR, "wlc_get_selection_data failed"); sway_log(L_ERROR, "get_clipboard: failed to retrieve "
"selection data");
goto data_error;
}
if (!(req->buf = malloc(512))) {
close(pipes[0]);
close(pipes[1]);
free(req);
sway_log_errno(L_ERROR, "get_clipboard: buf malloc failed");
goto data_error; goto data_error;
} }
@ -504,10 +532,15 @@ void ipc_get_clipboard(struct ipc_client *client, char *buf) {
req->type = strdup(types[i]); req->type = strdup(types[i]);
req->json = json; req->json = json;
req->pending = pending; req->pending = pending;
req->event_source = wlc_event_loop_add_fd(pipes[0], req->buf_position = 0;
req->buf_size = 512;
req->timer_event_source = wlc_event_loop_add_timer(ipc_selection_timer_cb, req);
req->fd_event_source = wlc_event_loop_add_fd(pipes[0],
WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP, WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
&ipc_selection_data_cb, req); &ipc_selection_data_cb, req);
wlc_event_source_timer_update(req->timer_event_source, 1000);
// NOTE: remove this goto to enable retrieving multiple // NOTE: remove this goto to enable retrieving multiple
// targets at once. The whole implementation is already // targets at once. The whole implementation is already
// made for it. The only reason it was disabled // made for it. The only reason it was disabled
@ -518,7 +551,6 @@ void ipc_get_clipboard(struct ipc_client *client, char *buf) {
// return empty data) // return empty data)
goto cleanup; goto cleanup;
} }
}
if (!found) { if (!found) {
sway_log(L_INFO, "Invalid clipboard type %s requested", pattern); sway_log(L_INFO, "Invalid clipboard type %s requested", pattern);

Loading…
Cancel
Save