diff --git a/CMakeLists.txt b/CMakeLists.txt index 928712b..cdf0350 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3) ADD_LIBRARY(ubus SHARED libubus.c) TARGET_LINK_LIBRARIES(ubus ubox) -ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c) +ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c) TARGET_LINK_LIBRARIES(ubusd ubox) ADD_EXECUTABLE(cli cli.c) diff --git a/cli.c b/cli.c index c0521fa..59e62ed 100644 --- a/cli.c +++ b/cli.c @@ -34,6 +34,7 @@ static int usage(char *prog) "Commands:\n" " - list [] List objects\n" " - call [] Call an object method\n" + " - listen [...] Listen for events\n" "\n", prog); return 1; } @@ -70,6 +71,8 @@ int main(int argc, char **argv) ret = ubus_lookup_id(ctx, argv[2], &id); if (!ret) ret = ubus_invoke(ctx, id, argv[3], NULL, receive_data, NULL); + } else if (!strcmp(cmd, "listen")) { + ret = ubus_invoke(ctx, UBUS_SYSTEM_OBJECT_EVENT, "listen", NULL, receive_data, NULL); } else { return usage(argv[0]); } diff --git a/ubusd.h b/ubusd.h index c0b02f5..c82896c 100644 --- a/ubusd.h +++ b/ubusd.h @@ -60,5 +60,8 @@ bool ubusd_send_hello(struct ubus_client *cl); struct blob_attr **ubus_parse_msg(struct blob_attr *msg); +void ubusd_event_init(void); +void ubusd_event_cleanup_object(struct ubus_object *obj); + #endif diff --git a/ubusd_event.c b/ubusd_event.c new file mode 100644 index 0000000..da0aed8 --- /dev/null +++ b/ubusd_event.c @@ -0,0 +1,45 @@ +#include "ubusd.h" + +static struct avl_tree patterns; +static struct ubus_object *event_obj; + +struct event_pattern { + struct avl_node avl; + + struct ubus_object *obj; + struct list_head list; + + const char *path; +}; + +static void ubusd_delete_event_pattern(struct event_pattern *ev) +{ + list_del(&ev->list); + avl_delete(&patterns, &ev->avl); + free(ev); +} + +void ubusd_event_cleanup_object(struct ubus_object *obj) +{ + struct event_pattern *ev; + + while (!list_empty(&obj->event_patterns)) { + ev = list_first_entry(&obj->event_patterns, + struct event_pattern, list); + ubusd_delete_event_pattern(ev); + } +} + +static int ubusd_event_recv(struct ubus_client *cl, const char *method, struct blob_attr *msg) +{ + fprintf(stderr, "event: call to method '%s'\n", method); + return 0; +} + +void ubusd_event_init(void) +{ + ubus_init_string_tree(&patterns, true); + event_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_EVENT); + event_obj->recv_msg = ubusd_event_recv; +} + diff --git a/ubusd_id.c b/ubusd_id.c index 44b509e..a9cfeae 100644 --- a/ubusd_id.c +++ b/ubusd_id.c @@ -18,6 +18,16 @@ static int ubus_cmp_id(const void *k1, const void *k2, void *ptr) return *id1 > *id2; } +static int ubus_cmp_str(const void *k1, const void *k2, void *ptr) +{ + return strcmp(k1, k2); +} + +void ubus_init_string_tree(struct avl_tree *tree, bool dup) +{ + avl_init(tree, ubus_cmp_str, dup, NULL); +} + void ubus_init_id_tree(struct avl_tree *tree) { if (random_fd < 0) { diff --git a/ubusd_id.h b/ubusd_id.h index 2b4cb6d..740e5d6 100644 --- a/ubusd_id.h +++ b/ubusd_id.h @@ -10,6 +10,7 @@ struct ubus_id { }; void ubus_init_id_tree(struct avl_tree *tree); +void ubus_init_string_tree(struct avl_tree *tree, bool dup); bool ubus_alloc_id(struct avl_tree *tree, struct ubus_id *id, uint32_t val); static inline void ubus_free_id(struct avl_tree *tree, struct ubus_id *id) diff --git a/ubusd_obj.c b/ubusd_obj.c index 7fc7951..a6be182 100644 --- a/ubusd_obj.c +++ b/ubusd_obj.c @@ -98,7 +98,8 @@ struct ubus_object *ubusd_create_object_internal(struct ubus_object_type *type, obj->type = type; INIT_LIST_HEAD(&obj->list); - type->refcount++; + if (type) + type->refcount++; return obj; @@ -156,18 +157,15 @@ void ubusd_free_object(struct ubus_object *obj) if (!list_empty(&obj->list)) list_del(&obj->list); ubus_free_id(&objects, &obj->id); - ubus_unref_object_type(obj->type); + if (obj->type) + ubus_unref_object_type(obj->type); free(obj); } -static int ubus_cmp_path(const void *k1, const void *k2, void *ptr) -{ - return strcmp(k1, k2); -} - static void __init ubusd_obj_init(void) { ubus_init_id_tree(&objects); ubus_init_id_tree(&obj_types); - avl_init(&path, ubus_cmp_path, false, NULL); + ubus_init_string_tree(&path, false); + ubusd_event_init(); } diff --git a/ubusd_obj.h b/ubusd_obj.h index 2064084..6e5c2c9 100644 --- a/ubusd_obj.h +++ b/ubusd_obj.h @@ -26,13 +26,17 @@ struct ubus_object { struct ubus_id id; struct list_head list; + struct list_head event_patterns; + struct ubus_object_type *type; struct avl_node path; struct ubus_client *client; + int (*recv_msg)(struct ubus_client *client, const char *method, struct blob_attr *msg); }; struct ubus_object *ubusd_create_object(struct ubus_client *cl, struct blob_attr **attr); +struct ubus_object *ubusd_create_object_internal(struct ubus_object_type *type, uint32_t id); void ubusd_free_object(struct ubus_object *obj); #endif diff --git a/ubusd_proto.c b/ubusd_proto.c index 1b3216f..07bb9fa 100644 --- a/ubusd_proto.c +++ b/ubusd_proto.c @@ -176,6 +176,10 @@ static int ubusd_handle_invoke(struct ubus_client *cl, struct ubus_msg_buf *ub, obj = container_of(id, struct ubus_object, id); method = blob_data(attr[UBUS_ATTR_METHOD]); + + if (!obj->client) + return obj->recv_msg(cl, method, attr[UBUS_ATTR_DATA]); + blob_buf_init(&b, 0); blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id); blob_put_string(&b, UBUS_ATTR_METHOD, method);