Browse Source

ubusd: add monitor support

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Felix Fietkau 8 years ago
parent
commit
47d75dd84a
6 changed files with 136 additions and 1 deletions
  1. 1 1
      CMakeLists.txt
  2. 5 0
      ubusd.c
  3. 4 0
      ubusd.h
  4. 110 0
      ubusd_monitor.c
  5. 1 0
      ubusd_obj.c
  6. 15 0
      ubusmsg.h

+ 1 - 1
CMakeLists.txt

@@ -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)

+ 5 - 0
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;
 	}

+ 4 - 0
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

+ 110 - 0
ubusd_monitor.c

@@ -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;
+}

+ 1 - 0
ubusd_obj.c

@@ -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();
 }

+ 15 - 0
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,