greatly overhaul bus code
This commit is contained in:
parent
15a449ee44
commit
095eb8f403
3 changed files with 397 additions and 354 deletions
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
||||||
CC?=gcc
|
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
|
jitterbug: util.c wire.c match.c server.c main.c
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
461
server.c
461
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);
|
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)
|
int bus_client_add(bus_t *s, int fd)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < BUS_MAX_CLIENTS; i++) {
|
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) {
|
if (c->fd >= 0) {
|
||||||
close(c->fd);
|
close(c->fd);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < BUS_MAX_MATCH; i++) {
|
for (int j = 0; j < BUS_MAX_MATCH; j++) {
|
||||||
if (c->matches[i]) {
|
if (c->matches[j]) {
|
||||||
match_rule_free(c->matches[i]);
|
match_rule_free(c->matches[j]);
|
||||||
c->matches[i] = NULL;
|
c->matches[j] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bus_name_remove(s, c->unique_name_index);
|
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];
|
bus_client_t *c = &s->clients[i];
|
||||||
int match_left = c->match_count;
|
int match_left = c->match_count;
|
||||||
for (int i = 0; i < BUS_MAX_MATCH && match_left > 0; i++) {
|
for (int j = 0; j < BUS_MAX_MATCH && match_left > 0; j++) {
|
||||||
if (!c->matches[i]) {
|
if (!c->matches[j]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match_left--;
|
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];
|
uint8_t reply_data[4096];
|
||||||
memset(reply_data, 0, 4096);
|
memset(reply_data, 0, 4096);
|
||||||
wire_context_t reply_ctx = {
|
wire_context_t reply_ctx = {
|
||||||
|
@ -275,89 +345,48 @@ int bus_unicast_message(bus_t *s, wire_message_t *msg, wire_context_t *ctx, char
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _reply_begin(M_sig) \
|
#define _reply_begin(M_sig) \
|
||||||
if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \
|
uint32_t *body_length = NULL; \
|
||||||
TRYST(wire_compose_reply(&reply_ctx, &msg, (M_sig), &body_length)); \
|
uint32_t body_start = 0; \
|
||||||
body_start = reply_ctx.byte_cursor; \
|
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() \
|
#define _reply_end() \
|
||||||
*body_length = reply_ctx.byte_cursor - body_start; \
|
*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) { \
|
if (send(s->fds[i].fd, reply_ctx->data, reply_ctx->byte_cursor, 0) != reply_ctx->byte_cursor) { \
|
||||||
return -1; \
|
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)) */
|
} /* if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) */
|
||||||
|
|
||||||
#define _reply_error(message) \
|
#define _reply_error(message) \
|
||||||
do { \
|
do { \
|
||||||
if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \
|
if (!(msg->flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \
|
||||||
TRYST(wire_compose_error(&reply_ctx, &msg, (message))); \
|
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; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} while(0) \
|
} while(0) \
|
||||||
|
|
||||||
int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
int handle_hello(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) {
|
||||||
{
|
(void)ctx;
|
||||||
bus_client_t *client = &s->clients[i];
|
|
||||||
|
|
||||||
wire_message_t msg = {0};
|
int unique_name_index = TRYST(bus_client_assign_unique_name(s, i));
|
||||||
|
|
||||||
if (wire_parse_message(ctx, &msg) < 0) {
|
|
||||||
printf("parsing failed\n");
|
|
||||||
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);
|
|
||||||
wire_context_t reply_ctx = {
|
|
||||||
.byte_cursor = 0,
|
|
||||||
.data = reply_data,
|
|
||||||
.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") {
|
_reply_begin("s") {
|
||||||
TRYPTR(wire_set_string(&reply_ctx, s->names[unique_name_index].name));
|
TRYPTR(wire_set_string(reply_ctx, s->names[unique_name_index].name));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
|
|
||||||
printf("assigned unique name '%s' to connection %d\n", s->names[unique_name_index].name, i);
|
printf("assigned unique name '%s' to connection %d\n", s->names[unique_name_index].name, i);
|
||||||
} else if (strcmp(member, "RequestName") == 0) {
|
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));
|
char *name = TRYPTR(wire_get_string(ctx));
|
||||||
int name_len = strlen(name);
|
int name_len = strlen(name);
|
||||||
if (name_len < 1 || name_len > 256) {
|
if (name_len < 1 || name_len > 256) {
|
||||||
|
__TRY_TRACE();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,13 +401,16 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
_reply_begin("u") {
|
_reply_begin("u") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, status_code));
|
TRYPTR(wire_set_u32(reply_ctx, status_code));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
|
|
||||||
if (status_code == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
|
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);
|
printf("client '%s' (index=%d) now owns name '%s'\n", s->names[s->clients[i].unique_name_index].name, i, name_str);
|
||||||
}
|
}
|
||||||
} else if (strcmp(member, "GetNameOwner") == 0) {
|
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));
|
char *name = TRYPTR(wire_get_string(ctx));
|
||||||
int name_len = strlen(name);
|
int name_len = strlen(name);
|
||||||
if (name_len < 1 || name_len > 256) {
|
if (name_len < 1 || name_len > 256) {
|
||||||
|
@ -392,9 +424,12 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
_reply_begin("s") {
|
_reply_begin("s") {
|
||||||
TRYPTR(wire_set_string(&reply_ctx, s->names[target->unique_name_index].name));
|
TRYPTR(wire_set_string(reply_ctx, s->names[target->unique_name_index].name));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "NameHasOwner") == 0) {
|
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));
|
char *name = TRYPTR(wire_get_string(ctx));
|
||||||
int name_len = strlen(name);
|
int name_len = strlen(name);
|
||||||
if (name_len < 1 || name_len > 256) {
|
if (name_len < 1 || name_len > 256) {
|
||||||
|
@ -404,39 +439,52 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
bus_client_t *target = bus_name_find_client(s, name);
|
bus_client_t *target = bus_name_find_client(s, name);
|
||||||
|
|
||||||
_reply_begin("b") {
|
_reply_begin("b") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, target ? 1 : 0));
|
TRYPTR(wire_set_u32(reply_ctx, target ? 1 : 0));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "ListNames") == 0) {
|
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") {
|
_reply_begin("as") {
|
||||||
uint32_t *array_length = TRYPTR(wire_set_u32(&reply_ctx, 0));
|
uint32_t *array_length = TRYPTR(wire_set_u32(reply_ctx, 0));
|
||||||
|
|
||||||
/* arrays start with the alignment of the type they contain */
|
/* arrays start with the alignment of the type they contain */
|
||||||
TRYPTR(wire_write_align(&reply_ctx, 4));
|
TRYPTR(wire_write_align(reply_ctx, 4));
|
||||||
|
|
||||||
uint32_t array_start = reply_ctx.byte_cursor;
|
uint32_t array_start = reply_ctx->byte_cursor;
|
||||||
|
|
||||||
TRYPTR(wire_set_string(&reply_ctx, "org.freedesktop.DBus"));
|
TRYPTR(wire_set_string(reply_ctx, "org.freedesktop.DBus"));
|
||||||
|
|
||||||
int left = s->names_count;
|
int left = s->names_count;
|
||||||
for (int i = 0; i < BUS_MAX_NAMES && left > 0; i++) {
|
for (int j = 0; j < BUS_MAX_NAMES && left > 0; j++) {
|
||||||
if (s->names[i].name && s->names[i].client_index >= 0) {
|
if (s->names[j].name && s->names[j].client_index >= 0) {
|
||||||
left--;
|
left--;
|
||||||
TRYPTR(wire_set_string(&reply_ctx, s->names[i].name));
|
TRYPTR(wire_set_string(reply_ctx, s->names[j].name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*array_length = reply_ctx.byte_cursor - array_start;
|
*array_length = reply_ctx->byte_cursor - array_start;
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "ListActivatableNames") == 0) {
|
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)
|
// TODO: stub (always returns empty array)
|
||||||
printf("FIXME: STUB: ListActivatableNames\n");
|
printf("FIXME: STUB: ListActivatableNames\n");
|
||||||
|
|
||||||
_reply_begin("as") {
|
_reply_begin("as") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, 0));
|
TRYPTR(wire_set_u32(reply_ctx, 0));
|
||||||
// empty arrays still need to align
|
// empty arrays still need to align
|
||||||
TRYPTR(wire_write_align(&reply_ctx, 4));
|
TRYPTR(wire_write_align(reply_ctx, 4));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "StartServiceByName") == 0) {
|
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)
|
// TODO: stub (does nothing and always returns success)
|
||||||
|
|
||||||
char *name = TRYPTR(wire_get_string(ctx));
|
char *name = TRYPTR(wire_get_string(ctx));
|
||||||
|
@ -450,9 +498,12 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
printf("FIXME: STUB: StartServiceByName: %s\n", name);
|
printf("FIXME: STUB: StartServiceByName: %s\n", name);
|
||||||
|
|
||||||
_reply_begin("u") {
|
_reply_begin("u") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, 1));
|
TRYPTR(wire_set_u32(reply_ctx, 1));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "AddMatch") == 0) {
|
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));
|
char *match = TRYPTR(wire_get_string(ctx));
|
||||||
int match_len = strlen(match);
|
int match_len = strlen(match);
|
||||||
if (match_len < 1 || match_len > MATCH_RULE_MAX) {
|
if (match_len < 1 || match_len > MATCH_RULE_MAX) {
|
||||||
|
@ -464,7 +515,10 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
TRYST(bus_client_match_add(s, i, match));
|
TRYST(bus_client_match_add(s, i, match));
|
||||||
|
|
||||||
_reply_begin("") {} _reply_end()
|
_reply_begin("") {} _reply_end()
|
||||||
} else if (strcmp(member, "RemoveMatch") == 0) {
|
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)
|
// TODO: stub (does nothing and always returns success)
|
||||||
|
|
||||||
char *match = TRYPTR(wire_get_string(ctx));
|
char *match = TRYPTR(wire_get_string(ctx));
|
||||||
|
@ -476,16 +530,25 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
printf("FIXME: STUB: RemoveMatch: %s\n", match);
|
printf("FIXME: STUB: RemoveMatch: %s\n", match);
|
||||||
|
|
||||||
_reply_begin("") {} _reply_end()
|
_reply_begin("") {} _reply_end()
|
||||||
} else if (strcmp(member, "GetConnectionStats") == 0) {
|
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)
|
// TODO: stub (always returns empty array)
|
||||||
printf("FIXME: STUB: GetConnectionStats\n");
|
printf("FIXME: STUB: GetConnectionStats\n");
|
||||||
|
|
||||||
_reply_begin("as") {
|
_reply_begin("as") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, 0));
|
TRYPTR(wire_set_u32(reply_ctx, 0));
|
||||||
// empty arrays still need to align
|
// empty arrays still need to align
|
||||||
TRYPTR(wire_write_align(&reply_ctx, 8));
|
TRYPTR(wire_write_align(reply_ctx, 8));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "GetConnectionUnixProcessID") == 0) {
|
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));
|
char *name = TRYPTR(wire_get_string(ctx));
|
||||||
int name_len = strlen(name);
|
int name_len = strlen(name);
|
||||||
if (name_len < 1 || name_len > 256) {
|
if (name_len < 1 || name_len > 256) {
|
||||||
|
@ -507,91 +570,135 @@ int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
_reply_begin("u") {
|
_reply_begin("u") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, cred.pid));
|
TRYPTR(wire_set_u32(reply_ctx, cred.pid));
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "GetAllMatchRules") == 0) {
|
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}") {
|
_reply_begin("a{sas}") {
|
||||||
uint32_t *outer_array_len = TRYPTR(wire_set_u32(&reply_ctx, 0));
|
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 */
|
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;
|
uint32_t outer_array_start = reply_ctx->byte_cursor;
|
||||||
|
|
||||||
int left = s->names_count;
|
int left = s->names_count;
|
||||||
for (int i = 0; i < BUS_MAX_NAMES && left > 0; i++) {
|
for (int j = 0; j < BUS_MAX_NAMES && left > 0; j++) {
|
||||||
bus_name_t *n = &s->names[i];
|
bus_name_t *n = &s->names[j];
|
||||||
if (!n->name || n->client_index < 0 || *n->name != ':') {
|
if (!n->name || n->client_index < 0 || *n->name != ':') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
left--;
|
left--;
|
||||||
|
|
||||||
TRYPTR(wire_write_align(&reply_ctx, 8)); /* structs always aligned to 8 */
|
TRYPTR(wire_write_align(reply_ctx, 8)); /* structs always aligned to 8 */
|
||||||
|
|
||||||
bus_client_t *c = &s->clients[s->names[i].client_index];
|
bus_client_t *c = &s->clients[s->names[j].client_index];
|
||||||
|
|
||||||
TRYPTR(wire_set_string(&reply_ctx, s->names[i].name)); /* unique name */
|
TRYPTR(wire_set_string(reply_ctx, s->names[j].name)); /* unique name */
|
||||||
|
|
||||||
/* array of all match rules */
|
/* array of all match rules */
|
||||||
int match_left = c->match_count;
|
int match_left = c->match_count;
|
||||||
uint32_t *name_array_len = TRYPTR(wire_set_u32(&reply_ctx, 0));
|
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 */
|
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;
|
uint32_t name_array_start = reply_ctx->byte_cursor;
|
||||||
for (int i = 0; i < BUS_MAX_MATCH && match_left > 0; i++) {
|
for (int k = 0; k < BUS_MAX_MATCH && match_left > 0; k++) {
|
||||||
if (!c->matches[i]) {
|
if (!c->matches[k]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match_left--;
|
match_left--;
|
||||||
|
|
||||||
TRYPTR(wire_set_string(&reply_ctx, c->matches[i]->rule_string));
|
TRYPTR(wire_set_string(reply_ctx, c->matches[k]->rule_string));
|
||||||
}
|
}
|
||||||
*name_array_len = reply_ctx.byte_cursor - name_array_start;
|
*name_array_len = reply_ctx->byte_cursor - name_array_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
*outer_array_len = reply_ctx.byte_cursor - outer_array_start;
|
*outer_array_len = reply_ctx->byte_cursor - outer_array_start;
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else {
|
return 0;
|
||||||
printf("FIXME: daemon method '%s' is not implemented or invalid\n", member);
|
}
|
||||||
_reply_error("org.freedesktop.DBus.Error.UnknownMethod");
|
|
||||||
|
|
||||||
|
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_ctx.data, reply_ctx.byte_cursor, 0) != reply_ctx.byte_cursor) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while(0) \
|
||||||
|
|
||||||
|
int bus_client_process_message(bus_t *s, int i, wire_context_t *ctx)
|
||||||
|
{
|
||||||
|
bus_client_t *client = &s->clients[i];
|
||||||
|
|
||||||
|
wire_message_t msg = {0};
|
||||||
|
|
||||||
|
if (wire_parse_message(ctx, &msg) < 0) {
|
||||||
|
printf("parsing failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wire_message_field_t *destination_field = &msg.fields[DBUS_HEADER_FIELD_DESTINATION];
|
||||||
|
wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER];
|
||||||
|
|
||||||
|
uint8_t reply_data[4096];
|
||||||
|
memset(reply_data, 0, 4096);
|
||||||
|
wire_context_t reply_ctx = {
|
||||||
|
.byte_cursor = 0,
|
||||||
|
.data = reply_data,
|
||||||
|
.data_len = 4096,
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
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;
|
|
||||||
}
|
}
|
||||||
|
printf("FIXME: daemon method '%s' is not implemented or invalid\n", member_field->t.str);
|
||||||
should_forward = true;
|
_process_message_reply_error("org.freedesktop.DBus.Error.UnknownMethod");
|
||||||
} break;
|
|
||||||
|
|
||||||
case DBUS_MESSAGE_SIGNAL: {
|
|
||||||
should_forward = true;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
_reply_error("xyz.hippoz.jitterbug.NotImplemented");
|
|
||||||
return 0;
|
return 0;
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_forward) {
|
// 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) {
|
if (client->unique_name_index < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destination_field->present) {
|
if (destination_field->present) {
|
||||||
/* unicast */
|
|
||||||
if (bus_unicast_message(s, &msg, ctx, destination_field->t.str, s->names[client->unique_name_index].name) < 0) {
|
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");
|
_process_message_reply_error("xyz.hippoz.jitterbug.UnicastFailed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* broadcast */
|
|
||||||
if (bus_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) {
|
if (bus_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) {
|
||||||
_reply_error("xyz.hippoz.jitterbug.BroadcastFailed");
|
_process_message_reply_error("xyz.hippoz.jitterbug.BroadcastFailed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
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;
|
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;})
|
#define _client_die(m) ({bus_client_error(s,i,m);continue;})
|
||||||
int bus_turn(bus_t *s)
|
int bus_turn(bus_t *s)
|
||||||
{
|
{
|
||||||
|
@ -738,10 +775,10 @@ int bus_turn(bus_t *s)
|
||||||
|
|
||||||
if (fd == s->sock_fd) {
|
if (fd == s->sock_fd) {
|
||||||
// new connection
|
// 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) {
|
if (bus_client_add(s, accepted_fd) == -1) {
|
||||||
close(fd);
|
close(accepted_fd);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
6
server.h
6
server.h
|
@ -2,6 +2,7 @@
|
||||||
#define _JITTERBUG__SERVER_H
|
#define _JITTERBUG__SERVER_H
|
||||||
|
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
|
#include "wire.h"
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -42,6 +43,11 @@ typedef struct bus {
|
||||||
struct pollfd fds[BUS_MAX_CLIENTS + 1];
|
struct pollfd fds[BUS_MAX_CLIENTS + 1];
|
||||||
} bus_t;
|
} 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);
|
int bus_client_add(bus_t *s, int fd);
|
||||||
void bus_client_remove(bus_t *s, int i);
|
void bus_client_remove(bus_t *s, int i);
|
||||||
|
|
Loading…
Reference in a new issue