static void bus_match_node_free(struct bus_match_node *node) { assert(node); assert(node->parent); assert(!node->child); assert(node->type != BUS_MATCH_ROOT); assert(node->type < _BUS_MATCH_NODE_TYPE_MAX); if (node->parent->child) { /* We are apparently linked into the parent's child * list. Let's remove us from there. */ if (node->prev) { assert(node->prev->next == node); node->prev->next = node->next; } else { assert(node->parent->child == node); node->parent->child = node->next; } if (node->next) node->next->prev = node->prev; } if (node->type == BUS_MATCH_VALUE) { /* We might be in the parent's hash table, so clean * this up */ if (node->parent->type == BUS_MATCH_MESSAGE_TYPE) hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8)); else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str) hashmap_remove(node->parent->compare.children, node->value.str); free(node->value.str); } if (BUS_MATCH_IS_COMPARE(node->type)) { assert(hashmap_isempty(node->compare.children)); hashmap_free(node->compare.children); } free(node); }
void bus_match_free(struct bus_match_node *node) { struct bus_match_node *c; if (!node) return; if (BUS_MATCH_CAN_HASH(node->type)) { Iterator i; HASHMAP_FOREACH(c, node->compare.children, i) bus_match_free(c); assert(hashmap_isempty(node->compare.children)); } while ((c = node->child)) bus_match_free(c); if (node->type != BUS_MATCH_ROOT) bus_match_node_free(node); }
static int bus_match_find_compare_value( struct bus_match_node *where, enum bus_match_node_type t, uint8_t value_u8, const char *value_str, struct bus_match_node **ret) { struct bus_match_node *c, *n; assert(where); assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); assert(BUS_MATCH_IS_COMPARE(t)); assert(ret); for (c = where->child; c && c->type != t; c = c->next) ; if (!c) return 0; if (t == BUS_MATCH_MESSAGE_TYPE) n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); 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) ; } if (n) { *ret = n; return 1; } return 0; }
static int bus_match_add_compare_value( struct bus_match_node *where, enum bus_match_node_type t, uint8_t value_u8, const char *value_str, struct bus_match_node **ret) { struct bus_match_node *c = NULL, *n = NULL; int r; assert(where); assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); assert(BUS_MATCH_IS_COMPARE(t)); assert(ret); for (c = where->child; c && c->type != t; c = c->next) ; if (c) { /* Comparison node already exists? Then let's see if * the value node exists too. */ if (t == BUS_MATCH_MESSAGE_TYPE) n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); else if (BUS_MATCH_CAN_HASH(t)) n = hashmap_get(c->compare.children, value_str); else { for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next) ; } if (n) { *ret = n; return 0; } } else { /* Comparison node, doesn't exist yet? Then let's * create it. */ c = new0(struct bus_match_node, 1); if (!c) { r = -ENOMEM; goto fail; } c->type = t; c->parent = where; c->next = where->child; if (c->next) c->next->prev = c; where->child = c; if (t == BUS_MATCH_MESSAGE_TYPE) { c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func); 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); if (!c->compare.children) { r = -ENOMEM; goto fail; } } } n = new0(struct bus_match_node, 1); if (!n) { r = -ENOMEM; goto fail; } n->type = BUS_MATCH_VALUE; n->value.u8 = value_u8; if (value_str) { n->value.str = strdup(value_str); if (!n->value.str) { r = -ENOMEM; goto fail; } } n->parent = c; if (c->compare.children) { if (t == BUS_MATCH_MESSAGE_TYPE) r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n); else r = hashmap_put(c->compare.children, n->value.str, n); if (r < 0) goto fail; } else { n->next = c->child; if (n->next) n->next->prev = n; c->child = n; } *ret = n; return 1; fail: if (c) bus_match_node_maybe_free(c); if (n) { free(n->value.str); free(n); } return r; }
int bus_match_run( sd_bus *bus, struct bus_match_node *node, sd_bus_message *m) { const char *test_str = NULL; uint8_t test_u8 = 0; int r; assert(m); if (!node) return 0; if (bus && bus->match_callbacks_modified) return 0; /* Not these special semantics: when traversing the tree we * usually let bus_match_run() when called for a node * recursively invoke bus_match_run(). There's are two * exceptions here though, which are BUS_NODE_ROOT (which * cannot have a sibling), and BUS_NODE_VALUE (whose siblings * are invoked anyway by its parent. */ switch (node->type) { case BUS_MATCH_ROOT: /* Run all children. Since we cannot have any siblings * we won't call any. The children of the root node * are compares or leaves, they will automatically * call their siblings. */ return bus_match_run(bus, node->child, m); case BUS_MATCH_VALUE: /* Run all children. We don't execute any siblings, we * assume our caller does that. The children of value * nodes are compares or leaves, they will * automatically call their siblings */ assert(node->child); return bus_match_run(bus, node->child, m); case BUS_MATCH_LEAF: if (bus) { if (node->leaf.last_iteration == bus->iteration_counter) return 0; node->leaf.last_iteration = bus->iteration_counter; } r = sd_bus_message_rewind(m, true); if (r < 0) return r; /* Run the callback. And then invoke siblings. */ if (node->leaf.callback) { _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; 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; } return bus_match_run(bus, node->next, m); case BUS_MATCH_MESSAGE_TYPE: test_u8 = m->header->type; break; case BUS_MATCH_SENDER: test_str = m->sender; /* FIXME: resolve test_str from a well-known to a unique name first */ break; case BUS_MATCH_DESTINATION: test_str = m->destination; break; case BUS_MATCH_INTERFACE: test_str = m->interface; break; case BUS_MATCH_MEMBER: test_str = m->member; break; case BUS_MATCH_PATH: case BUS_MATCH_PATH_NAMESPACE: test_str = m->path; break; case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG); break; case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH); break; case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE); break; default: assert_not_reached("Unknown match type."); } if (BUS_MATCH_CAN_HASH(node->type)) { struct bus_match_node *found; /* Lookup via hash table, nice! So let's jump directly. */ if (test_str) found = hashmap_get(node->compare.children, test_str); else if (node->type == BUS_MATCH_MESSAGE_TYPE) found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8)); else found = NULL; if (found) { r = bus_match_run(bus, found, m); if (r != 0) return r; } } else { struct bus_match_node *c; /* 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)) continue; r = bus_match_run(bus, c, m); if (r != 0) return r; } } if (bus && bus->match_callbacks_modified) return 0; /* And now, let's invoke our siblings */ return bus_match_run(bus, node->next, m); }