ubusd: add monitor support
authorFelix Fietkau <nbd@openwrt.org>
Thu, 19 Nov 2015 21:32:11 +0000 (22:32 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 19 Nov 2015 21:32:11 +0000 (22:32 +0100)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
CMakeLists.txt
ubusd.c
ubusd.h
ubusd_monitor.c [new file with mode: 0644]
ubusd_obj.c
ubusmsg.h

index 2492e13d59ada2fac6dd616b2d5d7fce447c6124..b1fdd5b7a5dd4c54e15bb5278ed058ac2f840ff2 100644 (file)
@@ -22,7 +22,7 @@ ENDIF()
 ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c libubus-acl.c)
 TARGET_LINK_LIBRARIES(ubus ubox)
 
-ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c ubusd_acl.c)
+ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c ubusd_acl.c ubusd_monitor.c)
 TARGET_LINK_LIBRARIES(ubusd ubox blobmsg_json ${json})
 
 find_library(json NAMES json-c json)
diff --git a/ubusd.c b/ubusd.c
index aa723511e58709ab7730cd84ac11f44933b31fdd..6629720831348573ed7c6727036b67a2ea15ab68 100644 (file)
--- a/ubusd.c
+++ b/ubusd.c
@@ -136,6 +136,9 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub, bool free)
 {
        int written;
 
+       if (ub->hdr.type != UBUS_MSG_MONITOR)
+               ubusd_monitor_message(cl, ub, true);
+
        if (!cl->tx_queue[cl->txq_cur]) {
                written = ubus_msg_writev(cl->sock.fd, ub, 0);
                if (written >= ub->len + sizeof(ub->hdr))
@@ -179,6 +182,7 @@ static void handle_client_disconnect(struct ubus_client *cl)
        while (ubus_msg_head(cl))
                ubus_msg_dequeue(cl);
 
+       ubusd_monitor_disconnect(cl);
        ubusd_proto_free_client(cl);
        if (cl->pending_msg_fd >= 0)
                close(cl->pending_msg_fd);
@@ -297,6 +301,7 @@ retry:
                cl->pending_msg_fd = -1;
                cl->pending_msg_offset = 0;
                cl->pending_msg = NULL;
+               ubusd_monitor_message(cl, ub, false);
                ubusd_proto_receive_message(cl, ub);
                goto retry;
        }
diff --git a/ubusd.h b/ubusd.h
index 32fe8524ec831f17057850387bd553b5608edfba..6078e02991fd1e3cfac34f54bf96aac32268d5b0 100644 (file)
--- a/ubusd.h
+++ b/ubusd.h
@@ -84,4 +84,8 @@ int ubusd_send_event(struct ubus_client *cl, const char *id,
 
 void ubusd_acl_init(void);
 
+void ubusd_monitor_init(void);
+void ubusd_monitor_message(struct ubus_client *cl, struct ubus_msg_buf *ub, bool send);
+void ubusd_monitor_disconnect(struct ubus_client *cl);
+
 #endif
diff --git a/ubusd_monitor.c b/ubusd_monitor.c
new file mode 100644 (file)
index 0000000..82d0333
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "ubusd.h"
+
+static struct ubus_object *monitor_obj;
+static LIST_HEAD(monitors);
+
+struct ubus_monitor {
+       struct list_head list;
+       struct ubus_client *cl;
+       uint32_t seq;
+};
+
+static void
+ubusd_monitor_free(struct ubus_monitor *m)
+{
+       list_del(&m->list);
+       free(m);
+}
+
+static void
+ubusd_monitor_connect(struct ubus_client *cl, struct ubus_msg_buf *ub)
+{
+       struct ubus_monitor *m;
+
+       ubusd_monitor_disconnect(cl);
+
+       m = calloc(1, sizeof(*m));
+       m->cl = cl;
+       list_add(&m->list, &monitors);
+}
+
+void
+ubusd_monitor_disconnect(struct ubus_client *cl)
+{
+       struct ubus_monitor *m;
+
+       list_for_each_entry(m, &monitors, list) {
+               if (m->cl != cl)
+                       continue;
+
+               ubusd_monitor_free(m);
+               return;
+       }
+}
+
+void
+ubusd_monitor_message(struct ubus_client *cl, struct ubus_msg_buf *ub, bool send)
+{
+       static struct blob_buf mb;
+       struct ubus_monitor *m;
+
+       if (list_empty(&monitors))
+               return;
+
+       blob_buf_init(&mb, 0);
+       blob_put_int32(&mb, UBUS_MONITOR_CLIENT, cl->id.id);
+       blob_put_int32(&mb, UBUS_MONITOR_PEER, ub->hdr.peer);
+       blob_put_int32(&mb, UBUS_MONITOR_SEQ, ub->hdr.seq);
+       blob_put_int32(&mb, UBUS_MONITOR_TYPE, ub->hdr.type);
+       blob_put_int8(&mb, UBUS_MONITOR_SEND, send);
+       blob_put(&mb, UBUS_MONITOR_DATA, blob_data(ub->data), blob_len(ub->data));
+
+       list_for_each_entry(m, &monitors, list) {
+               ub = ubus_msg_new(mb.head, blob_raw_len(mb.head), true);
+               ub->hdr.type = UBUS_MSG_MONITOR;
+               ub->hdr.seq = ++m->seq;
+               ubus_msg_send(m->cl, ub, true);
+       }
+}
+
+static int
+ubusd_monitor_recv(struct ubus_client *cl, struct ubus_msg_buf *ub,
+                  const char *method, struct blob_attr *msg)
+{
+       /* Only root is allowed for now */
+       if (cl->uid != 0 || cl->gid != 0)
+               return UBUS_STATUS_PERMISSION_DENIED;
+
+       if (!strcmp(method, "add")) {
+               ubusd_monitor_connect(cl, ub);
+               return 0;
+       }
+
+       if (!strcmp(method, "remove")) {
+               ubusd_monitor_disconnect(cl);
+               return 0;
+       }
+
+       return UBUS_STATUS_METHOD_NOT_FOUND;
+}
+
+void
+ubusd_monitor_init(void)
+{
+       monitor_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_MONITOR);
+       if (monitor_obj != NULL)
+               monitor_obj->recv_msg = ubusd_monitor_recv;
+}
index 914de05adbb2fdcd63848fdf3bf51c2a7729eb80..08314732567e7c03f066ae8d4c5faad22f381eff 100644 (file)
@@ -232,4 +232,5 @@ static void __constructor ubusd_obj_init(void)
        ubus_init_string_tree(&path, false);
        ubusd_event_init();
        ubusd_acl_init();
+       ubusd_monitor_init();
 }
