From 095eb8f403ba9dfefc551824e7514e5aea4cbbca Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Tue, 10 Jan 2023 14:57:16 +0200 Subject: [PATCH] greatly overhaul bus code --- Makefile | 2 +- server.c | 743 +++++++++++++++++++++++++++++-------------------------- server.h | 6 + 3 files changed, 397 insertions(+), 354 deletions(-) diff --git a/Makefile b/Makefile index 4940b82..aeda28c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC?=gcc -CFLAGS+=-Wall -Wextra -std=c99 -ggdb -fsanitize=address +CFLAGS+=-Wall -Wextra -Wshadow -std=c99 -ggdb -fsanitize=address jitterbug: util.c wire.c match.c server.c main.c $(CC) $(CFLAGS) -o $@ $^ diff --git a/server.c b/server.c index 684d07f..49970ca 100644 --- a/server.c +++ b/server.c @@ -28,6 +28,76 @@ uint64_t hashmap_hash(const char *bytes, size_t bytes_n, size_t map_len) return (hash % map_len); } +void bus_free(bus_t *s) +{ + if (!s) return; + if (s->sock_fd) close(s->sock_fd); + // freeing all clients will also free all matches and names + for (int i = 0; i < BUS_MAX_CLIENTS; i++) { + bus_client_remove(s, i); + } + free(s); +} + +bus_t *bus_create(const char *socket_path) +{ + bus_t *s = malloc(sizeof(bus_t)); + if (s == NULL) { + return NULL; + } + + s->sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (s->sock_fd == -1) { + free(s); + return NULL; + } + + struct sockaddr_un name; + memset(&name, 0, sizeof(name)); + name.sun_family = AF_UNIX; + strncpy(name.sun_path, socket_path, sizeof(name.sun_path) - 1); + + unlink(socket_path); + + if (bind(s->sock_fd, (const struct sockaddr *)&name, sizeof(name)) == -1) { + close(s->sock_fd); + free(s); + return NULL; + } + if (listen(s->sock_fd, BUS_BACKLOG) == -1) { + close(s->sock_fd); + free(s); + return NULL; + } + + for (int i = 0; i < BUS_MAX_CLIENTS; i++) { + s->clients[i].fd = -1; + s->clients[i].owned_name_index = -1; + s->clients[i].unique_name_index = -1; + s->clients[i].state = BUS_CLIENT_STATE_NONE; + s->clients[i].match_count = 0; + s->fds[i].fd = -1; + s->fds[i].events = 0; + s->fds[i].revents = 0; + for (int j = 0; j < BUS_MAX_MATCH; j++) { + s->clients[i].matches[j] = NULL; + } + } + + for (int i = 0; i < BUS_MAX_NAMES; i++) { + s->names[i].client_index = -1; + s->names[i].name = NULL; + } + s->names_count = 0; + s->clients_count = 0; + + s->fds[BUS_MAX_CLIENTS].fd = s->sock_fd; + s->fds[BUS_MAX_CLIENTS].events = POLLIN; + s->fd_num = BUS_MAX_CLIENTS + 1; + + return s; +} + int bus_client_add(bus_t *s, int fd) { for (int i = 0; i < BUS_MAX_CLIENTS; i++) { @@ -181,10 +251,10 @@ void bus_client_remove(bus_t *s, int i) if (c->fd >= 0) { close(c->fd); } - for (int i = 0; i < BUS_MAX_MATCH; i++) { - if (c->matches[i]) { - match_rule_free(c->matches[i]); - c->matches[i] = NULL; + for (int j = 0; j < BUS_MAX_MATCH; j++) { + if (c->matches[j]) { + match_rule_free(c->matches[j]); + c->matches[j] = NULL; } } bus_name_remove(s, c->unique_name_index); @@ -228,13 +298,13 @@ int bus_broadcast_message(bus_t *s, wire_message_t *msg, wire_context_t *ctx, ch bus_client_t *c = &s->clients[i]; int match_left = c->match_count; - for (int i = 0; i < BUS_MAX_MATCH && match_left > 0; i++) { - if (!c->matches[i]) { + for (int j = 0; j < BUS_MAX_MATCH && match_left > 0; j++) { + if (!c->matches[j]) { continue; } match_left--; - if (match_rule_check(c->matches[i], msg, ctx) >= 0) { + if (match_rule_check(c->matches[j], msg, ctx) >= 0) { uint8_t reply_data[4096]; memset(reply_data, 0, 4096); wire_context_t reply_ctx = { @@ -275,23 +345,301 @@ int bus_unicast_message(bus_t *s, wire_message_t *msg, wire_context_t *ctx, char } #define _reply_begin(M_sig) \ - if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \ - TRYST(wire_compose_reply(&reply_ctx, &msg, (M_sig), &body_length)); \ - body_start = reply_ctx.byte_cursor; \ + uint32_t *body_length = NULL; \ + uint32_t body_start = 0; \ + if (!(msg->flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \ + TRYST(wire_compose_reply(reply_ctx, msg, (M_sig), &body_length)); \ + body_start = reply_ctx->byte_cursor; \ #define _reply_end() \ - *body_length = reply_ctx.byte_cursor - body_start; \ - if (send(s->fds[i].fd, reply_data, reply_ctx.byte_cursor, 0) != reply_ctx.byte_cursor) { \ + *body_length = reply_ctx->byte_cursor - body_start; \ + if (send(s->fds[i].fd, reply_ctx->data, reply_ctx->byte_cursor, 0) != reply_ctx->byte_cursor) { \ return -1; \ } \ - printf("send: sent %d bytes!\n", reply_ctx.byte_cursor); \ + printf("send: sent %d bytes!\n", reply_ctx->byte_cursor); \ } /* if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) */ #define _reply_error(message) \ + do { \ + if (!(msg->flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \ + TRYST(wire_compose_error(reply_ctx, msg, (message))); \ + if (send(s->fds[i].fd, reply_ctx->data, reply_ctx->byte_cursor, 0) != reply_ctx->byte_cursor) { \ + return -1; \ + } \ + } \ + } while(0) \ + +int handle_hello(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + (void)ctx; + + int unique_name_index = TRYST(bus_client_assign_unique_name(s, i)); + + _reply_begin("s") { + TRYPTR(wire_set_string(reply_ctx, s->names[unique_name_index].name)); + } _reply_end() + + printf("assigned unique name '%s' to connection %d\n", s->names[unique_name_index].name, i); + return 0; +} + +int handle_request_name(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + char *name = TRYPTR(wire_get_string(ctx)); + int name_len = strlen(name); + if (name_len < 1 || name_len > 256) { + __TRY_TRACE(); + return -1; + } + + char *name_str = TRYPTR(string_dup(name)); + + int status_code = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; + + if (bus_client_assign_own_name(s, i, name_str) < 0) { + free(name_str); + // TODO: report the actual error + status_code = DBUS_REQUEST_NAME_REPLY_EXISTS; + } + + _reply_begin("u") { + TRYPTR(wire_set_u32(reply_ctx, status_code)); + } _reply_end() + + if (status_code == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + printf("client '%s' (index=%d) now owns name '%s'\n", s->names[s->clients[i].unique_name_index].name, i, name_str); + } + return 0; +} + +int handle_get_name_owner(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + char *name = TRYPTR(wire_get_string(ctx)); + int name_len = strlen(name); + if (name_len < 1 || name_len > 256) { + return -1; + } + + bus_client_t *target = bus_name_find_client(s, name); + if (!target || target->unique_name_index < 0) { + _reply_error("org.freedesktop.DBus.Error.NameHasNoOwner"); + return 0; + } + + _reply_begin("s") { + TRYPTR(wire_set_string(reply_ctx, s->names[target->unique_name_index].name)); + } _reply_end() + return 0; +} + +int handle_name_has_owner(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + char *name = TRYPTR(wire_get_string(ctx)); + int name_len = strlen(name); + if (name_len < 1 || name_len > 256) { + return -1; + } + + bus_client_t *target = bus_name_find_client(s, name); + + _reply_begin("b") { + TRYPTR(wire_set_u32(reply_ctx, target ? 1 : 0)); + } _reply_end() + return 0; +} + +int handle_list_names(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + (void)ctx; + + _reply_begin("as") { + uint32_t *array_length = TRYPTR(wire_set_u32(reply_ctx, 0)); + + /* arrays start with the alignment of the type they contain */ + TRYPTR(wire_write_align(reply_ctx, 4)); + + uint32_t array_start = reply_ctx->byte_cursor; + + TRYPTR(wire_set_string(reply_ctx, "org.freedesktop.DBus")); + + int left = s->names_count; + for (int j = 0; j < BUS_MAX_NAMES && left > 0; j++) { + if (s->names[j].name && s->names[j].client_index >= 0) { + left--; + TRYPTR(wire_set_string(reply_ctx, s->names[j].name)); + } + } + + *array_length = reply_ctx->byte_cursor - array_start; + } _reply_end() + return 0; +} + +int handle_list_activatable_names(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + (void)ctx; + + // TODO: stub (always returns empty array) + printf("FIXME: STUB: ListActivatableNames\n"); + + _reply_begin("as") { + TRYPTR(wire_set_u32(reply_ctx, 0)); + // empty arrays still need to align + TRYPTR(wire_write_align(reply_ctx, 4)); + } _reply_end() + return 0; +} + +int handle_start_service_by_name(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + // TODO: stub (does nothing and always returns success) + + char *name = TRYPTR(wire_get_string(ctx)); + int name_len = strlen(name); + if (name_len < 1 || name_len > 256) { + return -1; + } + /* unused flags value */ + TRYPTR(wire_get_u32(ctx)); + + printf("FIXME: STUB: StartServiceByName: %s\n", name); + + _reply_begin("u") { + TRYPTR(wire_set_u32(reply_ctx, 1)); + } _reply_end() + return 0; +} + +int handle_add_match(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + char *match = TRYPTR(wire_get_string(ctx)); + int match_len = strlen(match); + if (match_len < 1 || match_len > MATCH_RULE_MAX) { + return -1; + } + + printf("client index %d adding match rule: '%s'\n", i, match); + + TRYST(bus_client_match_add(s, i, match)); + + _reply_begin("") {} _reply_end() + return 0; +} + +int handle_remove_match(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + // TODO: stub (does nothing and always returns success) + + char *match = TRYPTR(wire_get_string(ctx)); + int match_len = strlen(match); + if (match_len < 1 || match_len > MATCH_RULE_MAX) { + return -1; + } + + printf("FIXME: STUB: RemoveMatch: %s\n", match); + + _reply_begin("") {} _reply_end() + return 0; +} + +int handle_get_connection_stats(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + (void)ctx; + + // TODO: stub (always returns empty array) + printf("FIXME: STUB: GetConnectionStats\n"); + + _reply_begin("as") { + TRYPTR(wire_set_u32(reply_ctx, 0)); + // empty arrays still need to align + TRYPTR(wire_write_align(reply_ctx, 8)); + } _reply_end() + return 0; +} + +int handle_get_connection_unix_process_id(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + (void)ctx; + char *name = TRYPTR(wire_get_string(ctx)); + int name_len = strlen(name); + if (name_len < 1 || name_len > 256) { + return -1; + } + + bus_client_t *target = bus_name_find_client(s, name); + if (!target || target->unique_name_index < 0 || target->fd < 0) { + _reply_error("org.freedesktop.DBus.Error.NameHasNoOwner"); + return 0; + } + + struct ucred cred; + socklen_t len = sizeof(struct ucred); + + if (getsockopt(target->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1) { + _reply_error("xyz.hippoz.jitterbug.FailedToGetPID"); + return 0; + } + + _reply_begin("u") { + TRYPTR(wire_set_u32(reply_ctx, cred.pid)); + } _reply_end() + return 0; +} + +int handle_get_all_match_rules(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { + (void)ctx; + _reply_begin("a{sas}") { + uint32_t *outer_array_len = TRYPTR(wire_set_u32(reply_ctx, 0)); + TRYPTR(wire_write_align(reply_ctx, 8)); /* arrays start with the alignment of the type they contain */ + uint32_t outer_array_start = reply_ctx->byte_cursor; + + int left = s->names_count; + for (int j = 0; j < BUS_MAX_NAMES && left > 0; j++) { + bus_name_t *n = &s->names[j]; + if (!n->name || n->client_index < 0 || *n->name != ':') { + continue; + } + left--; + + TRYPTR(wire_write_align(reply_ctx, 8)); /* structs always aligned to 8 */ + + bus_client_t *c = &s->clients[s->names[j].client_index]; + + TRYPTR(wire_set_string(reply_ctx, s->names[j].name)); /* unique name */ + + /* array of all match rules */ + int match_left = c->match_count; + uint32_t *name_array_len = TRYPTR(wire_set_u32(reply_ctx, 0)); + TRYPTR(wire_write_align(reply_ctx, 4)); /* arrays start with the alignment of the type they contain */ + uint32_t name_array_start = reply_ctx->byte_cursor; + for (int k = 0; k < BUS_MAX_MATCH && match_left > 0; k++) { + if (!c->matches[k]) { + continue; + } + match_left--; + + TRYPTR(wire_set_string(reply_ctx, c->matches[k]->rule_string)); + } + *name_array_len = reply_ctx->byte_cursor - name_array_start; + } + + *outer_array_len = reply_ctx->byte_cursor - outer_array_start; + } _reply_end() + return 0; +} + + +static const bus_method_handler_t bus_method_handlers[] = { + { "Hello", handle_hello }, + { "RequestName", handle_request_name }, + { "GetNameOwner", handle_get_name_owner }, + { "NameHasOwner", handle_name_has_owner }, + { "ListNames", handle_list_names }, + { "ListActivatableNames", handle_list_activatable_names }, + { "StartServiceByName", handle_start_service_by_name }, + { "AddMatch", handle_add_match }, + { "RemoveMatch", handle_remove_match }, + { "GetConnectionStats", handle_get_connection_stats }, + { "GetConnectionUnixProcessID", handle_get_connection_unix_process_id }, + { "GetAllMatchRules", handle_get_all_match_rules } +}; +static const int bus_method_handlers_count = sizeof(bus_method_handlers) / sizeof(bus_method_handlers[0]); + + +#define _process_message_reply_error(message) \ do { \ if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \ TRYST(wire_compose_error(&reply_ctx, &msg, (message))); \ - if (send(s->fds[i].fd, reply_data, reply_ctx.byte_cursor, 0) != reply_ctx.byte_cursor) { \ + if (send(s->fds[i].fd, reply_ctx.data, reply_ctx.byte_cursor, 0) != reply_ctx.byte_cursor) { \ return -1; \ } \ } \ @@ -308,13 +656,8 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx) return -1; } - printf("process_message: processed %d/%zu bytes\n", ctx->byte_cursor, ctx->data_len); - wire_message_field_t *destination_field = &msg.fields[DBUS_HEADER_FIELD_DESTINATION]; wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER]; - bool should_forward = false; - uint32_t *body_length; - uint32_t body_start; uint8_t reply_data[4096]; memset(reply_data, 0, 4096); @@ -324,272 +667,36 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx) .data_len = 4096, }; - switch (msg.type) { - case DBUS_MESSAGE_METHOD_CALL: { - if (!member_field->present) { - return -1; - } - - if (!destination_field->present) { - should_forward = true; - break; - } - - char *member = member_field->t.str; - - if (strcmp(destination_field->t.str, "org.freedesktop.DBus") != 0) { - // not for dbus. - should_forward = true; - break; - } - - if (strcmp(member, "Hello") == 0) { - int unique_name_index = bus_client_assign_unique_name(s, i); - if (unique_name_index < 0) { - return -1; - } - - _reply_begin("s") { - TRYPTR(wire_set_string(&reply_ctx, s->names[unique_name_index].name)); - } _reply_end() - - printf("assigned unique name '%s' to connection %d\n", s->names[unique_name_index].name, i); - } else if (strcmp(member, "RequestName") == 0) { - char *name = TRYPTR(wire_get_string(ctx)); - int name_len = strlen(name); - if (name_len < 1 || name_len > 256) { - return -1; - } - - char *name_str = TRYPTR(string_dup(name)); - - int status_code = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; - - if (bus_client_assign_own_name(s, i, name_str) < 0) { - free(name_str); - // TODO: report the actual error - status_code = DBUS_REQUEST_NAME_REPLY_EXISTS; - } - - _reply_begin("u") { - TRYPTR(wire_set_u32(&reply_ctx, status_code)); - } _reply_end() - - if (status_code == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - printf("client '%s' (index=%d) now owns name '%s'\n", s->names[client->unique_name_index].name, i, name_str); - } - } else if (strcmp(member, "GetNameOwner") == 0) { - char *name = TRYPTR(wire_get_string(ctx)); - int name_len = strlen(name); - if (name_len < 1 || name_len > 256) { - return -1; - } - - bus_client_t *target = bus_name_find_client(s, name); - if (!target || target->unique_name_index < 0) { - _reply_error("org.freedesktop.DBus.Error.NameHasNoOwner"); - return 0; - } - - _reply_begin("s") { - TRYPTR(wire_set_string(&reply_ctx, s->names[target->unique_name_index].name)); - } _reply_end() - } else if (strcmp(member, "NameHasOwner") == 0) { - char *name = TRYPTR(wire_get_string(ctx)); - int name_len = strlen(name); - if (name_len < 1 || name_len > 256) { - return -1; - } - - bus_client_t *target = bus_name_find_client(s, name); - - _reply_begin("b") { - TRYPTR(wire_set_u32(&reply_ctx, target ? 1 : 0)); - } _reply_end() - } else if (strcmp(member, "ListNames") == 0) { - _reply_begin("as") { - uint32_t *array_length = TRYPTR(wire_set_u32(&reply_ctx, 0)); - - /* arrays start with the alignment of the type they contain */ - TRYPTR(wire_write_align(&reply_ctx, 4)); - - uint32_t array_start = reply_ctx.byte_cursor; - - TRYPTR(wire_set_string(&reply_ctx, "org.freedesktop.DBus")); - - int left = s->names_count; - for (int i = 0; i < BUS_MAX_NAMES && left > 0; i++) { - if (s->names[i].name && s->names[i].client_index >= 0) { - left--; - TRYPTR(wire_set_string(&reply_ctx, s->names[i].name)); - } - } - - *array_length = reply_ctx.byte_cursor - array_start; - } _reply_end() - } else if (strcmp(member, "ListActivatableNames") == 0) { - // TODO: stub (always returns empty array) - printf("FIXME: STUB: ListActivatableNames\n"); - - _reply_begin("as") { - TRYPTR(wire_set_u32(&reply_ctx, 0)); - // empty arrays still need to align - TRYPTR(wire_write_align(&reply_ctx, 4)); - } _reply_end() - } else if (strcmp(member, "StartServiceByName") == 0) { - // TODO: stub (does nothing and always returns success) - - char *name = TRYPTR(wire_get_string(ctx)); - int name_len = strlen(name); - if (name_len < 1 || name_len > 256) { - return -1; - } - /* unused flags value */ - TRYPTR(wire_get_u32(ctx)); - - printf("FIXME: STUB: StartServiceByName: %s\n", name); - - _reply_begin("u") { - TRYPTR(wire_set_u32(&reply_ctx, 1)); - } _reply_end() - } else if (strcmp(member, "AddMatch") == 0) { - char *match = TRYPTR(wire_get_string(ctx)); - int match_len = strlen(match); - if (match_len < 1 || match_len > MATCH_RULE_MAX) { - return -1; - } - - printf("client index %d adding match rule: '%s'\n", i, match); - - TRYST(bus_client_match_add(s, i, match)); - - _reply_begin("") {} _reply_end() - } else if (strcmp(member, "RemoveMatch") == 0) { - // TODO: stub (does nothing and always returns success) - - char *match = TRYPTR(wire_get_string(ctx)); - int match_len = strlen(match); - if (match_len < 1 || match_len > MATCH_RULE_MAX) { - return -1; - } - - printf("FIXME: STUB: RemoveMatch: %s\n", match); - - _reply_begin("") {} _reply_end() - } else if (strcmp(member, "GetConnectionStats") == 0) { - // TODO: stub (always returns empty array) - printf("FIXME: STUB: GetConnectionStats\n"); - - _reply_begin("as") { - TRYPTR(wire_set_u32(&reply_ctx, 0)); - // empty arrays still need to align - TRYPTR(wire_write_align(&reply_ctx, 8)); - } _reply_end() - } else if (strcmp(member, "GetConnectionUnixProcessID") == 0) { - char *name = TRYPTR(wire_get_string(ctx)); - int name_len = strlen(name); - if (name_len < 1 || name_len > 256) { - return -1; - } - - bus_client_t *target = bus_name_find_client(s, name); - if (!target || target->unique_name_index < 0 || target->fd < 0) { - _reply_error("org.freedesktop.DBus.Error.NameHasNoOwner"); - return 0; - } - - struct ucred cred; - socklen_t len = sizeof(struct ucred); - - if (getsockopt(target->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1) { - _reply_error("xyz.hippoz.jitterbug.FailedToGetPID"); - return 0; - } - - _reply_begin("u") { - TRYPTR(wire_set_u32(&reply_ctx, cred.pid)); - } _reply_end() - } else if (strcmp(member, "GetAllMatchRules") == 0) { - _reply_begin("a{sas}") { - uint32_t *outer_array_len = TRYPTR(wire_set_u32(&reply_ctx, 0)); - TRYPTR(wire_write_align(&reply_ctx, 8)); /* arrays start with the alignment of the type they contain */ - uint32_t outer_array_start = reply_ctx.byte_cursor; - - int left = s->names_count; - for (int i = 0; i < BUS_MAX_NAMES && left > 0; i++) { - bus_name_t *n = &s->names[i]; - if (!n->name || n->client_index < 0 || *n->name != ':') { - continue; - } - left--; - - TRYPTR(wire_write_align(&reply_ctx, 8)); /* structs always aligned to 8 */ - - bus_client_t *c = &s->clients[s->names[i].client_index]; - - TRYPTR(wire_set_string(&reply_ctx, s->names[i].name)); /* unique name */ - - /* array of all match rules */ - int match_left = c->match_count; - uint32_t *name_array_len = TRYPTR(wire_set_u32(&reply_ctx, 0)); - TRYPTR(wire_write_align(&reply_ctx, 4)); /* arrays start with the alignment of the type they contain */ - uint32_t name_array_start = reply_ctx.byte_cursor; - for (int i = 0; i < BUS_MAX_MATCH && match_left > 0; i++) { - if (!c->matches[i]) { - continue; - } - match_left--; - - TRYPTR(wire_set_string(&reply_ctx, c->matches[i]->rule_string)); - } - *name_array_len = reply_ctx.byte_cursor - name_array_start; - } - - *outer_array_len = reply_ctx.byte_cursor - outer_array_start; - } _reply_end() - } else { - printf("FIXME: daemon method '%s' is not implemented or invalid\n", member); - _reply_error("org.freedesktop.DBus.Error.UnknownMethod"); + if (msg.type == DBUS_MESSAGE_METHOD_CALL && destination_field->present && member_field->present && strcmp(destination_field->t.str, "org.freedesktop.DBus") == 0) { + // method call to the bus + for (int j = 0; j < bus_method_handlers_count; j++) { + const bus_method_handler_t *handler = &bus_method_handlers[j]; + if (strcmp(handler->name, member_field->t.str) == 0) { + TRYST(handler->handler(s, i, &msg, ctx, &reply_ctx)); return 0; } - } break; - - case DBUS_MESSAGE_METHOD_RETURN: { - // we assume that method returns without any destination field are directed at their sender - // TODO: this is probably not correct - if (!destination_field->present) { - destination_field->t.str = s->names[client->unique_name_index].name; - } - - should_forward = true; - } break; - - case DBUS_MESSAGE_SIGNAL: { - should_forward = true; - } break; - - default: { - _reply_error("xyz.hippoz.jitterbug.NotImplemented"); - return 0; - } break; + } + printf("FIXME: daemon method '%s' is not implemented or invalid\n", member_field->t.str); + _process_message_reply_error("org.freedesktop.DBus.Error.UnknownMethod"); + return 0; } - if (should_forward) { - if (client->unique_name_index < 0) { - return -1; + // message needs to be routed + // TODO: perform checks here like making sure all method calls have the 'member' field, etc. + + if (client->unique_name_index < 0) { + return -1; + } + + if (destination_field->present) { + if (bus_unicast_message(s, &msg, ctx, destination_field->t.str, s->names[client->unique_name_index].name) < 0) { + _process_message_reply_error("xyz.hippoz.jitterbug.UnicastFailed"); + return 0; } - if (destination_field->present) { - /* unicast */ - if (bus_unicast_message(s, &msg, ctx, destination_field->t.str, s->names[client->unique_name_index].name) < 0) { - _reply_error("xyz.hippoz.jitterbug.UnicastFailed"); - return 0; - } - } else { - /* broadcast */ - if (bus_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) { - _reply_error("xyz.hippoz.jitterbug.BroadcastFailed"); - return 0; - } + } else { + if (bus_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) { + _process_message_reply_error("xyz.hippoz.jitterbug.BroadcastFailed"); + return 0; } } @@ -620,76 +727,6 @@ int bus_client_drain_messages(bus_t *s, int ci, uint8_t *data, uint32_t data_len return 0; } -void bus_free(bus_t *s) -{ - if (!s) return; - if (s->sock_fd) close(s->sock_fd); - // freeing all clients will also free all matches and names - for (int i = 0; i < BUS_MAX_CLIENTS; i++) { - bus_client_remove(s, i); - } - free(s); -} - -bus_t *bus_create(const char *socket_path) -{ - bus_t *s = malloc(sizeof(bus_t)); - if (s == NULL) { - return NULL; - } - - s->sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (s->sock_fd == -1) { - free(s); - return NULL; - } - - struct sockaddr_un name; - memset(&name, 0, sizeof(name)); - name.sun_family = AF_UNIX; - strncpy(name.sun_path, socket_path, sizeof(name.sun_path) - 1); - - unlink(socket_path); - - if (bind(s->sock_fd, (const struct sockaddr *)&name, sizeof(name)) == -1) { - close(s->sock_fd); - free(s); - return NULL; - } - if (listen(s->sock_fd, BUS_BACKLOG) == -1) { - close(s->sock_fd); - free(s); - return NULL; - } - - for (int i = 0; i < BUS_MAX_CLIENTS; i++) { - s->clients[i].fd = -1; - s->clients[i].owned_name_index = -1; - s->clients[i].unique_name_index = -1; - s->clients[i].state = BUS_CLIENT_STATE_NONE; - s->clients[i].match_count = 0; - s->fds[i].fd = -1; - s->fds[i].events = 0; - s->fds[i].revents = 0; - for (int j = 0; j < BUS_MAX_MATCH; j++) { - s->clients[i].matches[j] = NULL; - } - } - - for (int i = 0; i < BUS_MAX_NAMES; i++) { - s->names[i].client_index = -1; - s->names[i].name = NULL; - } - s->names_count = 0; - s->clients_count = 0; - - s->fds[BUS_MAX_CLIENTS].fd = s->sock_fd; - s->fds[BUS_MAX_CLIENTS].events = POLLIN; - s->fd_num = BUS_MAX_CLIENTS + 1; - - return s; -} - #define _client_die(m) ({bus_client_error(s,i,m);continue;}) int bus_turn(bus_t *s) { @@ -738,10 +775,10 @@ int bus_turn(bus_t *s) if (fd == s->sock_fd) { // new connection - int fd = TRYST(accept(s->sock_fd, NULL, NULL)); + int accepted_fd = TRYST(accept(s->sock_fd, NULL, NULL)); - if (bus_client_add(s, fd) == -1) { - close(fd); + if (bus_client_add(s, accepted_fd) == -1) { + close(accepted_fd); } continue; } diff --git a/server.h b/server.h index 134445a..29a42d9 100644 --- a/server.h +++ b/server.h @@ -2,6 +2,7 @@ #define _JITTERBUG__SERVER_H #include "match.h" +#include "wire.h" #include #include @@ -42,6 +43,11 @@ typedef struct bus { struct pollfd fds[BUS_MAX_CLIENTS + 1]; } bus_t; +typedef struct bus_method_handler { + const char *name; + int (*handler)(bus_t *bus, int client_index, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx); +} bus_method_handler_t; + int bus_client_add(bus_t *s, int fd); void bus_client_remove(bus_t *s, int i);