very barebones match implementation
This commit is contained in:
parent
fb2ea18aad
commit
2a07d8dd38
10 changed files with 459 additions and 44 deletions
4
Makefile
4
Makefile
|
@ -1,5 +1,5 @@
|
||||||
CC?=gcc
|
CC?=gcc
|
||||||
CFLAGS+=-Werror -Wall -Wextra -std=c99 -ggdb -fsanitize=address
|
CFLAGS+=-Wall -Wextra -std=c99 -ggdb -fsanitize=address
|
||||||
|
|
||||||
jitterbug: wire.c server.c main.c
|
jitterbug: util.c wire.c match.c server.c main.c
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
1
main.c
1
main.c
|
@ -3,6 +3,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include "match.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
const char *arg_shift(int *argc, char ***argv) {
|
const char *arg_shift(int *argc, char ***argv) {
|
||||||
|
|
204
match.c
Normal file
204
match.c
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "match.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "wire.h"
|
||||||
|
#include "try.h"
|
||||||
|
|
||||||
|
void match_rule_free(match_rule_t *rule)
|
||||||
|
{
|
||||||
|
if (rule) {
|
||||||
|
free(rule->sender);
|
||||||
|
free(rule->interface);
|
||||||
|
free(rule->member);
|
||||||
|
free(rule->path);
|
||||||
|
free(rule->path_namespace);
|
||||||
|
free(rule->destination);
|
||||||
|
free(rule->arg0namespace);
|
||||||
|
for (int i = 0; i < MATCH_RULE_MAX_ARG; i++) {
|
||||||
|
free(rule->arg[i]);
|
||||||
|
free(rule->arg_path[i]);
|
||||||
|
}
|
||||||
|
free(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match_rule_t *match_rule_from_string(char *d)
|
||||||
|
{
|
||||||
|
char *key = NULL;
|
||||||
|
char acc[MATCH_RULE_MAX];
|
||||||
|
int acci = 0;
|
||||||
|
match_rule_t *rule;
|
||||||
|
|
||||||
|
if (strlen(d) >= MATCH_RULE_MAX) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rule = calloc(sizeof(match_rule_t), 1);
|
||||||
|
if (!rule) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*d) {
|
||||||
|
/* key */
|
||||||
|
key = d;
|
||||||
|
while (*d && *d != '=') d++;
|
||||||
|
if (*d != '=') {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
*d = '\0';
|
||||||
|
d++;
|
||||||
|
if (!*d) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* value */
|
||||||
|
bool quote = false;
|
||||||
|
acci = 0;
|
||||||
|
acc[acci] = '\0';
|
||||||
|
for (;;) {
|
||||||
|
if (*d == '\'') {
|
||||||
|
/* '\'' starts a quoted region */
|
||||||
|
quote = !quote;
|
||||||
|
d++;
|
||||||
|
} else if (!quote && *d == ',') {
|
||||||
|
/* ',' outside quoted region means next key-value pair */
|
||||||
|
acc[acci] = '\0';
|
||||||
|
acci = 0;
|
||||||
|
d++;
|
||||||
|
break;
|
||||||
|
} else if (!quote && *d == '\\') {
|
||||||
|
/* '\\' outside quoted region means escaped character */
|
||||||
|
/* TODO: not entirely to spec */
|
||||||
|
d++;
|
||||||
|
if (*d != '\'') {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (acci >= MATCH_RULE_MAX) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
acc[acci++] = *d;
|
||||||
|
d++;
|
||||||
|
} else if (!*d) {
|
||||||
|
/* end of string */
|
||||||
|
if (quote) {
|
||||||
|
/* end of string, yet we were insinde a quoted region */
|
||||||
|
/* unexpected end of input */
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
acc[acci] = '\0';
|
||||||
|
acci = 0;
|
||||||
|
break;
|
||||||
|
} else if (quote) {
|
||||||
|
if (acci >= MATCH_RULE_MAX) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
acc[acci++] = *d;
|
||||||
|
d++;
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, "type") == 0 && !rule->type) {
|
||||||
|
if (strcmp(acc, "signal") == 0) rule->type = DBUS_MESSAGE_SIGNAL;
|
||||||
|
else if (strcmp(acc, "method_call") == 0) rule->type = DBUS_MESSAGE_METHOD_CALL;
|
||||||
|
else if (strcmp(acc, "method_return") == 0) rule->type = DBUS_MESSAGE_METHOD_RETURN;
|
||||||
|
else if (strcmp(acc, "error") == 0) rule->type = DBUS_MESSAGE_ERROR;
|
||||||
|
else goto fail;
|
||||||
|
} else if (strcmp(key, "sender") == 0 && !rule->sender) {
|
||||||
|
rule->sender = string_dup(acc);
|
||||||
|
} else if (strcmp(key, "interface") == 0 && !rule->interface) {
|
||||||
|
rule->interface = string_dup(acc);
|
||||||
|
} else if (strcmp(key, "member") == 0 && !rule->member) {
|
||||||
|
rule->member = string_dup(acc);
|
||||||
|
} else if (strcmp(key, "path") == 0 && !rule->path && !rule->path_namespace) {
|
||||||
|
rule->path = string_dup(acc);
|
||||||
|
} else if (strcmp(key, "path_namespace") == 0 && !rule->path && !rule->path_namespace) {
|
||||||
|
rule->path_namespace = string_dup(acc);
|
||||||
|
} else if (strcmp(key, "destination") == 0 && !rule->destination) {
|
||||||
|
rule->destination = string_dup(acc);
|
||||||
|
} else if (strcmp(key, "arg0namespace") == 0 && !rule->arg0namespace) {
|
||||||
|
rule->arg0namespace = string_dup(acc);
|
||||||
|
} else if (strncmp(key, "arg", 3) == 0) {
|
||||||
|
char *part = key + 3;
|
||||||
|
if (!*part) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thanks: https://github.com/bus1/dbus-broker/blob/55fe5443d88ee2b93afa340b82ad89508ff017e2/src/bus/match.c#L105
|
||||||
|
size_t partn = strlen(part);
|
||||||
|
uint32_t index = 0;
|
||||||
|
for (unsigned int i = 0; i < 2 && partn; i++, part++, --partn) {
|
||||||
|
if (*part >= '0' && *part <= '9') {
|
||||||
|
index = index * 10 + *part - '0';
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0 && rule->arg0namespace) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (index >= MATCH_RULE_MAX_ARG) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (rule->arg[index] || rule->arg_path[index]) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*part == '\0') {
|
||||||
|
rule->arg[index] = string_dup(acc);
|
||||||
|
} else if (strcmp(part, "path") == 0) {
|
||||||
|
rule->arg_path[index] = string_dup(acc);
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule;
|
||||||
|
fail:
|
||||||
|
match_rule_free(rule);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _check_header_field_str(M_rule_field, M_header_field) \
|
||||||
|
do { \
|
||||||
|
if (rule->M_rule_field && (!msg->fields[M_header_field].present || strcmp(rule->M_rule_field, msg->fields[M_header_field].t.str) != 0)) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
int match_rule_check(match_rule_t *rule, wire_message_t *msg, wire_context_t *ctx)
|
||||||
|
{
|
||||||
|
if (rule->type && msg->type != rule->type) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_check_header_field_str(sender, DBUS_HEADER_FIELD_SENDER);
|
||||||
|
_check_header_field_str(interface, DBUS_HEADER_FIELD_INTERFACE);
|
||||||
|
_check_header_field_str(member, DBUS_HEADER_FIELD_MEMBER);
|
||||||
|
_check_header_field_str(path, DBUS_HEADER_FIELD_PATH);
|
||||||
|
/* todo: path_namespace */
|
||||||
|
_check_header_field_str(destination, DBUS_HEADER_FIELD_DESTINATION);
|
||||||
|
|
||||||
|
wire_message_body_string_t strings[MATCH_RULE_MAX_ARG];
|
||||||
|
memset(strings, 0, sizeof(strings));
|
||||||
|
TRYST(wire_collect_strings(ctx, msg, strings, MATCH_RULE_MAX_ARG));
|
||||||
|
|
||||||
|
for (int i = 0; i < MATCH_RULE_MAX_ARG; i++) {
|
||||||
|
if (rule->arg[i] && (!strings[i].str || strcmp(strings[i].str, rule->arg[i]) != 0)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* todo: arg_path */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* todo: arg0namespace */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
23
match.h
Normal file
23
match.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef _JITTERBUG__MATCH_H
|
||||||
|
#define _JITTERBUG__MATCH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "wire.h"
|
||||||
|
|
||||||
|
#define MATCH_RULE_MAX 1024
|
||||||
|
#define MATCH_RULE_MAX_ARG 12
|
||||||
|
|
||||||
|
typedef struct match_rule {
|
||||||
|
uint8_t type;
|
||||||
|
bool eavesdrop;
|
||||||
|
char *sender, *interface, *member, *path, *path_namespace, *destination, *arg0namespace;
|
||||||
|
char *arg[MATCH_RULE_MAX_ARG]; /* TODO: spec states that indexes 0 to 63 should be supported */
|
||||||
|
char *arg_path[MATCH_RULE_MAX_ARG]; /* TODO: spec states that indexes 0 to 63 should be supported */
|
||||||
|
} match_rule_t;
|
||||||
|
|
||||||
|
void match_rule_free(match_rule_t *rule);
|
||||||
|
match_rule_t *match_rule_from_string(char *d);
|
||||||
|
int match_rule_check(match_rule_t *rule, wire_message_t *msg, wire_context_t *ctx);
|
||||||
|
|
||||||
|
#endif // _JITTERBUG__MATCH_H
|
131
server.c
131
server.c
|
@ -6,16 +6,11 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include "match.h"
|
||||||
#include "try.h"
|
#include "try.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "wire.h"
|
#include "wire.h"
|
||||||
|
#include "util.h"
|
||||||
char *string_dup(const char *s)
|
|
||||||
{
|
|
||||||
size_t len = strlen(s) + 1;
|
|
||||||
char *p = malloc(len);
|
|
||||||
return p ? memcpy(p, s, len) : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function#FNV-1a_hash
|
// https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function#FNV-1a_hash
|
||||||
|
@ -98,6 +93,19 @@ int jb_server_name_add(struct jb_server *s, char *name, int client_index)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int jb_server_match_add(struct jb_server *s, char *match, int client_index)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < JB_MAX_MATCH; i++) {
|
||||||
|
if (s->matches[i].client_index < 0) {
|
||||||
|
s->matches[i].rule = match_rule_from_string(match);
|
||||||
|
s->matches[i].client_index = client_index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int jb_server_client_assign_unique_name(struct jb_server *s, int i)
|
int jb_server_client_assign_unique_name(struct jb_server *s, int i)
|
||||||
{
|
{
|
||||||
struct jb_client *c = &s->clients[i];
|
struct jb_client *c = &s->clients[i];
|
||||||
|
@ -166,6 +174,14 @@ void jb_server_client_remove(struct jb_server *s, int i)
|
||||||
if (s->clients[i].fd >= 0) {
|
if (s->clients[i].fd >= 0) {
|
||||||
close(s->clients[i].fd);
|
close(s->clients[i].fd);
|
||||||
}
|
}
|
||||||
|
// TODO: slow
|
||||||
|
for (int i = 0; i < JB_MAX_MATCH; i++) {
|
||||||
|
if (s->matches[i].client_index == i) {
|
||||||
|
s->matches[i].client_index = -1;
|
||||||
|
match_rule_free(s->matches[i].rule);
|
||||||
|
s->matches[i].rule = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
jb_server_name_remove(s, s->clients[i].unique_name_index);
|
jb_server_name_remove(s, s->clients[i].unique_name_index);
|
||||||
jb_server_name_remove(s, s->clients[i].owned_name_index);
|
jb_server_name_remove(s, s->clients[i].owned_name_index);
|
||||||
s->clients[i].unique_name_index = -1;
|
s->clients[i].unique_name_index = -1;
|
||||||
|
@ -193,6 +209,29 @@ ssize_t jb_server_client_recv(struct jb_server *s, int i, void *buf, size_t n)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int jb_server_broadcast_message(struct jb_server *s, wire_message_t *msg, wire_context_t *ctx, char *sender_unique_name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < JB_MAX_MATCH; i++) {
|
||||||
|
if (s->matches[i].rule) {
|
||||||
|
if (match_rule_check(s->matches[i].rule, msg, ctx) >= 0) {
|
||||||
|
struct jb_client *client = &s->clients[s->matches[i].client_index];
|
||||||
|
|
||||||
|
uint8_t reply_data[4096];
|
||||||
|
memset(reply_data, 0, 4096);
|
||||||
|
wire_context_t reply_ctx = {
|
||||||
|
.byte_cursor = 0,
|
||||||
|
.data = reply_data,
|
||||||
|
.data_len = 4096,
|
||||||
|
};
|
||||||
|
|
||||||
|
TRYST(wire_compose_unicast_reply(&reply_ctx, ctx, msg, sender_unique_name));
|
||||||
|
TRYST(send(client->fd, reply_data, reply_ctx.byte_cursor, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define _reply_begin(M_sig) \
|
#define _reply_begin(M_sig) \
|
||||||
do { \
|
do { \
|
||||||
TRYST(wire_compose_reply(&reply_ctx, &msg, (M_sig), &body_length)); \
|
TRYST(wire_compose_reply(&reply_ctx, &msg, (M_sig), &body_length)); \
|
||||||
|
@ -205,6 +244,7 @@ ssize_t jb_server_client_recv(struct jb_server *s, int i, void *buf, size_t n)
|
||||||
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; \
|
||||||
} \
|
} \
|
||||||
|
printf("send: sent %d bytes!\n", reply_ctx.byte_cursor); \
|
||||||
} while(0); \
|
} while(0); \
|
||||||
|
|
||||||
#define _reply_error(message) \
|
#define _reply_error(message) \
|
||||||
|
@ -233,7 +273,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
|
|
||||||
wire_message_field_t *destination_field = &msg.fields[DBUS_HEADER_FIELD_DESTINATION];
|
wire_message_field_t *destination_field = &msg.fields[DBUS_HEADER_FIELD_DESTINATION];
|
||||||
wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER];
|
wire_message_field_t *member_field = &msg.fields[DBUS_HEADER_FIELD_MEMBER];
|
||||||
bool should_unicast = false;
|
bool should_forward = false;
|
||||||
uint32_t *body_length;
|
uint32_t *body_length;
|
||||||
uint32_t body_start;
|
uint32_t body_start;
|
||||||
|
|
||||||
|
@ -247,15 +287,20 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case DBUS_MESSAGE_METHOD_CALL: {
|
case DBUS_MESSAGE_METHOD_CALL: {
|
||||||
if (!destination_field->present || !member_field->present) {
|
if (!member_field->present) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!destination_field->present) {
|
||||||
|
should_forward = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
char *member = member_field->t.str;
|
char *member = member_field->t.str;
|
||||||
|
|
||||||
if (strcmp(destination_field->t.str, "org.freedesktop.DBus") != 0) {
|
if (strcmp(destination_field->t.str, "org.freedesktop.DBus") != 0) {
|
||||||
// not for dbus.
|
// not for dbus.
|
||||||
should_unicast = true;
|
should_forward = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,10 +322,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name_str = string_dup(name);
|
char *name_str = TRYPTR(string_dup(name));
|
||||||
if (!name_str) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int status_code = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
int status_code = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
||||||
|
|
||||||
|
@ -332,6 +374,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
} else if (strcmp(member, "ListNames") == 0) {
|
} else if (strcmp(member, "ListNames") == 0) {
|
||||||
_reply_begin("as") {
|
_reply_begin("as") {
|
||||||
TRYPTR(wire_set_u32(&reply_ctx, s->names_count));
|
TRYPTR(wire_set_u32(&reply_ctx, s->names_count));
|
||||||
|
printf("ListNames %d\n", s->names_count);
|
||||||
|
|
||||||
int left = s->names_count;
|
int left = s->names_count;
|
||||||
for (int i = 0; i < JB_MAX_NAMES; i++) {
|
for (int i = 0; i < JB_MAX_NAMES; i++) {
|
||||||
|
@ -346,7 +389,7 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
} _reply_end()
|
} _reply_end()
|
||||||
} else if (strcmp(member, "ListActivatableNames") == 0) {
|
} else if (strcmp(member, "ListActivatableNames") == 0) {
|
||||||
// TODO: stub (always returns empty array)
|
// TODO: stub (always returns empty array)
|
||||||
printf("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));
|
||||||
|
@ -361,14 +404,40 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
if (name_len < 1 || name_len > 256) {
|
if (name_len < 1 || name_len > 256) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
/* unused flags value */
|
||||||
|
TRYPTR(wire_get_u32(&ctx));
|
||||||
|
|
||||||
printf("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRYST(jb_server_match_add(s, match, i));
|
||||||
|
|
||||||
|
printf("client index %d just added match rule: '%s'\n", i, match);
|
||||||
|
|
||||||
|
_reply_begin("") {} _reply_end()
|
||||||
|
} else if (strcmp(member, "RemoveMatch") == 0) {
|
||||||
|
// TODO: stub (does nothing and always returns success)
|
||||||
|
|
||||||
|
char *match = TRYPTR(wire_get_string(&ctx));
|
||||||
|
int match_len = strlen(match);
|
||||||
|
if (match_len < 1 || match_len > MATCH_RULE_MAX) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("FIXME: STUB: RemoveMatch: %s\n", match);
|
||||||
|
|
||||||
|
_reply_begin("") {} _reply_end()
|
||||||
} else {
|
} else {
|
||||||
|
printf("FIXME: daemon method '%s' is not implemented or invalid\n", member);
|
||||||
_reply_error("org.freedesktop.DBus.Error.UnknownMethod");
|
_reply_error("org.freedesktop.DBus.Error.UnknownMethod");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -379,7 +448,11 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
should_unicast = true;
|
should_forward = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DBUS_MESSAGE_SIGNAL: {
|
||||||
|
should_forward = true;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
@ -388,10 +461,12 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_unicast) {
|
if (should_forward) {
|
||||||
if (client->unique_name_index < 0 || !destination_field->present) {
|
if (client->unique_name_index < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (destination_field->present) {
|
||||||
|
/* unicast */
|
||||||
struct jb_client *target = jb_server_name_find_client(s, destination_field->t.str);
|
struct jb_client *target = jb_server_name_find_client(s, destination_field->t.str);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
_reply_error("org.freedesktop.DBus.Error.NameHasNoOwner");
|
_reply_error("org.freedesktop.DBus.Error.NameHasNoOwner");
|
||||||
|
@ -399,6 +474,10 @@ int jb_server_client_process_message(struct jb_server *s, int i, uint8_t *data,
|
||||||
}
|
}
|
||||||
TRYST(wire_compose_unicast_reply(&reply_ctx, &ctx, &msg, s->names[client->unique_name_index].name));
|
TRYST(wire_compose_unicast_reply(&reply_ctx, &ctx, &msg, s->names[client->unique_name_index].name));
|
||||||
TRYST(send(target->fd, reply_data, reply_ctx.byte_cursor, 0));
|
TRYST(send(target->fd, reply_data, reply_ctx.byte_cursor, 0));
|
||||||
|
} else {
|
||||||
|
/* broadcast */
|
||||||
|
TRYST(jb_server_broadcast_message(s, &msg, &ctx, s->names[client->unique_name_index].name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -414,6 +493,12 @@ void jb_server_free(struct jb_server *s)
|
||||||
free(s->names[i].name);
|
free(s->names[i].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// matches are allocated on the heap
|
||||||
|
for (int i = 0; i < JB_MAX_MATCH; i++) {
|
||||||
|
if (s->matches[i].rule) {
|
||||||
|
match_rule_free(s->matches[i].rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,6 +547,12 @@ struct jb_server *jb_server_create(const char *socket_path)
|
||||||
s->names[i].client_index = -1;
|
s->names[i].client_index = -1;
|
||||||
s->names[i].name = NULL;
|
s->names[i].name = NULL;
|
||||||
}
|
}
|
||||||
|
s->names_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < JB_MAX_MATCH; i++) {
|
||||||
|
s->matches[i].client_index = -1;
|
||||||
|
s->matches[i].rule = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
s->fds[JB_MAX_CLIENTS].fd = s->sock_fd;
|
s->fds[JB_MAX_CLIENTS].fd = s->sock_fd;
|
||||||
s->fds[JB_MAX_CLIENTS].events = POLLIN;
|
s->fds[JB_MAX_CLIENTS].events = POLLIN;
|
||||||
|
|
10
server.h
10
server.h
|
@ -1,12 +1,14 @@
|
||||||
#ifndef _JITTERBUG__SERVER_H
|
#ifndef _JITTERBUG__SERVER_H
|
||||||
#define _JITTERBUG__SERVER_H
|
#define _JITTERBUG__SERVER_H
|
||||||
|
|
||||||
|
#include "match.h"
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// TODO: dynamically size the arrays
|
// TODO: dynamically size the arrays
|
||||||
#define JB_MAX_CLIENTS 256
|
#define JB_MAX_CLIENTS 256
|
||||||
#define JB_MAX_NAMES 512
|
#define JB_MAX_NAMES 512
|
||||||
|
#define JB_MAX_MATCH 512
|
||||||
#define JB_BACKLOG 12
|
#define JB_BACKLOG 12
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -25,7 +27,12 @@ struct jb_client {
|
||||||
|
|
||||||
struct jb_name {
|
struct jb_name {
|
||||||
char *name;
|
char *name;
|
||||||
int16_t client_index;
|
int32_t client_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jb_match {
|
||||||
|
match_rule_t *rule;
|
||||||
|
int32_t client_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct jb_server {
|
struct jb_server {
|
||||||
|
@ -35,6 +42,7 @@ struct jb_server {
|
||||||
struct jb_client clients[JB_MAX_CLIENTS];
|
struct jb_client clients[JB_MAX_CLIENTS];
|
||||||
struct jb_name names[JB_MAX_NAMES];
|
struct jb_name names[JB_MAX_NAMES];
|
||||||
struct pollfd fds[JB_MAX_CLIENTS + 1];
|
struct pollfd fds[JB_MAX_CLIENTS + 1];
|
||||||
|
struct jb_match matches[JB_MAX_MATCH];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
8
util.c
Normal file
8
util.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
char *string_dup(const char *s)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s) + 1;
|
||||||
|
char *p = (char*)malloc(len);
|
||||||
|
return p ? (char*)memcpy(p, s, len) : NULL;
|
||||||
|
}
|
11
util.h
Normal file
11
util.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _JITTERBUG__UTIL_H
|
||||||
|
#define _JITTERBUG__UTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
char *string_dup(const char *s);
|
||||||
|
|
||||||
|
#endif // _JITTERBUG__UTIL_H
|
76
wire.c
76
wire.c
|
@ -3,7 +3,7 @@
|
||||||
#include "try.h"
|
#include "try.h"
|
||||||
#include "wire.h"
|
#include "wire.h"
|
||||||
|
|
||||||
#define WIRE_ENABLE_VERBOSE 0
|
#define WIRE_ENABLE_VERBOSE 1
|
||||||
#if WIRE_ENABLE_VERBOSE
|
#if WIRE_ENABLE_VERBOSE
|
||||||
#define WIRE_VERBOSE printf
|
#define WIRE_VERBOSE printf
|
||||||
#else
|
#else
|
||||||
|
@ -118,7 +118,7 @@ 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;
|
||||||
|
|
||||||
WIRE_VERBOSE("start parse message: type=%d\n", msg->type);
|
WIRE_VERBOSE("\nstart parse message: type=%d, no_reply_expected=%d\n", msg->type, msg->flags & DBUS_FLAG_NO_REPLY_EXPECTED);
|
||||||
|
|
||||||
while (c->byte_cursor < header_fields_end) {
|
while (c->byte_cursor < header_fields_end) {
|
||||||
uint8_t field_code = *(uint8_t*)TRYPTR(wire_get_u8(c));
|
uint8_t field_code = *(uint8_t*)TRYPTR(wire_get_u8(c));
|
||||||
|
@ -271,7 +271,6 @@ int wire_compose_error(wire_context_t *c, wire_message_t *msg, const char *error
|
||||||
|
|
||||||
int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_message_t *msg, char *sender_unique_name)
|
int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_message_t *msg, char *sender_unique_name)
|
||||||
{
|
{
|
||||||
|
|
||||||
TRYPTR(wire_set_u8(c, msg->endianness)); /* endianness */
|
TRYPTR(wire_set_u8(c, msg->endianness)); /* endianness */
|
||||||
TRYPTR(wire_set_u8(c, msg->type)); /* type */
|
TRYPTR(wire_set_u8(c, msg->type)); /* type */
|
||||||
TRYPTR(wire_set_u8(c, 0)); /* flags */
|
TRYPTR(wire_set_u8(c, 0)); /* flags */
|
||||||
|
@ -366,3 +365,74 @@ int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_me
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wire_collect_strings(wire_context_t *c, wire_message_t *msg, wire_message_body_string_t *strings, int strings_count)
|
||||||
|
{
|
||||||
|
if (!msg->fields[DBUS_HEADER_FIELD_SIGNATURE].present) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sig = msg->fields[DBUS_HEADER_FIELD_SIGNATURE].t.str;
|
||||||
|
int stri = 0;
|
||||||
|
int sigi = 0;
|
||||||
|
uint32_t body_cursor = c->byte_cursor;
|
||||||
|
|
||||||
|
while (*sig) {
|
||||||
|
switch (*sig) {
|
||||||
|
case 'y': {
|
||||||
|
TRYPTR(wire_get_u8(c));
|
||||||
|
} break;
|
||||||
|
case 'b': {
|
||||||
|
TRYPTR(wire_get_u32(c));
|
||||||
|
} break;
|
||||||
|
case 'n': {
|
||||||
|
TRYPTR(wire_get_i16(c));
|
||||||
|
} break;
|
||||||
|
case 'q': {
|
||||||
|
TRYPTR(wire_get_u16(c));
|
||||||
|
} break;
|
||||||
|
case 'i': {
|
||||||
|
TRYPTR(wire_get_i32(c));
|
||||||
|
} break;
|
||||||
|
case 'u': {
|
||||||
|
TRYPTR(wire_get_u32(c));
|
||||||
|
} break;
|
||||||
|
case 'o': /* through */
|
||||||
|
case 's': {
|
||||||
|
char *s = TRYPTR(wire_get_string(c));
|
||||||
|
if (sigi >= strings_count) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strings[sigi].index = sigi;
|
||||||
|
strings[sigi].str = s;
|
||||||
|
} break;
|
||||||
|
case 'g': {
|
||||||
|
char *s = TRYPTR(wire_get_signature(c));
|
||||||
|
if (sigi >= strings_count) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strings[sigi].index = sigi;
|
||||||
|
strings[sigi].str = s;
|
||||||
|
} break;
|
||||||
|
case 'a': {
|
||||||
|
uint32_t array_size = *(uint32_t*)TRYPTR(wire_get_u32(c));
|
||||||
|
uint32_t new_cursor = c->byte_cursor + array_size;
|
||||||
|
if (new_cursor >= c->data_len) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
c->byte_cursor = new_cursor;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sigi++;
|
||||||
|
sig++;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->byte_cursor = body_cursor;
|
||||||
|
|
||||||
|
return stri;
|
||||||
|
}
|
||||||
|
|
23
wire.h
23
wire.h
|
@ -8,23 +8,17 @@
|
||||||
|
|
||||||
#define DBUS_PROTOCOL_VERSION 1
|
#define DBUS_PROTOCOL_VERSION 1
|
||||||
|
|
||||||
/* The caller is now the primary owner of the name, replacing any previous owner.
|
|
||||||
Either the name had no owner before, or the caller specified DBUS_NAME_FLAG_REPLACE_EXISTING
|
|
||||||
and the current owner specified DBUS_NAME_FLAG_ALLOW_REPLACEMENT. */
|
|
||||||
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
|
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
|
||||||
/* The name already had an owner, DBUS_NAME_FLAG_DO_NOT_QUEUE was not specified,
|
|
||||||
and either the current owner did not specify DBUS_NAME_FLAG_ALLOW_REPLACEMENT or
|
|
||||||
the requesting application did not specify DBUS_NAME_FLAG_REPLACE_EXISTING. */
|
|
||||||
#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2
|
#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2
|
||||||
/* The name already has an owner, DBUS_NAME_FLAG_DO_NOT_QUEUE was specified,
|
|
||||||
and either DBUS_NAME_FLAG_ALLOW_REPLACEMENT was not specified by the current owner,
|
|
||||||
or DBUS_NAME_FLAG_REPLACE_EXISTING was not specified by the requesting application. */
|
|
||||||
#define DBUS_REQUEST_NAME_REPLY_EXISTS 3
|
#define DBUS_REQUEST_NAME_REPLY_EXISTS 3
|
||||||
/* The application trying to request ownership of a name is already the owner of it. */
|
|
||||||
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
|
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
|
||||||
|
|
||||||
|
#define DBUS_FLAG_NO_REPLY_EXPECTED 0x1
|
||||||
|
#define DBUS_FLAG_NO_AUTO_START 0x1
|
||||||
|
#define DBUS_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION 0x1
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DBUS_HEADER_FIELD_INVALID,
|
DBUS_HEADER_FIELD_INVALID = 0,
|
||||||
DBUS_HEADER_FIELD_PATH,
|
DBUS_HEADER_FIELD_PATH,
|
||||||
DBUS_HEADER_FIELD_INTERFACE,
|
DBUS_HEADER_FIELD_INTERFACE,
|
||||||
DBUS_HEADER_FIELD_MEMBER,
|
DBUS_HEADER_FIELD_MEMBER,
|
||||||
|
@ -37,7 +31,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DBUS_MESSAGE_INVALID,
|
DBUS_MESSAGE_INVALID = 0,
|
||||||
DBUS_MESSAGE_METHOD_CALL,
|
DBUS_MESSAGE_METHOD_CALL,
|
||||||
DBUS_MESSAGE_METHOD_RETURN,
|
DBUS_MESSAGE_METHOD_RETURN,
|
||||||
DBUS_MESSAGE_ERROR,
|
DBUS_MESSAGE_ERROR,
|
||||||
|
@ -65,6 +59,10 @@ typedef struct wire_message {
|
||||||
uint8_t header_fields_count;
|
uint8_t header_fields_count;
|
||||||
wire_message_field_t fields[WIRE_MESSAGE_MAX_HEADER_FIELDS]; /* cannot have more than 9 header fields */
|
wire_message_field_t fields[WIRE_MESSAGE_MAX_HEADER_FIELDS]; /* cannot have more than 9 header fields */
|
||||||
} wire_message_t;
|
} wire_message_t;
|
||||||
|
typedef struct wire_message_body_string {
|
||||||
|
uint16_t index;
|
||||||
|
char *str;
|
||||||
|
} wire_message_body_string_t;
|
||||||
|
|
||||||
#define _WIRE_DECL_BYTE_TYPE(M_mnemonic, M_type) \
|
#define _WIRE_DECL_BYTE_TYPE(M_mnemonic, M_type) \
|
||||||
M_type *wire_get_##M_mnemonic(wire_context_t *c); \
|
M_type *wire_get_##M_mnemonic(wire_context_t *c); \
|
||||||
|
@ -129,6 +127,7 @@ 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);
|
int wire_compose_unicast_reply(wire_context_t *c, wire_context_t *msg_c, wire_message_t *msg, char *sender_unique_name);
|
||||||
|
int wire_collect_strings(wire_context_t *c, wire_message_t *msg, wire_message_body_string_t *strings, int strings_count);
|
||||||
|
|
||||||
static inline char *wire_get_signature(wire_context_t *c) {
|
static inline char *wire_get_signature(wire_context_t *c) {
|
||||||
return wire_get_string_impl(c, true);
|
return wire_get_string_impl(c, true);
|
||||||
|
|
Loading…
Reference in a new issue