mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
- 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.
204 lines
4.9 KiB
C
204 lines
4.9 KiB
C
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 dated June, 1991, or
|
|
(at your option) version 3 dated 29 June, 2007.
|
|
|
|
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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "dnsmasq.h"
|
|
|
|
#ifdef HAVE_UBUS
|
|
|
|
#include <libubus.h>
|
|
|
|
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 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 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)
|
|
{
|
|
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);
|
|
poll_listen(ubus->sock.fd, POLLHUP);
|
|
}
|
|
|
|
void check_ubus_listeners()
|
|
{
|
|
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
|
if (!ubus)
|
|
{
|
|
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 | POLLERR))
|
|
{
|
|
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;
|
|
|
|
(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]);
|
|
|
|
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)
|
|
{
|
|
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
|
int ret;
|
|
|
|
if (!ubus || !notify)
|
|
return;
|
|
|
|
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
|
if (mac)
|
|
blobmsg_add_string(&b, "mac", mac);
|
|
if (ip)
|
|
blobmsg_add_string(&b, "ip", ip);
|
|
if (name)
|
|
blobmsg_add_string(&b, "name", name);
|
|
if (interface)
|
|
blobmsg_add_string(&b, "interface", interface);
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
#endif /* HAVE_UBUS */
|