From a2b8220f4e82e454bbc0013ee83ea3220111d92e Mon Sep 17 00:00:00 2001 From: Jan Willem Janssen 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 --- 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 -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)); }