index d3d29284d70d59b4616705ccdcade0741ab40b08..398b126b6dc01833937749a110181ea0debb1476 100644 (file)
--- a/ubusmsg.h
+++ b/ubusmsg.h
@@ -23,6 +23,7 @@
 
 #define UBUS_SYSTEM_OBJECT_EVENT       1
 #define UBUS_SYSTEM_OBJECT_ACL         2
+#define UBUS_SYSTEM_OBJECT_MONITOR     3
 #define UBUS_SYSTEM_OBJECT_MAX         1024
 
 struct ubus_msghdr {
@@ -69,6 +70,8 @@ enum ubus_msg_type {
         */
        UBUS_MSG_NOTIFY,
 
+       UBUS_MSG_MONITOR,
+
        /* must be last */
        __UBUS_MSG_LAST,
 };
@@ -100,6 +103,18 @@ enum ubus_msg_attr {
        UBUS_ATTR_MAX,
 };
 
+enum ubus_monitor_attr {
+       UBUS_MONITOR_CLIENT,
+       UBUS_MONITOR_PEER,
+       UBUS_MONITOR_SEND,
+       UBUS_MONITOR_SEQ,
+       UBUS_MONITOR_TYPE,
+       UBUS_MONITOR_DATA,
+
+       /* must be last */
+       UBUS_MONITOR_MAX,
+};
+
 enum ubus_msg_status {
        UBUS_STATUS_OK,
        UBUS_STATUS_INVALID_COMMAND,