X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubus.git;a=blobdiff_plain;f=ubusd_event.c;h=7b4c35eecd3c5ba461365f23e6ee9db59bd030d5;hp=3396ebf13c725032ac1011c5652244a5fa0d580c;hb=ef978a8ea002a146d8a6d60a9f0458b272f912eb;hpb=f6a6b0d492900b7a087a8a89d11fa5b94f4c5cb5 diff --git a/ubusd_event.c b/ubusd_event.c index 3396ebf..7b4c35e 100644 --- a/ubusd_event.c +++ b/ubusd_event.c @@ -1,8 +1,11 @@ +#include #include "ubusd.h" static struct avl_tree patterns; static LIST_HEAD(catch_all); static struct ubus_object *event_obj; +static int event_seq = 0; +static int obj_event_seq = 0; enum evs_type { EVS_PATTERN, @@ -16,6 +19,7 @@ struct event_source { union { struct { struct avl_node avl; + bool partial; } pattern; struct { struct list_head list; @@ -23,18 +27,6 @@ struct event_source { }; }; -struct event_pattern { - struct event_source evs; - struct list_head list; -}; - -struct event_catchall { - struct event_source evs; - - struct list_head list; - struct ubus_object *obj; -}; - static void ubusd_delete_event_source(struct event_source *evs) { list_del(&evs->list); @@ -60,14 +52,14 @@ void ubusd_event_cleanup_object(struct ubus_object *obj) } enum { - EVMSG_PATTERN, - EVMSG_OBJECT, - EVMSG_LAST, + EVREG_PATTERN, + EVREG_OBJECT, + EVREG_LAST, }; -static struct blobmsg_policy ev_policy[] = { - [EVMSG_PATTERN] = { .name = "pattern", .type = BLOBMSG_TYPE_STRING }, - [EVMSG_OBJECT] = { .name = "object", .type = BLOBMSG_TYPE_INT32 }, +static struct blobmsg_policy evr_policy[] = { + [EVREG_PATTERN] = { .name = "pattern", .type = BLOBMSG_TYPE_STRING }, + [EVREG_OBJECT] = { .name = "object", .type = BLOBMSG_TYPE_INT32 }, }; @@ -96,15 +88,17 @@ static int ubusd_alloc_event_pattern(struct ubus_client *cl, struct blob_attr *m { struct event_source *ev; struct ubus_object *obj; - struct blob_attr *attr[EVMSG_LAST]; - const char *pattern; + struct blob_attr *attr[EVREG_LAST]; + char *pattern; uint32_t id; + bool partial = false; + int len; - blobmsg_parse(ev_policy, EVMSG_LAST, attr, blob_data(msg), blob_len(msg)); - if (!attr[EVMSG_OBJECT]) + blobmsg_parse(evr_policy, EVREG_LAST, attr, blob_data(msg), blob_len(msg)); + if (!attr[EVREG_OBJECT]) return UBUS_STATUS_INVALID_ARGUMENT; - id = blobmsg_get_u32(attr[EVMSG_OBJECT]); + id = blobmsg_get_u32(attr[EVREG_OBJECT]); if (id < UBUS_SYSTEM_OBJECT_MAX) return UBUS_STATUS_PERMISSION_DENIED; @@ -115,11 +109,20 @@ static int ubusd_alloc_event_pattern(struct ubus_client *cl, struct blob_attr *m if (obj->client != cl) return UBUS_STATUS_PERMISSION_DENIED; - if (!attr[EVMSG_PATTERN]) + if (!attr[EVREG_PATTERN]) return ubusd_alloc_catchall(obj); - pattern = blobmsg_data(attr[EVMSG_PATTERN]); - ev = ubusd_alloc_event_source(obj, EVS_PATTERN, strlen(pattern) + 1); + pattern = blobmsg_data(attr[EVREG_PATTERN]); + + len = strlen(pattern); + if (pattern[len - 1] == '*') { + partial = true; + pattern[len - 1] = 0; + len--; + } + + ev = ubusd_alloc_event_source(obj, EVS_PATTERN, len + 1); + ev->pattern.partial = partial; ev->pattern.avl.key = (void *) (ev + 1); strcpy(ev->pattern.avl.key, pattern); avl_insert(&patterns, &ev->pattern.avl); @@ -127,11 +130,122 @@ static int ubusd_alloc_event_pattern(struct ubus_client *cl, struct blob_attr *m return 0; } +enum { + EVMSG_ID, + EVMSG_DATA, + EVMSG_LAST, +}; + +static struct blobmsg_policy ev_policy[] = { + [EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING }, + [EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, +}; + +static void ubusd_send_event_msg(struct ubus_msg_buf **ub, struct ubus_client *cl, + struct ubus_object *obj, const char *id, + struct blob_attr *msg) +{ + uint32_t *objid_ptr; + + /* do not loop back events */ + if (obj->client == cl) + return; + + /* do not send duplicate events */ + if (obj->event_seen == obj_event_seq) + return; + + obj->event_seen = obj_event_seq; + + if (*ub) { + objid_ptr = blob_data(blob_data((*ub)->data)); + *objid_ptr = htonl(obj->id.id); + } else { + blob_buf_init(&b, 0); + blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id); + blob_put_string(&b, UBUS_ATTR_METHOD, id); + blob_put(&b, UBUS_ATTR_DATA, blobmsg_data(msg), blobmsg_data_len(msg)); + + *ub = ubus_msg_new(b.head, blob_raw_len(b.head), true); + + (*ub)->hdr.type = UBUS_MSG_INVOKE; + (*ub)->hdr.peer = 0; + } + (*ub)->hdr.seq = ++event_seq; + ubus_msg_send(obj->client, *ub, false); +} + +bool strmatch_len(const char *s1, const char *s2, int *len) +{ + for (*len = 0; s1[*len] == s2[*len]; (*len)++) + if (!s1[*len]) + return true; + + return false; +} + +static int ubusd_send_event(struct ubus_client *cl, struct blob_attr *msg) +{ + struct ubus_msg_buf *ub = NULL; + struct event_source *ev; + struct blob_attr *attr[EVMSG_LAST]; + const char *id; + int match_len = 0; + void *data; + + blobmsg_parse(ev_policy, EVMSG_LAST, attr, blob_data(msg), blob_len(msg)); + if (!attr[EVMSG_ID] || !attr[EVMSG_DATA]) + return UBUS_STATUS_INVALID_ARGUMENT; + + id = blobmsg_data(attr[EVMSG_ID]); + data = attr[EVMSG_DATA]; + + list_for_each_entry(ev, &catch_all, catchall.list) + ubusd_send_event_msg(&ub, cl, ev->obj, id, data); + + obj_event_seq++; + + /* + * Since this tree is sorted alphabetically, we can only expect to find + * matching entries as long as the number of matching characters + * between the pattern string and our string is monotonically increasing. + */ + avl_for_each_element(&patterns, ev, pattern.avl) { + const char *key = ev->pattern.avl.key; + int cur_match_len; + bool full_match; + + full_match = strmatch_len(id, key, &cur_match_len); + if (cur_match_len < match_len) + break; + + match_len = cur_match_len; + + if (!full_match) { + if (!ev->pattern.partial) + continue; + + if (match_len != strlen(key)) + continue; + } + + ubusd_send_event_msg(&ub, cl, ev->obj, id, data); + } + + if (ub) + ubus_msg_free(ub); + + return 0; +} + static int ubusd_event_recv(struct ubus_client *cl, const char *method, struct blob_attr *msg) { if (!strcmp(method, "register")) return ubusd_alloc_event_pattern(cl, msg); + if (!strcmp(method, "send")) + return ubusd_send_event(cl, msg); + return UBUS_STATUS_INVALID_COMMAND; }