ubus: add notification for subscribers present/gone
authorFelix Fietkau <nbd@openwrt.org>
Fri, 14 Dec 2012 12:00:49 +0000 (13:00 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 14 Dec 2012 12:00:57 +0000 (13:00 +0100)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
examples/client.c
libubus-internal.h
libubus-sub.c
libubus.c
libubus.h
ubusd_obj.c
ubusd_obj.h
ubusd_proto.c
ubusmsg.h

index 315a8e39d34a4595deb613ea70d80bb8feeac78b..418fb15f151eb385c22bcb108b55701203df53e1 100644 (file)
 static struct ubus_context *ctx;
 static struct blob_buf b;
 
-static struct ubus_object test_client_object = {};
+static void test_client_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
+{
+       fprintf(stderr, "Subscribers active: %d\n", obj->has_subscribers);
+}
+
+static struct ubus_object test_client_object = {
+       .subscribe_cb = test_client_subscribe_cb,
+};
 
 static void client_main(void)
 {
index f3e2a7393558fdc0002bd2930c7088f601ea2f23..072bf8effd7d3b98e9589f706fa9a58637a3917f 100644 (file)
@@ -27,5 +27,6 @@ void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr);
 int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
                                struct blob_attr *msg, int cmd, uint32_t peer);
 void ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr);
+void ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr);
 
 #endif
index 2bfb483cfd8019dd22b12fc3d9144914fd1dbea8..87c81281abadcf9f47961b9289d392b752235ab2 100644 (file)
@@ -91,4 +91,22 @@ void __hidden ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msg
        s->remove_cb(ctx, s, blob_get_u32(attrbuf[UBUS_ATTR_TARGET]));
 }
 
+void __hidden ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr)
+{
+       struct blob_attr **attrbuf;
+       struct ubus_object *obj;
+       uint32_t objid;
+
+       attrbuf = ubus_parse_msg(hdr->data);
+       if (!attrbuf[UBUS_ATTR_OBJID] || !attrbuf[UBUS_ATTR_ACTIVE])
+               return;
 
+       objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
+       obj = avl_find_element(&ctx->objects, &objid, obj, avl);
+       if (!obj)
+               return;
+
+       obj->has_subscribers = blob_get_u8(attrbuf[UBUS_ATTR_ACTIVE]);
+       if (obj->subscribe_cb)
+               obj->subscribe_cb(ctx, obj);
+}
index 03899d6db44e766513053e0eb65a5acee27cc6ee..dffbfeb958074aa3d27bc0fbe3e8102f99f6d366 100644 (file)
--- a/libubus.c
+++ b/libubus.c
@@ -232,6 +232,10 @@ void __hidden ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr
        case UBUS_MSG_UNSUBSCRIBE:
                ubus_process_unsubscribe(ctx, hdr);
                break;
+
+       case UBUS_MSG_NOTIFY:
+               ubus_process_notify(ctx, hdr);
+               break;
        }
 }
 
