basic unicast relay mechanism
This commit is contained in:
parent
36162d106e
commit
ec156a1b14
4 changed files with 234 additions and 89 deletions
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
||||||
CC?=gcc
|
CC?=gcc
|
||||||
CFLAGS+=-Werror -Wall -Wextra -std=c99
|
CFLAGS+=-Werror -Wall -Wextra -std=c99 -ggdb
|
||||||
|
|
||||||
jitterbug: wire.c server.c main.c
|
jitterbug: wire.c server.c main.c
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
90
server.c
90
server.c
|
@ -60,6 +60,24 @@ int jb_server_name_find(struct jb_server *s, char *name)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct jb_client *jb_server_name_find_client(struct jb_server *s, char *name)
|
||||||
|
{
|
||||||
|
int name_index = jb_server_name_find(s, name);
|
||||||
|
if (name_index < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->names[name_index].client_index < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->clients[s->names[name_index].client_index].state != JB_CLIENT_STATE_READY) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &s->clients[s->names[name_index].client_index];
|
||||||
|
}
|
||||||
|
|
||||||
int jb_server_name_add(struct jb_server *s, char *name, int client_index)
|
int jb_server_name_add(struct jb_server *s, char *name, int client_index)
|
||||||
{
|
{
|
||||||
if (jb_server_name_find(s, name) >= 0) {
|
if (jb_server_name_find(s, name) >= 0) {
|
||||||
|
@ -185,31 +203,33 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
|
|
||||||
TRY_NONNEGATIVE(int, wire_parse_message(&ctx, &msg), -1);
|
TRY_NONNEGATIVE(int, wire_parse_message(&ctx, &msg), -1);
|
||||||
|
|
||||||
uint8_t reply_data[512];
|
uint8_t reply_data[4096];
|
||||||
memset(reply_data, 0, 512);
|
memset(reply_data, 0, 4096);
|
||||||
wire_context_t reply_ctx = {
|
wire_context_t reply_ctx = {
|
||||||
.byte_cursor = 0,
|
.byte_cursor = 0,
|
||||||
.data = reply_data,
|
.data = reply_data,
|
||||||
.data_len = 511,
|
.data_len = 4096,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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_unicast = false;
|
||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case DBUS_MESSAGE_METHOD_CALL: {
|
case DBUS_MESSAGE_METHOD_CALL: {
|
||||||
bool for_dbus = false;
|
if (!destination_field->present || !member_field->present) {
|
||||||
char *member;
|
return -1;
|
||||||
|
}
|
||||||
// TODO: maybe the fields in the msg.fields array should be indexed based on their type?
|
|
||||||
for (int i = 0; i < msg.header_fields_count; i++) {
|
char *member = member_field->t.str;
|
||||||
if (msg.fields[i].type == DBUS_HEADER_FIELD_DESTINATION) {
|
|
||||||
if (strcmp(msg.fields[i].t.str, "org.freedesktop.DBus") == 0) {
|
if (strcmp(destination_field->t.str, "org.freedesktop.DBus") != 0) {
|
||||||
for_dbus = true;
|
// not for dbus.
|
||||||
}
|
should_unicast = true;
|
||||||
} else if (msg.fields[i].type == DBUS_HEADER_FIELD_MEMBER) {
|
break;
|
||||||
member = msg.fields[i].t.str;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (for_dbus) {
|
|
||||||
if (strcmp(member, "Hello") == 0) {
|
if (strcmp(member, "Hello") == 0) {
|
||||||
int unique_name_index = jb_server_client_assign_unique_name(s, i);
|
int unique_name_index = jb_server_client_assign_unique_name(s, i);
|
||||||
if (unique_name_index < 0) {
|
if (unique_name_index < 0) {
|
||||||
|
@ -263,12 +283,18 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} break;
|
||||||
printf("jb_server_client_process_message: skipping message not for dbus for now\n");
|
|
||||||
|
case DBUS_MESSAGE_METHOD_RETURN: {
|
||||||
|
if (!destination_field->present) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
should_unicast = true;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
printf("xyz.hippoz.jitterbug.NotImplemented\n");
|
||||||
TRY_NONNEGATIVE(int, wire_compose_error(&reply_ctx, &msg, "xyz.hippoz.jitterbug.NotImplemented"), -1);
|
TRY_NONNEGATIVE(int, wire_compose_error(&reply_ctx, &msg, "xyz.hippoz.jitterbug.NotImplemented"), -1);
|
||||||
if (send(s->fds[i].fd, reply_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;
|
||||||
|
@ -277,6 +303,30 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (should_unicast) {
|
||||||
|
if (client->unique_name_index < 0 || !destination_field->present) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("sending unicast message from %s\n", s->names[client->unique_name_index].name);
|
||||||
|
struct jb_client *target = jb_server_name_find_client(s, destination_field->t.str);
|
||||||
|
if (!target) {
|
||||||
|
uint8_t error_reply_data[512];
|
||||||
|
memset(error_reply_data, 0, 512);
|
||||||
|
wire_context_t error_reply_ctx = {
|
||||||
|
.byte_cursor = 0,
|
||||||
|
.data = error_reply_data,
|
||||||
|
.data_len = 511,
|
||||||
|
};
|
||||||
|
TRY_NONNEGATIVE(int, wire_compose_error(&error_reply_ctx, &msg, "xyz.hippoz.jitterbug.NotImplemented"), -1);
|
||||||
|
if (send(s->fds[i].fd, error_reply_data, error_reply_ctx.byte_cursor, 0) != error_reply_ctx.byte_cursor) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
TRY_NONNEGATIVE(int, wire_compose_unicast_reply(&reply_ctx, &ctx, &msg, s->names[client->unique_name_index].name), -1);
|
||||||
|
TRY_NONNEGATIVE(int, send(target->fd, reply_data, reply_ctx.byte_cursor, 0), -1);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +395,7 @@ 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 1234deadbeef\r\n";
|
static const char auth_ok[] = "OK 1234deadbeef\r\n";
|
||||||
static const int data_buffer_len = 256;
|
static const int data_buffer_len = 4096;
|
||||||
|
|
||||||
TRY_NONNEGATIVE(int, poll(s->fds, s->fd_num, -1), -1);
|
TRY_NONNEGATIVE(int, poll(s->fds, s->fd_num, -1), -1);
|
||||||
|
|
||||||
|
@ -395,7 +445,7 @@ int jb_server_turn(struct jb_server *s)
|
||||||
|
|
||||||
char *auth_string = data + 1;
|
char *auth_string = data + 1;
|
||||||
|
|
||||||
if (strcmp(auth_string, "AUTH EXTERNAL 31303030\r\n") != 0)
|
if (strcmp(auth_string, "AUTH EXTERNAL 31303030\r\n") != 0 && strcmp(auth_string, "AUTH\r\n") != 0)
|
||||||
_client_die("bad auth");
|
_client_die("bad auth");
|
||||||
send(fd, auth_ok, sizeof(auth_ok) - 1, 0);
|
send(fd, auth_ok, sizeof(auth_ok) - 1, 0);
|
||||||
c->state = JB_CLIENT_STATE_WAIT_BEGIN;
|
c->state = JB_CLIENT_STATE_WAIT_BEGIN;
|
||||||
|
|
137
wire.c
137
wire.c
|
@ -130,44 +130,37 @@ int wire_parse_message(wire_context_t *c, wire_message_t *msg)
|
||||||
|
|
||||||
size_t header_fields_end = c->byte_cursor + msg->header_fields_length;
|
size_t header_fields_end = c->byte_cursor + msg->header_fields_length;
|
||||||
|
|
||||||
|
printf(" > start parse!\n");
|
||||||
|
|
||||||
while (c->byte_cursor < header_fields_end) {
|
while (c->byte_cursor < header_fields_end) {
|
||||||
uint8_t field_code = *TRY_NONNULL(uint8_t*, wire_get_u8(c), -1);
|
uint8_t field_code = *TRY_NONNULL(uint8_t*, wire_get_u8(c), -1);
|
||||||
TRY_NONNULL(char*, wire_get_signature(c, NULL), -1);
|
TRY_NONNULL(char*, wire_get_signature(c, NULL), -1);
|
||||||
|
|
||||||
msg->fields[msg->header_fields_count].type = field_code;
|
|
||||||
|
|
||||||
switch (field_code) {
|
switch (field_code) {
|
||||||
case DBUS_HEADER_FIELD_PATH: {
|
case DBUS_HEADER_FIELD_PATH: /* through */
|
||||||
char *str = TRY_NONNULL(char*, wire_get_string(c, NULL), -1);
|
case DBUS_HEADER_FIELD_INTERFACE: /* through */
|
||||||
msg->fields[msg->header_fields_count].t.str = str;
|
case DBUS_HEADER_FIELD_MEMBER: /* through */
|
||||||
printf("DBUS_HEADER_FIELD_PATH: %s\n", str);
|
|
||||||
} break;
|
|
||||||
case DBUS_HEADER_FIELD_INTERFACE: {
|
|
||||||
char *str = TRY_NONNULL(char*, wire_get_string(c, NULL), -1);
|
|
||||||
msg->fields[msg->header_fields_count].t.str = str;
|
|
||||||
printf("DBUS_HEADER_FIELD_INTERFACE: %s\n", str);
|
|
||||||
} break;
|
|
||||||
case DBUS_HEADER_FIELD_MEMBER: {
|
|
||||||
char *str = TRY_NONNULL(char*, wire_get_string(c, NULL), -1);
|
|
||||||
msg->fields[msg->header_fields_count].t.str = str;
|
|
||||||
printf("DBUS_HEADER_FIELD_MEMBER: %s\n", str);
|
|
||||||
} break;
|
|
||||||
case DBUS_HEADER_FIELD_DESTINATION: {
|
case DBUS_HEADER_FIELD_DESTINATION: {
|
||||||
char *str = TRY_NONNULL(char*, wire_get_string(c, NULL), -1);
|
char *str = TRY_NONNULL(char*, wire_get_string(c, NULL), -1);
|
||||||
msg->fields[msg->header_fields_count].t.str = str;
|
printf("field: %s\n", str);
|
||||||
printf("DBUS_HEADER_FIELD_DESTINATION: %s\n", str);
|
msg->fields[field_code].t.str = str;
|
||||||
} break;
|
} break;
|
||||||
case DBUS_HEADER_FIELD_SIGNATURE: {
|
case DBUS_HEADER_FIELD_SIGNATURE: {
|
||||||
char *str = TRY_NONNULL(char*, wire_get_signature(c, NULL), -1);
|
char *str = TRY_NONNULL(char*, wire_get_signature(c, NULL), -1);
|
||||||
msg->fields[msg->header_fields_count].t.str = str;
|
printf("field: %s\n", str);
|
||||||
printf("DBUS_HEADER_FIELD_SIGNATURE: %s\n", str);
|
msg->fields[field_code].t.str = str;
|
||||||
|
} break;
|
||||||
|
case DBUS_HEADER_FIELD_REPLY_SERIAL: {
|
||||||
|
uint32_t u = *TRY_NONNULL(uint32_t*, wire_get_u32(c), -1);
|
||||||
|
printf("field: %d\n", u);
|
||||||
|
msg->fields[field_code].t.u32 = u;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
printf("header: unknown field: %d\n", field_code);
|
printf("header: unknown field: %d\n", field_code);
|
||||||
return -1;
|
return -1;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
msg->fields[field_code].present = true;
|
||||||
|
|
||||||
// Structs are always aligned to `8`.
|
// Structs are always aligned to `8`.
|
||||||
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#id-1.4.6
|
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#id-1.4.6
|
||||||
|
@ -178,6 +171,8 @@ int wire_parse_message(wire_context_t *c, wire_message_t *msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf(" > parsed!!\n");
|
||||||
|
|
||||||
/* header ends at 8 byte boundry */
|
/* header ends at 8 byte boundry */
|
||||||
TRY_NONNULL(bool, wire_align(c, 8), -1);
|
TRY_NONNULL(bool, wire_align(c, 8), -1);
|
||||||
|
|
||||||
|
@ -285,3 +280,101 @@ int wire_compose_error(wire_context_t *c, wire_message_t *msg, const char *error
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_message_t *msg, char *sender_unique_name)
|
||||||
|
{
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, msg->endianness), -1); /* endianness */
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, msg->type), -1); /* type */
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, 0), -1); /* flags */
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_PROTOCOL_VERSION), -1); /* protocol_version */
|
||||||
|
TRY_NONNULL(uint32_t*, wire_set_u32(c, msg->body_length), -1); /* body length */
|
||||||
|
TRY_NONNULL(uint32_t*, wire_set_u32(c, msg->serial), -1); /* serial */
|
||||||
|
uint32_t *header_fields_length = TRY_NONNULL(uint32_t*, wire_set_u32(c, 0), -1); /* header_fields_length */
|
||||||
|
|
||||||
|
uint32_t header_fields_start = c->byte_cursor;
|
||||||
|
|
||||||
|
switch (msg->type) {
|
||||||
|
case DBUS_MESSAGE_METHOD_CALL: {
|
||||||
|
// these fields are required for DBUS_MESSAGE_METHOD_CALL, so we must (hackily) check for their presence
|
||||||
|
// interface is not strictly required by the spec, however we require it here anyways
|
||||||
|
wire_message_field_t *path_field = &msg->fields[DBUS_HEADER_FIELD_PATH];
|
||||||
|
wire_message_field_t *interface_field = &msg->fields[DBUS_HEADER_FIELD_INTERFACE];
|
||||||
|
wire_message_field_t *member_field = &msg->fields[DBUS_HEADER_FIELD_MEMBER];
|
||||||
|
wire_message_field_t *signature_field = &msg->fields[DBUS_HEADER_FIELD_SIGNATURE];
|
||||||
|
if (!path_field->present || !interface_field->present || !interface_field->present) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_PATH), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "o"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_string(c, path_field->t.str), -1);
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_INTERFACE), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "s"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_string(c, interface_field->t.str), -1);
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_MEMBER), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "s"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_string(c, member_field->t.str), -1);
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
|
||||||
|
if (signature_field->present) {
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "g"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, signature_field->t.str), -1);
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_SENDER), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "s"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_string(c, sender_unique_name), -1);
|
||||||
|
// last element, don't align
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DBUS_MESSAGE_METHOD_RETURN: {
|
||||||
|
wire_message_field_t *reply_serial_field = &msg->fields[DBUS_HEADER_FIELD_REPLY_SERIAL];
|
||||||
|
if (!reply_serial_field->present) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_REPLY_SERIAL), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "u"), -1);
|
||||||
|
TRY_NONNULL(uint32_t*, wire_set_u32(c, reply_serial_field->t.u32), -1);
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
|
||||||
|
wire_message_field_t *signature_field = &msg->fields[DBUS_HEADER_FIELD_SIGNATURE];
|
||||||
|
if (signature_field->present) {
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_SIGNATURE), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "g"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_string(c, signature_field->t.str), -1);
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_NONNULL(uint8_t*, wire_set_u8(c, DBUS_HEADER_FIELD_SENDER), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_signature(c, "s"), -1);
|
||||||
|
TRY_NONNULL(char*, wire_set_string(c, sender_unique_name), -1);
|
||||||
|
// last element, don't align
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return -1;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*header_fields_length = c->byte_cursor - header_fields_start;
|
||||||
|
|
||||||
|
// header ends on an 8 byte alignment
|
||||||
|
TRY_NONNULL(bool, wire_write_align(c, 8), -1);
|
||||||
|
|
||||||
|
if (c->byte_cursor + msg->body_length > c->data_len) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&c->data[c->byte_cursor], &msg_c->data[msg_c->byte_cursor], msg->body_length);
|
||||||
|
c->byte_cursor += msg->body_length;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
4
wire.h
4
wire.h
|
@ -52,9 +52,10 @@ typedef struct wire_context {
|
||||||
|
|
||||||
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
|
// SPEC: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
|
||||||
typedef struct wire_message_field {
|
typedef struct wire_message_field {
|
||||||
uint8_t type;
|
bool present;
|
||||||
union {
|
union {
|
||||||
char *str;
|
char *str;
|
||||||
|
uint32_t u32;
|
||||||
} t;
|
} t;
|
||||||
} wire_message_field_t;
|
} wire_message_field_t;
|
||||||
#define WIRE_MESSAGE_MAX_HEADER_FIELDS 9
|
#define WIRE_MESSAGE_MAX_HEADER_FIELDS 9
|
||||||
|
@ -128,5 +129,6 @@ char *wire_set_signature(wire_context_t *c, const char *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);
|
||||||
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);
|
||||||
|
int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_message_t *msg, char *sender_unique_name);
|
||||||
|
|
||||||
#endif // _JITTERBUG__WIRE_H
|
#endif // _JITTERBUG__WIRE_H
|
||||||
|
|
Loading…
Reference in a new issue