Compare commits

..

No commits in common. "ce164d8d5da23f9dfeba9ac20e9211a3e9d81aa2" and "de00067fd1907aab7e00a9582f60a360f75bd261" have entirely different histories.

6 changed files with 441 additions and 469 deletions

View file

@ -1,5 +1,5 @@
CC?=gcc CC?=gcc
CFLAGS+=-Wall -Wextra -Wshadow -std=c99 -ggdb -fsanitize=address CFLAGS+=-Wall -Wextra -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 $@ $^

8
main.c
View file

@ -27,7 +27,7 @@ int main(int argc, char *argv[])
/* we handle send() errors directly in the code */ /* we handle send() errors directly in the code */
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
bus_t *srv = bus_create(socket_path); struct jb_server *srv = jb_server_create(socket_path);
if (srv == NULL) { if (srv == NULL) {
fprintf(stderr, "server_create failed\n"); fprintf(stderr, "server_create failed\n");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -36,14 +36,14 @@ int main(int argc, char *argv[])
printf("Listening on %s\n", socket_path); printf("Listening on %s\n", socket_path);
while (1) { while (1) {
if (bus_turn(srv) < 0) { if (jb_server_turn(srv) < 0) {
fprintf(stderr, "server_turn failed (errno=%d, strerror=%s)\n", errno, strerror(errno)); fprintf(stderr, "server_turn failed (errno=%d, strerror=%s)\n", errno, strerror(errno));
bus_free(srv); jb_server_free(srv);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
bus_free(srv); jb_server_free(srv);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

615
server.c
View file

@ -28,84 +28,14 @@ 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) int jb_server_client_add(struct jb_server *s, int fd)
{ {
if (!s) return; for (int i = 0; i < JB_MAX_CLIENTS; i++) {
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++) {
if (s->clients[i].fd < 0) { if (s->clients[i].fd < 0) {
s->clients[i].fd = fd; s->clients[i].fd = fd;
s->clients[i].owned_name_index = -1; s->clients[i].owned_name_index = -1;
s->clients[i].unique_name_index = -1; s->clients[i].unique_name_index = -1;
s->clients[i].state = BUS_CLIENT_STATE_WAIT_AUTH; s->clients[i].state = JB_CLIENT_STATE_WAIT_AUTH;
s->fds[i].fd = fd; s->fds[i].fd = fd;
s->fds[i].events = POLLIN; s->fds[i].events = POLLIN;
s->clients_count++; s->clients_count++;
@ -115,11 +45,11 @@ int bus_client_add(bus_t *s, int fd)
return -1; return -1;
} }
int bus_name_find(bus_t *s, char *name) int jb_server_name_find(struct jb_server *s, char *name)
{ {
int bucket = hashmap_hash(name, strlen(name), BUS_MAX_NAMES); int bucket = hashmap_hash(name, strlen(name), JB_MAX_NAMES);
for (int i = bucket; i < bucket + 12 && i < BUS_MAX_NAMES; i++) { for (int i = bucket; i < bucket + 12 && i < JB_MAX_NAMES; i++) {
if (s->names[i].name && strcmp(s->names[i].name, name) == 0) { if (s->names[i].name && strcmp(s->names[i].name, name) == 0) {
return i; return i;
} }
@ -128,9 +58,9 @@ int bus_name_find(bus_t *s, char *name)
return -1; return -1;
} }
bus_client_t *bus_name_find_client(bus_t *s, char *name) struct jb_client *jb_server_name_find_client(struct jb_server *s, char *name)
{ {
int name_index = bus_name_find(s, name); int name_index = jb_server_name_find(s, name);
if (name_index < 0) { if (name_index < 0) {
return NULL; return NULL;
} }
@ -139,22 +69,22 @@ bus_client_t *bus_name_find_client(bus_t *s, char *name)
return NULL; return NULL;
} }
if (s->clients[s->names[name_index].client_index].state != BUS_CLIENT_STATE_READY) { if (s->clients[s->names[name_index].client_index].state != JB_CLIENT_STATE_READY) {
return NULL; return NULL;
} }
return &s->clients[s->names[name_index].client_index]; return &s->clients[s->names[name_index].client_index];
} }
int bus_name_add(bus_t *s, char *name, int client_index) int jb_server_name_add(struct jb_server *s, char *name, int client_index)
{ {
if (bus_name_find(s, name) >= 0) { if (jb_server_name_find(s, name) >= 0) {
return -1; return -1;
} }
int bucket = hashmap_hash(name, strlen(name), BUS_MAX_NAMES); int bucket = hashmap_hash(name, strlen(name), JB_MAX_NAMES);
for (int i = bucket; i < bucket + 12 && i < BUS_MAX_NAMES; i++) { for (int i = bucket; i < bucket + 12 && i < JB_MAX_NAMES; i++) {
if (s->names[i].client_index == -1) { if (s->names[i].client_index == -1) {
s->names[i].client_index = client_index; s->names[i].client_index = client_index;
s->names[i].name = name; s->names[i].name = name;
@ -166,11 +96,11 @@ int bus_name_add(bus_t *s, char *name, int client_index)
return -1; return -1;
} }
int bus_client_match_add(bus_t *s, int client_index, char *match) int jb_server_client_match_add(struct jb_server *s, int client_index, char *match)
{ {
bus_client_t *c = &s->clients[client_index]; struct jb_client *c = &s->clients[client_index];
for (int i = 0; i < BUS_MAX_MATCH; i++) { for (int i = 0; i < JB_MAX_MATCH; i++) {
if (!c->matches[i]) { if (!c->matches[i]) {
c->matches[i] = match_rule_from_string(match); c->matches[i] = match_rule_from_string(match);
c->match_count++; c->match_count++;
@ -181,9 +111,9 @@ int bus_client_match_add(bus_t *s, int client_index, char *match)
return -1; return -1;
} }
int bus_client_assign_unique_name(bus_t *s, int i) int jb_server_client_assign_unique_name(struct jb_server *s, int i)
{ {
bus_client_t *c = &s->clients[i]; struct jb_client *c = &s->clients[i];
if (c->unique_name_index != -1) { if (c->unique_name_index != -1) {
return -1; return -1;
} }
@ -206,7 +136,7 @@ int bus_client_assign_unique_name(bus_t *s, int i)
return -1; return -1;
} }
int name_index = bus_name_add(s, name, i); int name_index = jb_server_name_add(s, name, i);
if (name_index < 0) { if (name_index < 0) {
free(name); free(name);
return -1; return -1;
@ -216,14 +146,14 @@ int bus_client_assign_unique_name(bus_t *s, int i)
return name_index; return name_index;
} }
int bus_client_assign_own_name(bus_t *s, int i, char *name) int jb_server_client_assign_own_name(struct jb_server *s, int i, char *name)
{ {
bus_client_t *c = &s->clients[i]; struct jb_client *c = &s->clients[i];
if (c->owned_name_index != -1 || !name || *name == ':' || *name == '\0') { if (c->owned_name_index != -1 || !name || *name == ':' || *name == '\0') {
return -1; return -1;
} }
int name_index = bus_name_add(s, name, i); int name_index = jb_server_name_add(s, name, i);
if (name_index < 0) { if (name_index < 0) {
return -1; return -1;
} }
@ -232,7 +162,7 @@ int bus_client_assign_own_name(bus_t *s, int i, char *name)
return 0; return 0;
} }
void bus_name_remove(bus_t *s, int i) void jb_server_name_remove(struct jb_server *s, int i)
{ {
if (i >= 0) { if (i >= 0) {
if (s->names[i].name) { if (s->names[i].name) {
@ -244,67 +174,67 @@ void bus_name_remove(bus_t *s, int i)
} }
} }
void bus_client_remove(bus_t *s, int i) void jb_server_client_remove(struct jb_server *s, int i)
{ {
bus_client_t *c = &s->clients[i]; struct jb_client *c = &s->clients[i];
if (c->fd >= 0) { if (c->fd >= 0) {
close(c->fd); close(c->fd);
} }
for (int j = 0; j < BUS_MAX_MATCH; j++) { for (int i = 0; i < JB_MAX_MATCH; i++) {
if (c->matches[j]) { if (c->matches[i]) {
match_rule_free(c->matches[j]); match_rule_free(c->matches[i]);
c->matches[j] = NULL; c->matches[i] = NULL;
} }
} }
bus_name_remove(s, c->unique_name_index); jb_server_name_remove(s, c->unique_name_index);
bus_name_remove(s, c->owned_name_index); jb_server_name_remove(s, c->owned_name_index);
c->unique_name_index = -1; c->unique_name_index = -1;
c->owned_name_index = -1; c->owned_name_index = -1;
c->match_count = 0; c->match_count = 0;
c->fd = -1; c->fd = -1;
c->state = BUS_CLIENT_STATE_NONE; c->state = JB_CLIENT_STATE_NONE;
s->fds[i].fd = -1; s->fds[i].fd = -1;
s->fds[i].events = 0; s->fds[i].events = 0;
s->fds[i].revents = 0; s->fds[i].revents = 0;
s->clients_count--; s->clients_count--;
} }
void bus_client_error(bus_t *s, int i, const char *msg) void jb_server_client_error(struct jb_server *s, int i, const char *msg)
{ {
printf("bus_client_error: %s\n", msg); printf("jb_server_client_error: %s\n", msg);
send(s->clients[i].fd, msg, strlen(msg), 0); send(s->clients[i].fd, msg, strlen(msg), 0);
bus_client_remove(s, i); jb_server_client_remove(s, i);
} }
ssize_t bus_client_recv(bus_t *s, int i, void *buf, size_t n) ssize_t jb_server_client_recv(struct jb_server *s, int i, void *buf, size_t n)
{ {
ssize_t status = recv(s->fds[i].fd, buf, n, 0); ssize_t status = recv(s->fds[i].fd, buf, n, 0);
if (status <= 0) { if (status <= 0) {
bus_client_remove(s, i); jb_server_client_remove(s, i);
} }
return status; return status;
} }
int bus_broadcast_message(bus_t *s, wire_message_t *msg, wire_context_t *ctx, char *sender_unique_name) int jb_server_broadcast_message(struct jb_server *s, wire_message_t *msg, wire_context_t *ctx, char *sender_unique_name)
{ {
int left = s->clients_count; int left = s->clients_count;
for (int i = 0; i < BUS_MAX_CLIENTS && left > 0; i++) { for (int i = 0; i < JB_MAX_CLIENTS && left > 0; i++) {
if (s->clients[i].match_count <= 0) { if (s->clients[i].match_count <= 0) {
continue; continue;
} }
left--; left--;
bus_client_t *c = &s->clients[i]; struct jb_client *c = &s->clients[i];
int match_left = c->match_count; int match_left = c->match_count;
for (int j = 0; j < BUS_MAX_MATCH && match_left > 0; j++) { for (int i = 0; i < JB_MAX_MATCH && match_left > 0; i++) {
if (!c->matches[j]) { if (!c->matches[i]) {
continue; continue;
} }
match_left--; match_left--;
if (match_rule_check(c->matches[j], msg, ctx) >= 0) { if (match_rule_check(c->matches[i], 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 = {
@ -323,9 +253,9 @@ int bus_broadcast_message(bus_t *s, wire_message_t *msg, wire_context_t *ctx, ch
return 0; return 0;
} }
int bus_unicast_message(bus_t *s, wire_message_t *msg, wire_context_t *ctx, char *target_name, char *sender_unique_name) int jb_server_unicast_message(struct jb_server *s, wire_message_t *msg, wire_context_t *ctx, char *target_name, char *sender_unique_name)
{ {
bus_client_t *target = bus_name_find_client(s, target_name); struct jb_client *target = jb_server_name_find_client(s, target_name);
if (!target) { if (!target) {
return -1; return -1;
} }
@ -345,189 +275,224 @@ 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) \
uint32_t *body_length = NULL; \ if (!(msg.flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \
uint32_t body_start = 0; \ TRYST(wire_compose_reply(&reply_ctx, &msg, (M_sig), &body_length)); \
if (!(msg->flags & DBUS_FLAG_NO_REPLY_EXPECTED)) { \ body_start = reply_ctx.byte_cursor; \
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_ctx->data, reply_ctx->byte_cursor, 0) != reply_ctx->byte_cursor) { \ if (send(s->fds[i].fd, reply_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_ctx->data, reply_ctx->byte_cursor, 0) != reply_ctx->byte_cursor) { \ if (send(s->fds[i].fd, reply_data, reply_ctx.byte_cursor, 0) != reply_ctx.byte_cursor) { \
return -1; \ return -1; \
} \ } \
} \ } \
} while(0) \ } while(0) \
int handle_hello(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { int jb_server_client_process_message(struct jb_server *s, int i, wire_context_t *ctx)
(void)ctx; {
struct jb_client *client = &s->clients[i];
int unique_name_index = TRYST(bus_client_assign_unique_name(s, i)); wire_message_t msg = {0};
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 = jb_server_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);
return 0; } 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;
} }
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_name_string(ctx));
char *name_str = TRYPTR(string_dup(name)); char *name_str = TRYPTR(string_dup(name));
int status_code = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; int status_code = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
if (bus_client_assign_own_name(s, i, name_str) < 0) { if (jb_server_client_assign_own_name(s, i, name_str) < 0) {
free(name_str); free(name_str);
// TODO: report the actual error // TODO: report the actual error
status_code = DBUS_REQUEST_NAME_REPLY_EXISTS; status_code = DBUS_REQUEST_NAME_REPLY_EXISTS;
} }
_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[s->clients[i].unique_name_index].name, i, name_str); printf("client '%s' (index=%d) now owns name '%s'\n", s->names[client->unique_name_index].name, i, name_str);
} }
return 0; } 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;
} }
int handle_get_name_owner(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { struct jb_client *target = jb_server_name_find_client(s, name);
char *name = TRYPTR(wire_get_name_string(ctx));
bus_client_t *target = bus_name_find_client(s, name);
if (!target || target->unique_name_index < 0) { if (!target || target->unique_name_index < 0) {
_reply_error("org.freedesktop.DBus.Error.NameHasNoOwner"); _reply_error("org.freedesktop.DBus.Error.NameHasNoOwner");
return 0; return 0;
} }
_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()
return 0; } 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;
} }
int handle_name_has_owner(bus_t *s, int i, wire_message_t *msg, wire_context_t *ctx, wire_context_t *reply_ctx) { struct jb_client *target = jb_server_name_find_client(s, name);
char *name = TRYPTR(wire_get_name_string(ctx));
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()
return 0; } else if (strcmp(member, "ListNames") == 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 j = 0; j < BUS_MAX_NAMES && left > 0; j++) { for (int i = 0; i < JB_MAX_NAMES && left > 0; i++) {
if (s->names[j].name && s->names[j].client_index >= 0) { if (s->names[i].name && s->names[i].client_index >= 0) {
left--; left--;
TRYPTR(wire_set_string(reply_ctx, s->names[j].name)); TRYPTR(wire_set_string(&reply_ctx, s->names[i].name));
} }
} }
*array_length = reply_ctx->byte_cursor - array_start; *array_length = reply_ctx.byte_cursor - array_start;
} _reply_end() } _reply_end()
return 0; } else if (strcmp(member, "ListActivatableNames") == 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()
return 0; } else if (strcmp(member, "StartServiceByName") == 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_name_string(ctx)); char *name = TRYPTR(wire_get_string(ctx));
int name_len = strlen(name);
if (name_len < 1 || name_len > 256) {
return -1;
}
/* unused flags value */ /* unused flags value */
TRYPTR(wire_get_u32(ctx)); TRYPTR(wire_get_u32(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()
return 0; } 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;
} }
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_check(ctx, 1, MATCH_RULE_MAX));
printf("client index %d adding match rule: '%s'\n", i, match); printf("client index %d adding match rule: '%s'\n", i, match);
TRYST(bus_client_match_add(s, i, match)); TRYST(jb_server_client_match_add(s, i, match));
_reply_begin("") {} _reply_end() _reply_begin("") {} _reply_end()
return 0; } else if (strcmp(member, "RemoveMatch") == 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_check(ctx, 1, MATCH_RULE_MAX)); 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); printf("FIXME: STUB: RemoveMatch: %s\n", match);
_reply_begin("") {} _reply_end() _reply_begin("") {} _reply_end()
return 0; } else if (strcmp(member, "GetConnectionStats") == 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()
return 0; } 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;
} }
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) { struct jb_client *target = jb_server_name_find_client(s, name);
(void)ctx;
char *name = TRYPTR(wire_get_name_string(ctx));
bus_client_t *target = bus_name_find_client(s, name);
if (!target || target->unique_name_index < 0 || target->fd < 0) { if (!target || target->unique_name_index < 0 || target->fd < 0) {
_reply_error("org.freedesktop.DBus.Error.NameHasNoOwner"); _reply_error("org.freedesktop.DBus.Error.NameHasNoOwner");
return 0; return 0;
@ -542,140 +507,96 @@ int handle_get_connection_unix_process_id(bus_t *s, int i, wire_message_t *msg,
} }
_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()
return 0; } else if (strcmp(member, "GetAllMatchRules") == 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 j = 0; j < BUS_MAX_NAMES && left > 0; j++) { for (int i = 0; i < JB_MAX_NAMES && left > 0; i++) {
bus_name_t *n = &s->names[j]; struct jb_name *n = &s->names[i];
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[j].client_index]; struct jb_client *c = &s->clients[s->names[i].client_index];
TRYPTR(wire_set_string(reply_ctx, s->names[j].name)); /* unique name */ TRYPTR(wire_set_string(&reply_ctx, s->names[i].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 k = 0; k < BUS_MAX_MATCH && match_left > 0; k++) { for (int i = 0; i < JB_MAX_MATCH && match_left > 0; i++) {
if (!c->matches[k]) { if (!c->matches[i]) {
continue; continue;
} }
match_left--; match_left--;
TRYPTR(wire_set_string(reply_ctx, c->matches[k]->rule_string)); TRYPTR(wire_set_string(&reply_ctx, c->matches[i]->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 {
printf("FIXME: daemon method '%s' is not implemented or invalid\n", member);
_reply_error("org.freedesktop.DBus.Error.UnknownMethod");
return 0; return 0;
} }
} break;
case DBUS_MESSAGE_METHOD_RETURN: {
static const bus_method_handler_t bus_method_handlers[] = { // we assume that method returns without any destination field are directed at their sender
{ "Hello", handle_hello }, // TODO: this is probably not correct
{ "RequestName", handle_request_name }, if (!destination_field->present) {
{ "GetNameOwner", handle_get_name_owner }, destination_field->t.str = s->names[client->unique_name_index].name;
{ "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]; should_forward = true;
wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER]; } break;
uint8_t reply_data[4096]; case DBUS_MESSAGE_SIGNAL: {
memset(reply_data, 0, 4096); should_forward = true;
wire_context_t reply_ctx = { } break;
.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) { default: {
// method call to the bus _reply_error("xyz.hippoz.jitterbug.NotImplemented");
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;
}
}
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; return 0;
} break;
} }
// message needs to be routed if (should_forward) {
// 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) {
if (bus_unicast_message(s, &msg, ctx, destination_field->t.str, s->names[client->unique_name_index].name) < 0) { /* unicast */
_process_message_reply_error("xyz.hippoz.jitterbug.UnicastFailed"); if (jb_server_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; return 0;
} }
} else { } else {
if (bus_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) { /* broadcast */
_process_message_reply_error("xyz.hippoz.jitterbug.BroadcastFailed"); if (jb_server_broadcast_message(s, &msg, ctx, s->names[client->unique_name_index].name) < 0) {
_reply_error("xyz.hippoz.jitterbug.BroadcastFailed");
return 0; return 0;
} }
} }
}
return 0; return 0;
} }
int bus_client_drain_messages(bus_t *s, int ci, uint8_t *data, uint32_t data_len) int jb_server_client_drain_messages(struct jb_server *s, int ci, uint8_t *data, uint32_t data_len)
{ {
wire_context_t ctx = { wire_context_t ctx = {
.byte_cursor = 0, .byte_cursor = 0,
@ -683,7 +604,7 @@ int bus_client_drain_messages(bus_t *s, int ci, uint8_t *data, uint32_t data_len
.data_len = data_len .data_len = data_len
}; };
TRYST(bus_client_process_message(s, ci, &ctx)); TRYST(jb_server_client_process_message(s, ci, &ctx));
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
if (ctx.byte_cursor >= ctx.data_len || ctx.data[ctx.byte_cursor] != 'l') { if (ctx.byte_cursor >= ctx.data_len || ctx.data[ctx.byte_cursor] != 'l') {
@ -693,14 +614,84 @@ int bus_client_drain_messages(bus_t *s, int ci, uint8_t *data, uint32_t data_len
ctx.data = ctx.data + ctx.byte_cursor; ctx.data = ctx.data + ctx.byte_cursor;
ctx.data_len = ctx.data_len - ctx.byte_cursor; ctx.data_len = ctx.data_len - ctx.byte_cursor;
ctx.byte_cursor = 0; ctx.byte_cursor = 0;
TRYST(bus_client_process_message(s, ci, &ctx)); TRYST(jb_server_client_process_message(s, ci, &ctx));
} }
return 0; return 0;
} }
#define _client_die(m) ({bus_client_error(s,i,m);continue;}) void jb_server_free(struct jb_server *s)
int bus_turn(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 < JB_MAX_CLIENTS; i++) {
jb_server_client_remove(s, i);
}
free(s);
}
struct jb_server *jb_server_create(const char *socket_path)
{
struct jb_server *s = malloc(sizeof(struct jb_server));
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, JB_BACKLOG) == -1) {
close(s->sock_fd);
free(s);
return NULL;
}
for (int i = 0; i < JB_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 = JB_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 < JB_MAX_MATCH; j++) {
s->clients[i].matches[j] = NULL;
}
}
for (int i = 0; i < JB_MAX_NAMES; i++) {
s->names[i].client_index = -1;
s->names[i].name = NULL;
}
s->names_count = 0;
s->clients_count = 0;
s->fds[JB_MAX_CLIENTS].fd = s->sock_fd;
s->fds[JB_MAX_CLIENTS].events = POLLIN;
s->fd_num = JB_MAX_CLIENTS + 1;
return s;
}
#define _client_die(m) ({jb_server_client_error(s,i,m);continue;})
int jb_server_turn(struct jb_server *s)
{ {
static const char agree_unix_fd[] = "AGREE_UNIX_FD\r\n"; static const char agree_unix_fd[] = "AGREE_UNIX_FD\r\n";
static const char auth_ok[] = "OK aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"; static const char auth_ok[] = "OK aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n";
@ -723,23 +714,23 @@ int bus_turn(bus_t *s)
for (int i = 0; i < s->fd_num; i++) { for (int i = 0; i < s->fd_num; i++) {
int fd = s->fds[i].fd; int fd = s->fds[i].fd;
if (s->fds[i].revents & POLLNVAL) { if (s->fds[i].revents & POLLNVAL) {
fprintf(stderr, "bus_turn: error: got POLLNVAL for fds[%d]. This is considered a bug in the server implementation.\n", i); fprintf(stderr, "jb_server_turn: error: got POLLNVAL for fds[%d]. This is considered a bug in the server implementation.\n", i);
return -1; return -1;
} }
if (s->fds[i].revents & POLLERR) { if (s->fds[i].revents & POLLERR) {
if (fd == s->sock_fd) { if (fd == s->sock_fd) {
fprintf(stderr, "bus_turn: error: got POLLERR for sock_fd\n"); fprintf(stderr, "jb_server_turn: error: got POLLERR for sock_fd\n");
return -1; return -1;
} }
bus_client_remove(s, i); jb_server_client_remove(s, i);
continue; continue;
} }
if (s->fds[i].revents & POLLHUP) { if (s->fds[i].revents & POLLHUP) {
if (fd == s->sock_fd) { if (fd == s->sock_fd) {
fprintf(stderr, "bus_turn: error: got POLLHUP for sock_fd\n"); fprintf(stderr, "jb_server_turn: error: got POLLHUP for sock_fd\n");
return -1; return -1;
} }
bus_client_remove(s, i); jb_server_client_remove(s, i);
continue; continue;
} }
if (s->fds[i].revents & POLLIN) { if (s->fds[i].revents & POLLIN) {
@ -747,10 +738,10 @@ int bus_turn(bus_t *s)
if (fd == s->sock_fd) { if (fd == s->sock_fd) {
// new connection // new connection
int accepted_fd = TRYST(accept(s->sock_fd, NULL, NULL)); int fd = TRYST(accept(s->sock_fd, NULL, NULL));
if (bus_client_add(s, accepted_fd) == -1) { if (jb_server_client_add(s, fd) == -1) {
close(accepted_fd); close(fd);
} }
continue; continue;
} }
@ -762,15 +753,15 @@ int bus_turn(bus_t *s)
if (bytes <= 0) { if (bytes <= 0) {
// error during recv() OR client disconnected, disconnect the client // error during recv() OR client disconnected, disconnect the client
// TODO: should we actually do this? // TODO: should we actually do this?
bus_client_remove(s, i); jb_server_client_remove(s, i);
continue; continue;
} }
printf("\nrecv: got %zd bytes\n", bytes); printf("\nrecv: got %zd bytes\n", bytes);
bus_client_t *c = &s->clients[i]; struct jb_client *c = &s->clients[i];
switch (c->state) { switch (c->state) {
case BUS_CLIENT_STATE_WAIT_AUTH: { case JB_CLIENT_STATE_WAIT_AUTH: {
// The D-Bus authentication protocol is a simple plain text protocol. // The D-Bus authentication protocol is a simple plain text protocol.
// Before the flow of messages can begin, the two applications must authenticate. // Before the flow of messages can begin, the two applications must authenticate.
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol // SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol
@ -787,23 +778,23 @@ int bus_turn(bus_t *s)
send(fd, auth_list, sizeof(auth_list) - 1, 0); send(fd, auth_list, sizeof(auth_list) - 1, 0);
} else if (strcmp(auth_string, "AUTH EXTERNAL 31303030\r\n") == 0 || strcmp(auth_string, "DATA\r\n") == 0) { } else if (strcmp(auth_string, "AUTH EXTERNAL 31303030\r\n") == 0 || strcmp(auth_string, "DATA\r\n") == 0) {
send(fd, auth_ok, sizeof(auth_ok) - 1, 0); send(fd, auth_ok, sizeof(auth_ok) - 1, 0);
c->state = BUS_CLIENT_STATE_WAIT_BEGIN; c->state = JB_CLIENT_STATE_WAIT_BEGIN;
} else if (strcmp(auth_string, "AUTH EXTERNAL\r\n") == 0) { } else if (strcmp(auth_string, "AUTH EXTERNAL\r\n") == 0) {
send(fd, auth_data, sizeof(auth_data) - 1, 0); send(fd, auth_data, sizeof(auth_data) - 1, 0);
} }
} break; } break;
case BUS_CLIENT_STATE_WAIT_BEGIN: { case JB_CLIENT_STATE_WAIT_BEGIN: {
// Right now, we're expecting the client to either immediately begin the connection, // Right now, we're expecting the client to either immediately begin the connection,
// or to negotiate UNIX file descriptor passing. // or to negotiate UNIX file descriptor passing.
if (strncmp(data, "BEGIN\r\n", 7) == 0) { if (strncmp(data, "BEGIN\r\n", 7) == 0) {
c->state = BUS_CLIENT_STATE_READY; c->state = JB_CLIENT_STATE_READY;
// At this point, a D-Bus connection has been established. // At this point, a D-Bus connection has been established.
// The first octet after the \r\n of the BEGIN command is the first octet of the D-Bus communication. // The first octet after the \r\n of the BEGIN command is the first octet of the D-Bus communication.
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-command-begin // SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#auth-command-begin
char *first_message_begin = data + 7; /* 7 = length of "BEGIN\r\n" */ char *first_message_begin = data + 7; /* 7 = length of "BEGIN\r\n" */
if (*first_message_begin == 'l' || *first_message_begin == 'B') { if (*first_message_begin == 'l' || *first_message_begin == 'B') {
// This looks like a D-Bus message. Let's process it! // This looks like a D-Bus message. Let's process it!
if (bus_client_drain_messages(s, i, (uint8_t *)first_message_begin, data_buffer_len - 7) < 0) { if (jb_server_client_drain_messages(s, i, (uint8_t *)first_message_begin, data_buffer_len - 7) < 0) {
_client_die("failed to process message"); _client_die("failed to process message");
} }
} }
@ -815,13 +806,13 @@ int bus_turn(bus_t *s)
} }
} break; } break;
case BUS_CLIENT_STATE_READY: { case JB_CLIENT_STATE_READY: {
if (bus_client_drain_messages(s, i, (uint8_t*)data, data_buffer_len) < 0) { if (jb_server_client_drain_messages(s, i, (uint8_t*)data, data_buffer_len) < 0) {
_client_die("failed to process message"); _client_die("failed to process message");
} }
} break; } break;
case BUS_CLIENT_STATE_NONE: {} /* through */ case JB_CLIENT_STATE_NONE: {} /* through */
default: { default: {
_client_die("bad state"); _client_die("bad state");
} break; } break;

View file

@ -2,58 +2,52 @@
#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>
// TODO: dynamically size the arrays // TODO: dynamically size the arrays
#define BUS_MAX_CLIENTS 256 #define JB_MAX_CLIENTS 256
#define BUS_MAX_NAMES 512 #define JB_MAX_NAMES 512
#define BUS_MAX_MATCH 12 #define JB_MAX_MATCH 12
#define BUS_BACKLOG 12 #define JB_BACKLOG 12
enum { enum {
BUS_CLIENT_STATE_NONE, JB_CLIENT_STATE_NONE,
BUS_CLIENT_STATE_WAIT_AUTH, JB_CLIENT_STATE_WAIT_AUTH,
BUS_CLIENT_STATE_WAIT_BEGIN, JB_CLIENT_STATE_WAIT_BEGIN,
BUS_CLIENT_STATE_READY JB_CLIENT_STATE_READY
}; };
typedef struct bus_client { struct jb_client {
int fd; int fd;
uint8_t state; uint8_t state;
int16_t unique_name_index; int16_t unique_name_index;
int16_t owned_name_index; int16_t owned_name_index;
int8_t match_count; int8_t match_count;
match_rule_t *matches[BUS_MAX_MATCH]; match_rule_t *matches[JB_MAX_MATCH];
} bus_client_t; };
typedef struct bus_name { struct jb_name {
char *name; char *name;
int32_t client_index; int32_t client_index;
} bus_name_t; };
typedef struct bus { struct jb_server {
int sock_fd; int sock_fd;
int fd_num; int fd_num;
int names_count; int names_count;
int clients_count; int clients_count;
bus_client_t clients[BUS_MAX_CLIENTS]; struct jb_client clients[JB_MAX_CLIENTS];
bus_name_t names[BUS_MAX_NAMES]; struct jb_name names[JB_MAX_NAMES];
struct pollfd fds[BUS_MAX_CLIENTS + 1]; struct pollfd fds[JB_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); int jb_server_client_add(struct jb_server *s, int fd);
void bus_client_remove(bus_t *s, int i); void jb_server_client_remove(struct jb_server *s, int i);
void bus_free(bus_t *s); void jb_server_free(struct jb_server *s);
bus_t *bus_create(const char *socket_path); struct jb_server *jb_server_create(const char *socket_path);
int bus_turn(bus_t *s); int jb_server_turn(struct jb_server *s);
#endif // _JITTERBUG__SERVER_H #endif // _JITTERBUG__SERVER_H

7
wire.c
View file

@ -100,13 +100,6 @@ char *wire_set_string_impl(wire_context_t *c, const char *str, bool as_signature
return dest; return dest;
} }
char *wire_get_string_check(wire_context_t *c, int min_length, int max_length) {
char *str = TRYPTR_NIL(wire_get_string_impl(c, false));
int length = strlen(str);
if (length < min_length || length > max_length) return NULL;
return str;
}
int wire_parse_message(wire_context_t *c, wire_message_t *msg) int wire_parse_message(wire_context_t *c, wire_message_t *msg)
{ {
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages // SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages

6
wire.h
View file

@ -123,7 +123,6 @@ _WIRE_DECL_TYPE(boolean, uint32_t, 4);
char *wire_get_string_impl(wire_context_t *c, bool as_signature); char *wire_get_string_impl(wire_context_t *c, bool as_signature);
char *wire_set_string_impl(wire_context_t *c, const char *str, bool as_signature); char *wire_set_string_impl(wire_context_t *c, const char *str, bool as_signature);
char *wire_get_string_check(wire_context_t *c, int min_length, int max_length);
int wire_parse_message(wire_context_t *c, wire_message_t *msg); int wire_parse_message(wire_context_t *c, wire_message_t *msg);
int wire_compose_reply(wire_context_t *c, wire_message_t *msg, const char *signature, uint32_t **out_body_length); int wire_compose_reply(wire_context_t *c, wire_message_t *msg, const char *signature, uint32_t **out_body_length);
int wire_compose_error(wire_context_t *c, wire_message_t *msg, const char *error_name); int wire_compose_error(wire_context_t *c, wire_message_t *msg, const char *error_name);
@ -146,10 +145,5 @@ static inline char *wire_set_string(wire_context_t *c, const char *str) {
return wire_set_string_impl(c, str, false); return wire_set_string_impl(c, str, false);
} }
// maximum name length is 255
static inline char *wire_get_name_string(wire_context_t *c) {
return wire_get_string_check(c, 1, 255);
}
#endif // _JITTERBUG__WIRE_H #endif // _JITTERBUG__WIRE_H