[ipc] remove complex managing of message types. guile will do better easily

This commit is contained in:
nixo 2020-05-10 01:33:55 +02:00
parent 176a56df0a
commit 0270a9c565
8 changed files with 22 additions and 668 deletions

View File

@ -50,101 +50,6 @@ void errorlog(char *fmt, ...) {
static char *last_key = NULL; static char *last_key = NULL;
typedef struct reply_t {
bool success;
char *error;
char *input;
char *errorposition;
} reply_t;
static int exit_code = 0;
static reply_t last_reply;
static int reply_boolean_cb(void *params, int val) {
if (strcmp(last_key, "success") == 0)
last_reply.success = val;
return 1;
}
static int reply_string_cb(void *params, const unsigned char *val, size_t len) {
char *str = sstrndup((const char *)val, len);
if (strcmp(last_key, "error") == 0)
last_reply.error = str;
else if (strcmp(last_key, "input") == 0)
last_reply.input = str;
else if (strcmp(last_key, "errorposition") == 0)
last_reply.errorposition = str;
else
free(str);
return 1;
}
static int reply_start_map_cb(void *params) {
return 1;
}
static int reply_end_map_cb(void *params) {
if (!last_reply.success) {
if (last_reply.input) {
fprintf(stderr, "ERROR: Your command: %s\n", last_reply.input);
fprintf(stderr, "ERROR: %s\n", last_reply.errorposition);
}
fprintf(stderr, "ERROR: %s\n", last_reply.error);
exit_code = 2;
}
return 1;
}
static int reply_map_key_cb(void *params, const unsigned char *keyVal, size_t keyLen) {
free(last_key);
last_key = sstrndup((const char *)keyVal, keyLen);
return 1;
}
static yajl_callbacks reply_callbacks = {
.yajl_boolean = reply_boolean_cb,
.yajl_string = reply_string_cb,
.yajl_start_map = reply_start_map_cb,
.yajl_map_key = reply_map_key_cb,
.yajl_end_map = reply_end_map_cb,
};
/*******************************************************************************
* Config reply callbacks
*******************************************************************************/
static char *config_last_key = NULL;
static int config_string_cb(void *params, const unsigned char *val, size_t len) {
char *str = sstrndup((const char *)val, len);
if (strcmp(config_last_key, "config") == 0) {
fprintf(stdout, "%s", str);
}
free(str);
return 1;
}
static int config_start_map_cb(void *params) {
return 1;
}
static int config_end_map_cb(void *params) {
return 1;
}
static int config_map_key_cb(void *params, const unsigned char *keyVal, size_t keyLen) {
config_last_key = sstrndup((const char *)keyVal, keyLen);
return 1;
}
static yajl_callbacks config_callbacks = {
.yajl_string = config_string_cb,
.yajl_start_map = config_start_map_cb,
.yajl_map_key = config_map_key_cb,
.yajl_end_map = config_end_map_cb,
};
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
#if defined(__OpenBSD__) #if defined(__OpenBSD__)
if (pledge("stdio rpath unix", NULL) == -1) if (pledge("stdio rpath unix", NULL) == -1)
@ -152,17 +57,11 @@ int main(int argc, char *argv[]) {
#endif #endif
char *socket_path = NULL; char *socket_path = NULL;
int o, option_index = 0; int o, option_index = 0;
uint32_t message_type = I3_IPC_MESSAGE_TYPE_RUN_COMMAND;
char *payload = NULL; char *payload = NULL;
bool quiet = false;
bool monitor = false;
static struct option long_options[] = { static struct option long_options[] = {
{"socket", required_argument, 0, 's'}, {"socket", required_argument, 0, 's'},
{"type", required_argument, 0, 't'},
{"version", no_argument, 0, 'v'}, {"version", no_argument, 0, 'v'},
{"quiet", no_argument, 0, 'q'},
{"monitor", no_argument, 0, 'm'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{0, 0, 0, 0}}; {0, 0, 0, 0}};
@ -172,57 +71,18 @@ int main(int argc, char *argv[]) {
if (o == 's') { if (o == 's') {
free(socket_path); free(socket_path);
socket_path = sstrdup(optarg); socket_path = sstrdup(optarg);
} else if (o == 't') {
if (strcasecmp(optarg, "command") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_RUN_COMMAND;
} else if (strcasecmp(optarg, "run_command") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_RUN_COMMAND;
} else if (strcasecmp(optarg, "get_workspaces") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_WORKSPACES;
} else if (strcasecmp(optarg, "get_outputs") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS;
} else if (strcasecmp(optarg, "get_tree") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_TREE;
} else if (strcasecmp(optarg, "get_marks") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS;
} else if (strcasecmp(optarg, "get_bar_config") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG;
} else if (strcasecmp(optarg, "get_binding_modes") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_BINDING_MODES;
} else if (strcasecmp(optarg, "get_version") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_VERSION;
} else if (strcasecmp(optarg, "get_config") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_GET_CONFIG;
} else if (strcasecmp(optarg, "send_tick") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_SEND_TICK;
} else if (strcasecmp(optarg, "subscribe") == 0) {
message_type = I3_IPC_MESSAGE_TYPE_SUBSCRIBE;
} else {
printf("Unknown message type\n");
printf("Known types: run_command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_binding_modes, get_version, get_config, send_tick, subscribe\n");
exit(EXIT_FAILURE);
}
} else if (o == 'q') {
quiet = true;
} else if (o == 'm') {
monitor = true;
} else if (o == 'v') { } else if (o == 'v') {
printf("i3-msg " I3_VERSION "\n"); puts("i3-msg " I3_VERSION "\n");
return 0; return 0;
} else if (o == 'h') { } else if (o == 'h') {
printf("i3-msg " I3_VERSION "\n"); puts("i3-msg " I3_VERSION "\n");
printf("i3-msg [-s <socket>] [-t <type>] [-m] <message>\n"); puts("i3-msg [-s <socket>] [-m] <message>\n");
return 0; return 0;
} else if (o == '?') { } else if (o == '?') {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
if (monitor && message_type != I3_IPC_MESSAGE_TYPE_SUBSCRIBE) {
fprintf(stderr, "The monitor option -m is used with -t SUBSCRIBE exclusively.\n");
exit(EXIT_FAILURE);
}
/* Use all arguments, separated by whitespace, as payload. /* Use all arguments, separated by whitespace, as payload.
* This way, you dont have to do i3-msg 'mark foo', you can use * This way, you dont have to do i3-msg 'mark foo', you can use
* i3-msg mark foo */ * i3-msg mark foo */
@ -242,78 +102,18 @@ int main(int argc, char *argv[]) {
payload = sstrdup(""); payload = sstrdup("");
int sockfd = ipc_connect(socket_path); int sockfd = ipc_connect(socket_path);
if (ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t *)payload) == -1) if (ipc_send_message(sockfd, strlen(payload), (uint8_t *)payload) == -1)
err(EXIT_FAILURE, "IPC: write()"); err(EXIT_FAILURE, "IPC: write()");
free(payload); free(payload);
uint32_t reply_length; uint32_t reply_length;
uint32_t reply_type;
uint8_t *reply; uint8_t *reply;
int ret; int ret;
if ((ret = ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) { if ((ret = ipc_recv_message(sockfd, &reply_length, &reply)) != 0) {
if (ret == -1) if (ret == -1)
err(EXIT_FAILURE, "IPC: read()"); err(EXIT_FAILURE, "IPC: read()");
exit(1); exit(1);
} }
if (reply_type != message_type) puts(reply);
errx(EXIT_FAILURE, "IPC: Received reply of type %d but expected %d", reply_type, message_type); return 0;
/* For the reply of commands, have a look if that command was successful.
* If not, nicely format the error message. */
if (reply_type == I3_IPC_REPLY_TYPE_COMMAND) {
yajl_handle handle = yajl_alloc(&reply_callbacks, NULL, NULL);
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
yajl_free(handle);
switch (state) {
case yajl_status_ok:
break;
case yajl_status_client_canceled:
case yajl_status_error:
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
}
if (!quiet) {
printf("%.*s\n", reply_length, reply);
}
} else if (reply_type == I3_IPC_REPLY_TYPE_CONFIG) {
yajl_handle handle = yajl_alloc(&config_callbacks, NULL, NULL);
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
yajl_free(handle);
switch (state) {
case yajl_status_ok:
break;
case yajl_status_client_canceled:
case yajl_status_error:
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
}
} else if (reply_type == I3_IPC_REPLY_TYPE_SUBSCRIBE) {
do {
free(reply);
if ((ret = ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) {
if (ret == -1)
err(EXIT_FAILURE, "IPC: read()");
exit(1);
}
if (!(reply_type & I3_IPC_EVENT_MASK)) {
errx(EXIT_FAILURE, "IPC: Received reply of type %d but expected an event", reply_type);
}
if (!quiet) {
fprintf(stdout, "%.*s\n", reply_length, reply);
fflush(stdout);
}
} while (monitor);
} else {
if (!quiet) {
printf("%.*s\n", reply_length, reply);
}
}
free(reply);
close(sockfd);
return exit_code;
} }

View File

@ -59,8 +59,7 @@ typedef void (*handler_t)(ipc_client *, uint8_t *, int, uint32_t, uint32_t);
/* Macro to declare a callback */ /* Macro to declare a callback */
#define IPC_HANDLER(name) \ #define IPC_HANDLER(name) \
static void handle_##name(ipc_client *client, uint8_t *message, \ static void handle_##name(ipc_client *client, uint8_t *message, \
int size, uint32_t message_size, \ int size, uint32_t message_size)
uint32_t message_type)
/** /**
* Handler for activity on the listening socket, meaning that a new client * Handler for activity on the listening socket, meaning that a new client

View File

@ -301,8 +301,7 @@ int ipc_connect(const char *socket_path);
* Returns 0 on success. * Returns 0 on success.
* *
*/ */
int ipc_send_message(int sockfd, const uint32_t message_size, int ipc_send_message(int sockfd, const uint32_t message_size, const uint8_t *payload);
const uint32_t message_type, const uint8_t *payload);
/** /**
* Reads a message from the given socket file descriptor and stores its length * Reads a message from the given socket file descriptor and stores its length
@ -315,8 +314,7 @@ int ipc_send_message(int sockfd, const uint32_t message_size,
* Returns 0 on success. * Returns 0 on success.
* *
*/ */
int ipc_recv_message(int sockfd, uint32_t *message_type, int ipc_recv_message(int sockfd, uint32_t *reply_length, uint8_t **reply);
uint32_t *reply_length, uint8_t **reply);
/** /**
* Generates a configure_notify event and sends it to the given window * Generates a configure_notify event and sends it to the given window

View File

@ -26,8 +26,7 @@
* Returns 0 on success. * Returns 0 on success.
* *
*/ */
int ipc_recv_message(int sockfd, uint32_t *message_type, int ipc_recv_message(int sockfd, uint32_t *reply_length, uint8_t **reply) {
uint32_t *reply_length, uint8_t **reply) {
/* Read the message header first */ /* Read the message header first */
const uint32_t to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t); const uint32_t to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t);
char msg[to_read]; char msg[to_read];
@ -60,8 +59,6 @@ int ipc_recv_message(int sockfd, uint32_t *message_type,
walk += strlen(I3_IPC_MAGIC); walk += strlen(I3_IPC_MAGIC);
memcpy(reply_length, walk, sizeof(uint32_t)); memcpy(reply_length, walk, sizeof(uint32_t));
walk += sizeof(uint32_t); walk += sizeof(uint32_t);
if (message_type != NULL)
memcpy(message_type, walk, sizeof(uint32_t));
*reply = smalloc(*reply_length); *reply = smalloc(*reply_length);

View File

@ -18,13 +18,11 @@
* Returns 0 on success. * Returns 0 on success.
* *
*/ */
int ipc_send_message(int sockfd, const uint32_t message_size, int ipc_send_message(int sockfd, const uint32_t message_size, const uint8_t *payload) {
const uint32_t message_type, const uint8_t *payload) {
const i3_ipc_header_t header = { const i3_ipc_header_t header = {
/* We dont use I3_IPC_MAGIC because its a 0-terminated C string. */ /* We dont use I3_IPC_MAGIC because its a 0-terminated C string. */
.magic = {'i', '3', '-', 'i', 'p', 'c'}, .magic = {'i', '3', '-', 'i', 'p', 'c'},
.size = message_size, .size = message_size};
.type = message_type};
if (writeall(sockfd, ((void *)&header), sizeof(i3_ipc_header_t)) == -1) if (writeall(sockfd, ((void *)&header), sizeof(i3_ipc_header_t)) == -1)
return -1; return -1;

View File

@ -71,15 +71,16 @@ void display_running_version(void) {
fflush(stdout); fflush(stdout);
int sockfd = ipc_connect(NULL); int sockfd = ipc_connect(NULL);
if (ipc_send_message(sockfd, 0, I3_IPC_MESSAGE_TYPE_GET_VERSION, /* if (ipc_send_message(sockfd, 0, I3_IPC_MESSAGE_TYPE_GET_VERSION, */
(uint8_t *)"") == -1) /* (uint8_t *)"") == -1) */
err(EXIT_FAILURE, "IPC: write()"); /* err(EXIT_FAILURE, "IPC: write()"); */
err(EXIT_FAILURE, "GUILE: NOT IMPLEMENTED");
uint32_t reply_length; uint32_t reply_length;
uint32_t reply_type; uint32_t reply_type;
uint8_t *reply; uint8_t *reply;
int ret; int ret;
if ((ret = ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) { if ((ret = ipc_recv_message(sockfd, &reply_length, &reply)) != 0) {
if (ret == -1) if (ret == -1)
err(EXIT_FAILURE, "IPC: read()"); err(EXIT_FAILURE, "IPC: read()");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

442
src/ipc.c
View File

@ -870,285 +870,6 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
#undef YSTR_IF_SET #undef YSTR_IF_SET
} }
IPC_HANDLER(tree) {
setlocale(LC_NUMERIC, "C");
yajl_gen gen = ygenalloc();
dump_node(gen, croot, false);
setlocale(LC_NUMERIC, "");
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_TREE, payload);
y(free);
}
/*
* Formats the reply message for a GET_WORKSPACES request and sends it to the
* client
*
*/
IPC_HANDLER(get_workspaces) {
yajl_gen gen = ygenalloc();
y(array_open);
Con *focused_ws = con_get_workspace(focused);
Con *output;
TAILQ_FOREACH (output, &(croot->nodes_head), nodes) {
if (con_is_internal(output))
continue;
Con *ws;
TAILQ_FOREACH (ws, &(output_get_content(output)->nodes_head), nodes) {
assert(ws->type == CT_WORKSPACE);
y(map_open);
ystr("id");
y(integer, (uintptr_t)ws);
ystr("num");
y(integer, ws->num);
ystr("name");
ystr(ws->name);
ystr("visible");
y(bool, workspace_is_visible(ws));
ystr("focused");
y(bool, ws == focused_ws);
ystr("rect");
y(map_open);
ystr("x");
y(integer, ws->rect.x);
ystr("y");
y(integer, ws->rect.y);
ystr("width");
y(integer, ws->rect.width);
ystr("height");
y(integer, ws->rect.height);
y(map_close);
ystr("output");
ystr(output->name);
ystr("urgent");
y(bool, ws->urgent);
y(map_close);
}
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_WORKSPACES, payload);
y(free);
}
/*
* Formats the reply message for a GET_OUTPUTS request and sends it to the
* client
*
*/
IPC_HANDLER(get_outputs) {
yajl_gen gen = ygenalloc();
y(array_open);
Output *output;
TAILQ_FOREACH (output, &outputs, outputs) {
y(map_open);
ystr("name");
ystr(output_primary_name(output));
ystr("active");
y(bool, output->active);
ystr("primary");
y(bool, output->primary);
ystr("rect");
y(map_open);
ystr("x");
y(integer, output->rect.x);
ystr("y");
y(integer, output->rect.y);
ystr("width");
y(integer, output->rect.width);
ystr("height");
y(integer, output->rect.height);
y(map_close);
ystr("current_workspace");
Con *ws = NULL;
if (output->con && (ws = con_get_fullscreen_con(output->con, CF_OUTPUT)))
ystr(ws->name);
else
y(null);
y(map_close);
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_OUTPUTS, payload);
y(free);
}
/*
* Formats the reply message for a GET_MARKS request and sends it to the
* client
*
*/
IPC_HANDLER(get_marks) {
yajl_gen gen = ygenalloc();
y(array_open);
Con *con;
TAILQ_FOREACH (con, &all_cons, all_cons) {
mark_t *mark;
TAILQ_FOREACH (mark, &(con->marks_head), marks) {
ystr(mark->name);
}
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_MARKS, payload);
y(free);
}
/*
* Returns the version of i3
*
*/
IPC_HANDLER(get_version) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("major");
y(integer, MAJOR_VERSION);
ystr("minor");
y(integer, MINOR_VERSION);
ystr("patch");
y(integer, PATCH_VERSION);
ystr("human_readable");
ystr(i3_version);
ystr("loaded_config_file_name");
ystr(current_configpath);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_VERSION, payload);
y(free);
}
/*
* Formats the reply message for a GET_BAR_CONFIG request and sends it to the
* client.
*
*/
IPC_HANDLER(get_bar_config) {
yajl_gen gen = ygenalloc();
/* If no ID was passed, we return a JSON array with all IDs */
if (message_size == 0) {
y(array_open);
Barconfig *current;
TAILQ_FOREACH (current, &barconfigs, configs) {
ystr(current->id);
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
y(free);
return;
}
/* To get a properly terminated buffer, we copy
* message_size bytes out of the buffer */
char *bar_id = NULL;
sasprintf(&bar_id, "%.*s", message_size, message);
LOG("IPC: looking for config for bar ID \"%s\"\n", bar_id);
Barconfig *current, *config = NULL;
TAILQ_FOREACH (current, &barconfigs, configs) {
if (strcmp(current->id, bar_id) != 0)
continue;
config = current;
break;
}
free(bar_id);
if (!config) {
/* If we did not find a config for the given ID, the reply will contain
* a null 'id' field. */
y(map_open);
ystr("id");
y(null);
y(map_close);
} else {
dump_bar_config(gen, config);
}
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BAR_CONFIG, payload);
y(free);
}
/*
* Returns a list of configured binding modes
*
*/
IPC_HANDLER(get_binding_modes) {
yajl_gen gen = ygenalloc();
y(array_open);
struct Mode *mode;
SLIST_FOREACH (mode, &modes, modes) {
ystr(mode->name);
}
y(array_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_BINDING_MODES, payload);
y(free);
}
/* /*
* Callback for the YAJL parser (will be called when a string is parsed). * Callback for the YAJL parser (will be called when a string is parsed).
* *
@ -1176,107 +897,6 @@ static int add_subscription(void *extra, const unsigned char *s,
return 1; return 1;
} }
/*
* Subscribes this connection to the event types which were given as a JSON
* serialized array in the payload field of the message.
*
*/
IPC_HANDLER(subscribe) {
yajl_handle p;
yajl_status stat;
/* Setup the JSON parser */
static yajl_callbacks callbacks = {
.yajl_string = add_subscription,
};
p = yalloc(&callbacks, (void *)client);
stat = yajl_parse(p, (const unsigned char *)message, message_size);
if (stat != yajl_status_ok) {
unsigned char *err;
err = yajl_get_error(p, true, (const unsigned char *)message,
message_size);
ELOG("YAJL parse error: %s\n", err);
yajl_free_error(p, err);
const char *reply = "{\"success\":false}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
yajl_free(p);
return;
}
yajl_free(p);
const char *reply = "{\"success\":true}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SUBSCRIBE, (const uint8_t *)reply);
if (client->first_tick_sent) {
return;
}
bool is_tick = false;
for (int i = 0; i < client->num_events; i++) {
if (strcmp(client->events[i], "tick") == 0) {
is_tick = true;
break;
}
}
if (!is_tick) {
return;
}
client->first_tick_sent = true;
const char *payload = "{\"first\":true,\"payload\":\"\"}";
ipc_send_client_message(client, strlen(payload), I3_IPC_EVENT_TICK, (const uint8_t *)payload);
}
/*
* Returns the raw last loaded i3 configuration file contents.
*/
IPC_HANDLER(get_config) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("config");
ystr(current_config);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_client_message(client, length, I3_IPC_REPLY_TYPE_CONFIG, payload);
y(free);
}
/*
* Sends the tick event from the message payload to subscribers. Establishes a
* synchronization point in event-related tests.
*/
IPC_HANDLER(send_tick) {
yajl_gen gen = ygenalloc();
y(map_open);
ystr("first");
y(bool, false);
ystr("payload");
yajl_gen_string(gen, (unsigned char *)message, message_size);
y(map_close);
const unsigned char *payload;
ylength length;
y(get_buf, &payload, &length);
ipc_send_event("tick", I3_IPC_EVENT_TICK, (const char *)payload);
y(free);
const char *reply = "{\"success\":true}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_TICK, (const uint8_t *)reply);
DLOG("Sent tick event\n");
}
struct sync_state { struct sync_state {
char *last_key; char *last_key;
@ -1302,58 +922,6 @@ static int _sync_json_int(void *extra, long long val) {
return 1; return 1;
} }
IPC_HANDLER(sync) {
yajl_handle p;
yajl_status stat;
/* Setup the JSON parser */
static yajl_callbacks callbacks = {
.yajl_map_key = _sync_json_key,
.yajl_integer = _sync_json_int,
};
struct sync_state state;
memset(&state, '\0', sizeof(struct sync_state));
p = yalloc(&callbacks, (void *)&state);
stat = yajl_parse(p, (const unsigned char *)message, message_size);
FREE(state.last_key);
if (stat != yajl_status_ok) {
unsigned char *err;
err = yajl_get_error(p, true, (const unsigned char *)message,
message_size);
ELOG("YAJL parse error: %s\n", err);
yajl_free_error(p, err);
const char *reply = "{\"success\":false}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
yajl_free(p);
return;
}
yajl_free(p);
DLOG("received IPC sync request (rnd = %d, window = 0x%08x)\n", state.rnd, state.window);
sync_respond(state.window, state.rnd);
const char *reply = "{\"success\":true}";
ipc_send_client_message(client, strlen(reply), I3_IPC_REPLY_TYPE_SYNC, (const uint8_t *)reply);
}
/* The index of each callback function corresponds to the numeric
* value of the message type (see include/i3/ipc.h) */
handler_t handlers[12] = {
handle_run_command,
handle_get_workspaces,
handle_subscribe,
handle_get_outputs,
handle_tree,
handle_get_marks,
handle_get_bar_config,
handle_get_version,
handle_get_binding_modes,
handle_get_config,
handle_send_tick,
handle_sync,
};
/* /*
* Handler for activity on a client connection, receives a message from a * Handler for activity on a client connection, receives a message from a
* client. * client.
@ -1365,13 +933,12 @@ handler_t handlers[12] = {
* *
*/ */
static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) { static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
uint32_t message_type;
uint32_t message_length; uint32_t message_length;
uint8_t *message = NULL; uint8_t *message = NULL;
ipc_client *client = (ipc_client *)w->data; ipc_client *client = (ipc_client *)w->data;
assert(client->fd == w->fd); assert(client->fd == w->fd);
int ret = ipc_recv_message(w->fd, &message_type, &message_length, &message); int ret = ipc_recv_message(w->fd, &message_length, &message);
/* EOF or other error */ /* EOF or other error */
if (ret < 0) { if (ret < 0) {
/* Was this a spurious read? See ev(3) */ /* Was this a spurious read? See ev(3) */
@ -1387,12 +954,7 @@ static void ipc_receive_message(EV_P_ struct ev_io *w, int revents) {
return; return;
} }
if (message_type >= (sizeof(handlers) / sizeof(handler_t))) handle_run_command(client, message, 0, message_length);
DLOG("Unhandled message type: %d\n", message_type);
else {
handler_t h = handlers[message_type];
h(client, message, 0, message_length, message_type);
}
FREE(message); FREE(message);
} }

View File

@ -520,8 +520,7 @@ int main(int argc, char *argv[]) {
if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
err(EXIT_FAILURE, "Could not connect to i3"); err(EXIT_FAILURE, "Could not connect to i3");
if (ipc_send_message(sockfd, strlen(payload), I3_IPC_MESSAGE_TYPE_RUN_COMMAND, if (ipc_send_message(sockfd, strlen(payload), (uint8_t *)payload) == -1)
(uint8_t *)payload) == -1)
err(EXIT_FAILURE, "IPC: write()"); err(EXIT_FAILURE, "IPC: write()");
FREE(payload); FREE(payload);
@ -529,7 +528,7 @@ int main(int argc, char *argv[]) {
uint32_t reply_type; uint32_t reply_type;
uint8_t *reply; uint8_t *reply;
int ret; int ret;
if ((ret = ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) { if ((ret = ipc_recv_message(sockfd, &reply_length, &reply)) != 0) {
if (ret == -1) if (ret == -1)
err(EXIT_FAILURE, "IPC: read()"); err(EXIT_FAILURE, "IPC: read()");
return 1; return 1;