e9eec39aac
Backport upstream patches pre 2.81rc for testing purposes. Let's see what falls out! Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
321 lines
8.0 KiB
Diff
321 lines
8.0 KiB
Diff
From a2b8220f4e82e454bbc0013ee83ea3220111d92e Mon Sep 17 00:00:00 2001
|
|
From: Jan Willem Janssen <j.w.janssen@lxtreme.nl>
|
|
Date: Mon, 25 Mar 2019 12:42:23 +0100
|
|
Subject: [PATCH 52/57] Improved UBus supported
|
|
|
|
- aligned the handling of UBus connections with the DBus code as it
|
|
makes it a bit easier to comprehend;
|
|
- added logging to the various UBus calls to aid debugging from an
|
|
enduser point of view, but be careful to not flood the logs;
|
|
- show the (lack of) support for UBus in the configuration string.
|
|
|
|
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
|
---
|
|
src/config.h | 4 ++
|
|
src/dnsmasq.c | 32 +++++++++++-
|
|
src/dnsmasq.h | 6 +++
|
|
src/ubus.c | 138 ++++++++++++++++++++++++++++++++++++++++++--------
|
|
4 files changed, 157 insertions(+), 23 deletions(-)
|
|
|
|
--- a/src/config.h
|
|
+++ b/src/config.h
|
|
@@ -362,6 +362,10 @@ static char *compile_opts =
|
|
"no-"
|
|
#endif
|
|
"DBus "
|
|
+#ifndef HAVE_UBUS
|
|
+"no-"
|
|
+#endif
|
|
+"UBus "
|
|
#ifndef LOCALEDIR
|
|
"no-"
|
|
#endif
|
|
--- a/src/dnsmasq.c
|
|
+++ b/src/dnsmasq.c
|
|
@@ -420,6 +420,16 @@ int main (int argc, char **argv)
|
|
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
|
|
#endif
|
|
|
|
+ if (option_bool(OPT_UBUS))
|
|
+#ifdef HAVE_UBUS
|
|
+ {
|
|
+ daemon->ubus = NULL;
|
|
+ ubus_init();
|
|
+ }
|
|
+#else
|
|
+ die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
|
|
+#endif
|
|
+
|
|
if (daemon->port != 0)
|
|
pre_allocate_sfds();
|
|
|
|
@@ -811,6 +821,16 @@ int main (int argc, char **argv)
|
|
}
|
|
#endif
|
|
|
|
+#ifdef HAVE_UBUS
|
|
+ if (option_bool(OPT_UBUS))
|
|
+ {
|
|
+ if (daemon->ubus)
|
|
+ my_syslog(LOG_INFO, _("UBus support enabled: connected to system bus"));
|
|
+ else
|
|
+ my_syslog(LOG_INFO, _("UBus support enabled: bus connection pending"));
|
|
+ }
|
|
+#endif
|
|
+
|
|
#ifdef HAVE_DNSSEC
|
|
if (option_bool(OPT_DNSSEC_VALID))
|
|
{
|
|
@@ -999,7 +1019,7 @@ int main (int argc, char **argv)
|
|
|
|
#ifdef HAVE_UBUS
|
|
if (option_bool(OPT_UBUS))
|
|
- set_ubus_listeners();
|
|
+ set_ubus_listeners();
|
|
#endif
|
|
|
|
#ifdef HAVE_DHCP
|
|
@@ -1134,7 +1154,15 @@ int main (int argc, char **argv)
|
|
|
|
#ifdef HAVE_UBUS
|
|
if (option_bool(OPT_UBUS))
|
|
- check_ubus_listeners();
|
|
+ {
|
|
+ /* if we didn't create a UBus connection, retry now. */
|
|
+ if (!daemon->ubus)
|
|
+ {
|
|
+ ubus_init();
|
|
+ }
|
|
+
|
|
+ check_ubus_listeners();
|
|
+ }
|
|
#endif
|
|
|
|
check_dns_listeners(now);
|
|
--- a/src/dnsmasq.h
|
|
+++ b/src/dnsmasq.h
|
|
@@ -1130,6 +1130,11 @@ extern struct daemon {
|
|
#ifdef HAVE_DBUS
|
|
struct watch *watches;
|
|
#endif
|
|
+ /* UBus stuff */
|
|
+#ifdef HAVE_UBUS
|
|
+ /* void * here to avoid depending on ubus headers outside ubus.c */
|
|
+ void *ubus;
|
|
+#endif
|
|
|
|
/* TFTP stuff */
|
|
struct tftp_transfer *tftp_trans, *tftp_done_trans;
|
|
@@ -1467,6 +1472,7 @@ void emit_dbus_signal(int action, struct
|
|
|
|
/* ubus.c */
|
|
#ifdef HAVE_UBUS
|
|
+void ubus_init(void);
|
|
void set_ubus_listeners(void);
|
|
void check_ubus_listeners(void);
|
|
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
|
|
--- a/src/ubus.c
|
|
+++ b/src/ubus.c
|
|
@@ -20,29 +20,112 @@
|
|
|
|
#include <libubus.h>
|
|
|
|
-static struct ubus_context *ubus = NULL;
|
|
static struct blob_buf b;
|
|
+static int notify;
|
|
+static int error_logged = 0;
|
|
|
|
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg);
|
|
-static struct ubus_method ubus_object_methods[] = {
|
|
- {.name = "metrics", .handler = ubus_handle_metrics},
|
|
+
|
|
+static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
|
|
+
|
|
+static const struct ubus_method ubus_object_methods[] = {
|
|
+ UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
|
|
};
|
|
|
|
-static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
|
|
+static struct ubus_object_type ubus_object_type =
|
|
+ UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
|
|
|
|
static struct ubus_object ubus_object = {
|
|
.name = "dnsmasq",
|
|
.type = &ubus_object_type,
|
|
.methods = ubus_object_methods,
|
|
.n_methods = ARRAY_SIZE(ubus_object_methods),
|
|
+ .subscribe_cb = ubus_subscribe_cb,
|
|
};
|
|
|
|
+static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
|
|
+{
|
|
+ (void)ctx;
|
|
+
|
|
+ my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");
|
|
+ notify = obj->has_subscribers;
|
|
+}
|
|
+
|
|
+static void ubus_destroy(struct ubus_context *ubus)
|
|
+{
|
|
+ // Forces re-initialization when we're reusing the same definitions later on.
|
|
+ ubus_object.id = 0;
|
|
+ ubus_object_type.id = 0;
|
|
+
|
|
+ ubus_free(ubus);
|
|
+ daemon->ubus = NULL;
|
|
+}
|
|
+
|
|
+static void ubus_disconnect_cb(struct ubus_context *ubus)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = ubus_reconnect(ubus, NULL);
|
|
+ if (ret)
|
|
+ {
|
|
+ my_syslog(LOG_ERR, _("Cannot reconnect to UBus: %s"), ubus_strerror(ret));
|
|
+
|
|
+ ubus_destroy(ubus);
|
|
+ }
|
|
+}
|
|
+
|
|
+void ubus_init()
|
|
+{
|
|
+ struct ubus_context *ubus = NULL;
|
|
+ int ret = 0;
|
|
+
|
|
+ ubus = ubus_connect(NULL);
|
|
+ if (!ubus)
|
|
+ {
|
|
+ if (!error_logged)
|
|
+ {
|
|
+ my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed"));
|
|
+ error_logged = 1;
|
|
+ }
|
|
+
|
|
+ ubus_destroy(ubus);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = ubus_add_object(ubus, &ubus_object);
|
|
+ if (ret)
|
|
+ {
|
|
+ if (!error_logged)
|
|
+ {
|
|
+ my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));
|
|
+ error_logged = 1;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ubus->connection_lost = ubus_disconnect_cb;
|
|
+ daemon->ubus = ubus;
|
|
+ error_logged = 0;
|
|
+
|
|
+ my_syslog(LOG_INFO, _("Connected to system UBus"));
|
|
+}
|
|
+
|
|
void set_ubus_listeners()
|
|
{
|
|
+ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
|
if (!ubus)
|
|
- return;
|
|
+ {
|
|
+ if (!error_logged)
|
|
+ {
|
|
+ my_syslog(LOG_ERR, _("Cannot set UBus listeners: no connection"));
|
|
+ error_logged = 1;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ error_logged = 0;
|
|
|
|
poll_listen(ubus->sock.fd, POLLIN);
|
|
poll_listen(ubus->sock.fd, POLLERR);
|
|
@@ -51,46 +134,57 @@ void set_ubus_listeners()
|
|
|
|
void check_ubus_listeners()
|
|
{
|
|
+ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
|
if (!ubus)
|
|
{
|
|
- ubus = ubus_connect(NULL);
|
|
- if (!ubus)
|
|
- return;
|
|
- ubus_add_object(ubus, &ubus_object);
|
|
+ if (!error_logged)
|
|
+ {
|
|
+ my_syslog(LOG_ERR, _("Cannot poll UBus listeners: no connection"));
|
|
+ error_logged = 1;
|
|
+ }
|
|
+ return;
|
|
}
|
|
|
|
+ error_logged = 0;
|
|
+
|
|
if (poll_check(ubus->sock.fd, POLLIN))
|
|
ubus_handle_event(ubus);
|
|
|
|
- if (poll_check(ubus->sock.fd, POLLHUP))
|
|
+ if (poll_check(ubus->sock.fd, POLLHUP | POLLERR))
|
|
{
|
|
- ubus_free(ubus);
|
|
- ubus = NULL;
|
|
+ my_syslog(LOG_INFO, _("Disconnecting from UBus"));
|
|
+
|
|
+ ubus_destroy(ubus);
|
|
}
|
|
}
|
|
|
|
-
|
|
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
int i;
|
|
- blob_buf_init(&b, 0);
|
|
|
|
- for(i=0; i < __METRIC_MAX; i++)
|
|
+ (void)obj;
|
|
+ (void)method;
|
|
+ (void)msg;
|
|
+
|
|
+ blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
|
+
|
|
+ for (i=0; i < __METRIC_MAX; i++)
|
|
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
|
|
|
|
- ubus_send_reply(ctx, req, b.head);
|
|
-
|
|
- return 0;
|
|
+ return ubus_send_reply(ctx, req, b.head);
|
|
}
|
|
|
|
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
|
|
{
|
|
- if (!ubus || !ubus_object.has_subscribers)
|
|
+ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
|
+ int ret;
|
|
+
|
|
+ if (!ubus || !notify)
|
|
return;
|
|
|
|
- blob_buf_init(&b, 0);
|
|
+ blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
|
if (mac)
|
|
blobmsg_add_string(&b, "mac", mac);
|
|
if (ip)
|
|
@@ -100,7 +194,9 @@ void ubus_event_bcast(const char *type,
|
|
if (interface)
|
|
blobmsg_add_string(&b, "interface", interface);
|
|
|
|
- ubus_notify(ubus, &ubus_object, type, b.head, -1);
|
|
+ ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
|
|
+ if (!ret)
|
|
+ my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
|
|
}
|
|
|
|
|