index 17c49527095dc09084daf6b2e458a496e22f87b7..19a421779c560eff922b036f957d741dbb8b7e7a 100644 (file)
--- a/libubus.h
+++ b/libubus.h
@@ -37,6 +37,7 @@ typedef void (*ubus_lookup_handler_t)(struct ubus_context *ctx,
 typedef int (*ubus_handler_t)(struct ubus_context *ctx, struct ubus_object *obj,
                              struct ubus_request_data *req,
                              const char *method, struct blob_attr *msg);
+typedef void (*ubus_state_handler_t)(struct ubus_context *ctx, struct ubus_object *obj);
 typedef void (*ubus_remove_handler_t)(struct ubus_context *ctx,
                                      struct ubus_subscriber *obj, uint32_t id);
 typedef void (*ubus_event_handler_t)(struct ubus_context *ctx, struct ubus_event_handler *ev,
@@ -86,6 +87,9 @@ struct ubus_object {
        const char *path;
        struct ubus_object_type *type;
 
+       ubus_state_handler_t subscribe_cb;
+       bool has_subscribers;
+
        const struct ubus_method *methods;
        int n_methods;
 };
@@ -134,6 +138,7 @@ struct ubus_request_data {
        uint32_t peer;
        uint32_t seq;
        bool deferred;
+       bool notify;
 };
 
 struct ubus_request {
index 8b1b18f8fe4e14de302882900d22b3d088204d15..69ca8b871fd8c6a3cfc83dd04945cb897bac71be 100644 (file)
@@ -167,6 +167,7 @@ free:
 void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target, const char *method)
 {
        struct ubus_subscription *s;
+       bool first = list_empty(&target->subscribers);
 
        s = calloc(1, sizeof(*s) + strlen(method) + 1);
        if (!s)
@@ -177,13 +178,21 @@ void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target, const c
        list_add(&s->list, &target->subscribers);
        list_add(&s->target_list, &obj->target_list);
        strcpy(s->method, method);
+
+       if (first)
+               ubus_notify_subscription(target);
 }
 
 void ubus_unsubscribe(struct ubus_subscription *s)
 {
+       struct ubus_object *obj = s->target;
+
        list_del(&s->list);
        list_del(&s->target_list);
        free(s);
+
+       if (list_empty(&obj->subscribers))
+               ubus_notify_subscription(obj);
 }
 
 void ubusd_free_object(struct ubus_object *obj)
index 5a82e8dfccefebfb980a395c75272ff8aae7c685..8e80078f5aeafe7ad734f6852a7114e6ed32ccd2 100644 (file)
@@ -79,5 +79,6 @@ static inline struct ubus_object *ubusd_find_object(uint32_t objid)
 void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target, const char *method);
 void ubus_unsubscribe(struct ubus_subscription *s);
 void ubus_notify_unsubscribe(struct ubus_subscription *s);
+void ubus_notify_subscription(struct ubus_object *obj);
 
 #endif
index 59920ed7f9a8c79355244a26b0bd92a5e9d4ed50..283cb771b8cda759126aad0890bb2d8ab73f8775 100644 (file)
@@ -416,6 +416,20 @@ void ubusd_proto_free_client(struct ubus_client *cl)
        ubus_free_id(&clients, &cl->id);
 }
 
+void ubus_notify_subscription(struct ubus_object *obj)
+{
+       bool active = !list_empty(&obj->subscribers);
+       struct ubus_msg_buf *ub;
+
+       blob_buf_init(&b, 0);
+       blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
+       blob_put_int8(&b, UBUS_ATTR_ACTIVE, active);
+
+       ub = ubus_msg_from_blob(false);
+       ubus_msg_init(ub, UBUS_MSG_NOTIFY, ++obj->invoke_seq, 0);
+       ubus_msg_send(obj->client, ub, true);
+}
+
 void ubus_notify_unsubscribe(struct ubus_subscription *s)
 {
        struct ubus_msg_buf *ub;
index 833d7bff17afbe9fda3f9dc2bb7e889764a0f76f..fc4eeddcf59cf3dbd239797749cfc8a314b97dfa 100644 (file)
--- a/ubusmsg.h
+++ b/ubusmsg.h
@@ -62,6 +62,13 @@ enum ubus_msg_type {
        UBUS_MSG_SUBSCRIBE,
        UBUS_MSG_UNSUBSCRIBE,
 
+       /*
+        * send a notification to all subscribers of an object.
+        * when sent from the server, it indicates a subscription
+        * status change
+        */
+       UBUS_MSG_NOTIFY,
+
        /* must be last */
        __UBUS_MSG_LAST,
 };
@@ -81,6 +88,8 @@ enum ubus_msg_attr {
        UBUS_ATTR_DATA,
        UBUS_ATTR_TARGET,
 
+       UBUS_ATTR_ACTIVE,
+
        /* must be last */
        UBUS_ATTR_MAX,
 };