static bool bus_match_node_maybe_free(struct bus_match_node *node) {
assert(node);
+ if (node->type == BUS_MATCH_ROOT)
+ return false;
+
if (node->child)
return false;
enum bus_match_node_type parent_type,
uint8_t value_u8,
const char *value_str,
+ char **value_strv,
sd_bus_message *m) {
assert(node);
case BUS_MATCH_INTERFACE:
case BUS_MATCH_MEMBER:
case BUS_MATCH_PATH:
- case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
- return streq_ptr(node->value.str, value_str);
+ case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
+ char **i;
- case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
- return namespace_simple_pattern(node->value.str, value_str);
+ if (value_str)
+ return streq_ptr(node->value.str, value_str);
+
+ STRV_FOREACH(i, value_strv)
+ if (streq_ptr(node->value.str, *i))
+ return true;
+
+ return false;
+ }
+
+ case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
+ char **i;
+
+ if (value_str)
+ return namespace_simple_pattern(node->value.str, value_str);
+
+ STRV_FOREACH(i, value_strv)
+ if (namespace_simple_pattern(node->value.str, *i))
+ return true;
+ return false;
+ }
case BUS_MATCH_PATH_NAMESPACE:
return path_simple_pattern(node->value.str, value_str);
- case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
- return path_complex_pattern(node->value.str, value_str);
+ case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
+ char **i;
+
+ if (value_str)
+ return path_complex_pattern(node->value.str, value_str);
+
+ STRV_FOREACH(i, value_strv)
+ if (path_complex_pattern(node->value.str, *i))
+ return true;
+
+ return false;
+ }
default:
assert_not_reached("Invalid node type");
struct bus_match_node *node,
sd_bus_message *m) {
-
+ _cleanup_strv_free_ char **test_strv = NULL;
const char *test_str = NULL;
uint8_t test_u8 = 0;
int r;
case BUS_MATCH_LEAF:
if (bus) {
- if (node->leaf.last_iteration == bus->iteration_counter)
+ if (node->leaf.callback->last_iteration == bus->iteration_counter)
return 0;
- node->leaf.last_iteration = bus->iteration_counter;
+ node->leaf.callback->last_iteration = bus->iteration_counter;
}
r = sd_bus_message_rewind(m, true);
return r;
/* Run the callback. And then invoke siblings. */
- if (node->leaf.callback) {
+ if (node->leaf.callback->callback) {
_cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+ sd_bus_slot *slot;
+
+ slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
+ if (bus) {
+ bus->current_slot = sd_bus_slot_ref(slot);
+ bus->current_handler = node->leaf.callback->callback;
+ bus->current_userdata = slot->userdata;
+ }
+ r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
+ if (bus) {
+ bus->current_userdata = NULL;
+ bus->current_handler = NULL;
+ bus->current_slot = sd_bus_slot_unref(slot);
+ }
- r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
r = bus_maybe_reply_error(m, r, &error_buffer);
if (r != 0)
return r;
+
+ if (bus && bus->match_callbacks_modified)
+ return 0;
}
return bus_match_run(bus, node->next, m);
break;
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
- test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
break;
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
- test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
break;
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
- test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
break;
default:
if (test_str)
found = hashmap_get(node->compare.children, test_str);
- else if (node->type == BUS_MATCH_MESSAGE_TYPE)
+ else if (test_strv) {
+ char **i;
+
+ STRV_FOREACH(i, test_strv) {
+ found = hashmap_get(node->compare.children, *i);
+ if (found) {
+ r = bus_match_run(bus, found, m);
+ if (r != 0)
+ return r;
+ }
+ }
+
+ found = NULL;
+ } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
else
found = NULL;
/* No hash table, so let's iterate manually... */
for (c = node->child; c; c = c->next) {
- if (!value_node_test(c, node->type, test_u8, test_str, m))
+ if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
continue;
r = bus_match_run(bus, c, m);
where->child = c;
if (t == BUS_MATCH_MESSAGE_TYPE) {
- c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func);
+ c->compare.children = hashmap_new(NULL);
if (!c->compare.children) {
r = -ENOMEM;
goto fail;
}
} else if (BUS_MATCH_CAN_HASH(t)) {
- c->compare.children = hashmap_new(string_hash_func, string_compare_func);
+ c->compare.children = hashmap_new(&string_hash_ops);
if (!c->compare.children) {
r = -ENOMEM;
goto fail;
else if (BUS_MATCH_CAN_HASH(t))
n = hashmap_get(c->compare.children, value_str);
else {
- for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
+ for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
;
}
static int bus_match_add_leaf(
struct bus_match_node *where,
- sd_bus_message_handler_t callback,
- void *userdata,
- uint64_t cookie,
- struct bus_match_node **ret) {
+ struct match_callback *callback) {
struct bus_match_node *n;
assert(where);
assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
- assert(ret);
+ assert(callback);
n = new0(struct bus_match_node, 1);
if (!n)
n->next = where->child;
if (n->next)
n->next->prev = n;
+
n->leaf.callback = callback;
- n->leaf.userdata = userdata;
- n->leaf.cookie = cookie;
+ callback->match_node = n;
where->child = n;
- *ret = n;
return 1;
}
assert(ret);
for (c = where->child; c; c = c->next) {
+ sd_bus_slot *s;
+
+ s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
+
if (c->type == BUS_MATCH_LEAF &&
- c->leaf.callback == callback &&
- c->leaf.userdata == userdata) {
+ c->leaf.callback->callback == callback &&
+ s->userdata == userdata) {
*ret = c;
return 1;
}
bool escaped = false, quoted;
uint8_t u;
+ /* Avahi's match rules appear to include whitespace, skip over it */
+ p += strspn(p, " ");
+
eq = strchr(p, '=');
if (!eq)
return -EINVAL;
value = NULL;
- if (q[1] == 0)
+ if (q[quoted] == 0)
break;
if (q[quoted] != ',') {
struct bus_match_node *root,
struct bus_match_component *components,
unsigned n_components,
- sd_bus_message_handler_t callback,
- void *userdata,
- uint64_t cookie,
- struct bus_match_node **ret) {
+ struct match_callback *callback) {
unsigned i;
struct bus_match_node *n;
int r;
assert(root);
+ assert(callback);
n = root;
for (i = 0; i < n_components; i++) {
return r;
}
- r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
- if (r < 0)
- return r;
+ return bus_match_add_leaf(n, callback);
+}
- if (ret)
- *ret = n;
+int bus_match_remove(
+ struct bus_match_node *root,
+ struct match_callback *callback) {
- return 0;
+ struct bus_match_node *node, *pp;
+
+ assert(root);
+ assert(callback);
+
+ node = callback->match_node;
+ if (!node)
+ return 0;
+
+ assert(node->type == BUS_MATCH_LEAF);
+
+ callback->match_node = NULL;
+
+ /* Free the leaf */
+ pp = node->parent;
+ bus_match_node_free(node);
+
+ /* Prune the tree above */
+ while (pp) {
+ node = pp;
+ pp = node->parent;
+
+ if (!bus_match_node_maybe_free(node))
+ break;
+ }
+
+ return 1;
}
-int bus_match_remove(
+int bus_match_find(
struct bus_match_node *root,
struct bus_match_component *components,
unsigned n_components,
sd_bus_message_handler_t callback,
void *userdata,
- uint64_t *cookie) {
+ struct match_callback **ret) {
- unsigned i;
struct bus_match_node *n, **gc;
+ unsigned i;
int r;
assert(root);
+ assert(ret);
gc = newa(struct bus_match_node*, n_components);
if (r <= 0)
return r;
- if (cookie)
- *cookie = n->leaf.cookie;
-
- /* Free the leaf */
- bus_match_node_free(n);
-
- /* Prune the tree above */
- for (i = n_components; i > 0; i --) {
- struct bus_match_node *p = gc[i-1]->parent;
-
- if (!bus_match_node_maybe_free(gc[i-1]))
- break;
-
- if (!bus_match_node_maybe_free(p))
- break;
- }
-
- return r;
+ *ret = n->leaf.callback;
+ return 1;
}
void bus_match_free(struct bus_match_node *node) {
} else if (node->type == BUS_MATCH_ROOT)
puts(" root");
else if (node->type == BUS_MATCH_LEAF)
- printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
+ printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
else
putchar('\n');