Re: [PATCH v2] dns: update dnsmasq DNS nameservers using its SetServers DBus method



On Tue, 2012-07-31 at 16:39 -0400, Mathieu Trudel-Lapierre wrote:
> Instead of rewriting the dnsmasq configuration file and restarting dnsmasq,
> which leaves a small period of time during which no resolution can occur
> because dnsmasq is not yet fully started; use the dnsmasq DBus methods to
> update nameservers; SetServers allows setting the nameservers without
> restarting the daemon.
> 
> There is still a short period of time during which, on startup, dnsmasq is
> started but has not yet initialized DBus completely; handle this case by
> introducing a new PLUGIN_APPEARED signal that can be emitted once the name
> is found on the system bus.

Summarizing off-list conversation...

This patch would remove the ability to specify an IPv6 scope ID since
the dnsmasq dbus interface only accepts addresses, and not any
additional qualifiers.  Also the usage of straight D-Bus is somewhat
sub-optimal, but necessary due to the dnsmasq D-Bus interface oddities.

To fix both those issues, I've sent a patch to dnsmasq upstream to add a
new method call.  Ideally when that patch is accepted, we add support to
the NM dnsmasq plugin to first try the new method (which should be
substantially less code than the old one) and if that method is not
supported, fall back to the old method.

The patches should show up here when they get through any moderation:

http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2012q3/thread.html

but I'll post them as replies to this thread too.

Dan

> ---
>  src/dns-manager/nm-dns-dnsmasq.c |  339 ++++++++++++++++++++++++--------------
>  src/dns-manager/nm-dns-manager.c |   24 +++
>  src/dns-manager/nm-dns-plugin.c  |   16 ++
>  src/dns-manager/nm-dns-plugin.h  |    1 +
>  4 files changed, 255 insertions(+), 125 deletions(-)
> 
> diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
> index 9090e26..9ad2dfc 100644
> --- a/src/dns-manager/nm-dns-dnsmasq.c
> +++ b/src/dns-manager/nm-dns-dnsmasq.c
> @@ -29,11 +29,16 @@
>  #include <glib.h>
>  #include <glib/gi18n.h>
>  
> +#include <dbus/dbus.h>
> +#include <dbus/dbus-glib-lowlevel.h>
> +#include <dbus/dbus-glib.h>
> +
>  #include "nm-dns-dnsmasq.h"
>  #include "nm-logging.h"
>  #include "nm-ip4-config.h"
>  #include "nm-ip6-config.h"
>  #include "nm-dns-utils.h"
> +#include "nm-dbus-manager.h"
>  
>  G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
>  
> @@ -43,8 +48,13 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
>  #define CONFFILE LOCALSTATEDIR "/run/nm-dns-dnsmasq.conf"
>  #define CONFDIR SYSCONFDIR "/NetworkManager/dnsmasq.d"
>  
> +#define DNSMASQ_DBUS_SERVICE "uk.org.thekelleys.dnsmasq"
> +#define DNSMASQ_DBUS_PATH "/uk/org/thekelleys/dnsmasq"
> +#define DNSMASQ_DBUS_INTERFACE "uk.org.thekelleys.dnsmasq"
> +
>  typedef struct {
> -	guint32 foo;
> +	NMDBusManager *dbus_mgr;
> +	guint name_owner_id;
>  } NMDnsDnsmasqPrivate;
>  
>  /*******************************************/
> @@ -69,12 +79,11 @@ find_dnsmasq (void)
>  }
>  
>  static gboolean
> -add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
> +add_ip4_config (DBusMessage *message, NMIP4Config *ip4, gboolean split)
>  {
> -	char buf[INET_ADDRSTRLEN + 1];
> -	struct in_addr addr;
>  	int n, i;
>  	gboolean added = FALSE;
> +	guint32 addr;
>  
>  	if (split) {
>  		char **domains, **iter;
> @@ -83,17 +92,17 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
>  		 * per domain (and the manpage says this too) so only use the first
>  		 * nameserver here.
>  		 */
> -		addr.s_addr = nm_ip4_config_get_nameserver (ip4, 0);
> -		memset (&buf[0], 0, sizeof (buf));
> -		if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
> -			return FALSE;
> +		addr = g_htonl(nm_ip4_config_get_nameserver (ip4, 0));
> +		dbus_message_append_args (message,
> +		                          DBUS_TYPE_UINT32, &addr,
> +		                          DBUS_TYPE_INVALID);
>  
>  		/* searches are preferred over domains */
>  		n = nm_ip4_config_get_num_searches (ip4);
>  		for (i = 0; i < n; i++) {
> -			g_string_append_printf (str, "server=/%s/%s\n",
> -				                    nm_ip4_config_get_search (ip4, i),
> -				                    buf);
> +			dbus_message_append_args (message,
> +			                          DBUS_TYPE_STRING, nm_ip4_config_get_search (ip4, i),
> +			                          DBUS_TYPE_INVALID);
>  			added = TRUE;
>  		}
>  
> @@ -101,9 +110,9 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
>  			/* If not searches, use any domains */
>  			n = nm_ip4_config_get_num_domains (ip4);
>  			for (i = 0; i < n; i++) {
> -				g_string_append_printf (str, "server=/%s/%s\n",
> -							            nm_ip4_config_get_domain (ip4, i),
> -							            buf);
> +				dbus_message_append_args (message,
> +				                          DBUS_TYPE_STRING, nm_ip4_config_get_domain (ip4, i),
> +				                          DBUS_TYPE_INVALID);
>  				added = TRUE;
>  			}
>  		}
> @@ -114,7 +123,9 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
>  		domains = nm_dns_utils_get_ip4_rdns_domains (ip4);
>  		if (domains) {
>  			for (iter = domains; iter && *iter; iter++)
> -				g_string_append_printf (str, "server=/%s/%s\n", *iter, buf);
> +				dbus_message_append_args (message,
> +				                          DBUS_TYPE_STRING, *iter,
> +				                          DBUS_TYPE_INVALID);
>  			g_strfreev (domains);
>  			added = TRUE;
>  		}
> @@ -124,66 +135,20 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
>  	if (!added) {
>  		n = nm_ip4_config_get_num_nameservers (ip4);
>  		for (i = 0; i < n; i++) {
> -			memset (&buf[0], 0, sizeof (buf));
> -			addr.s_addr = nm_ip4_config_get_nameserver (ip4, i);
> -			if (inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
> -				g_string_append_printf (str, "server=%s\n", buf);
> +			addr = g_htonl(nm_ip4_config_get_nameserver (ip4, i));
> +			dbus_message_append_args (message,
> +			                          DBUS_TYPE_UINT32, &addr,
> +			                          DBUS_TYPE_INVALID);
>  		}
>  	}
>  
>  	return TRUE;
>  }
>  
> -#define IP6_ADDR_BUFLEN (INET6_ADDRSTRLEN + 50)
> -
> -static char *
> -ip6_addr_to_string (const struct in6_addr *addr, const char *iface)
> -{
> -	char *buf, *p;
> -
> -	/* allocate enough space for the address + interface name */
> -	buf = g_malloc0 (IP6_ADDR_BUFLEN + 1);
> -
> -	/* inet_ntop is probably supposed to do this for us, but it doesn't */
> -	if (IN6_IS_ADDR_V4MAPPED (addr)) {
> -		if (!inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, IP6_ADDR_BUFLEN))
> -			goto error;
> -		return buf;
> -	}
> -
> -	if (!inet_ntop (AF_INET6, addr, buf, IP6_ADDR_BUFLEN))
> -		goto error;
> -
> -	/* In the case of addr being a link-local address, inet_ntop can either
> -	 * return an address with scope identifier already in place (like
> -	 * fe80::202:b3ff:fe8d:7aaf%wlan0) or it returns an address without
> -	 * scope identifier at all (like fe80::202:b3ff:fe8d:7aaf)
> -	 */
> -	p = strchr (buf, '%');
> -	if (p) {
> -		/* If we got a scope identifier, we need to replace the '%'
> -		 * with '@', since dnsmasq supports '%' in server= addresses
> -		 * only since version 2.58 and up
> -		 */
> -		*p = '@';
> -	} else if (IN6_IS_ADDR_LINKLOCAL (addr)) {
> -		/* If we got no scope identifier at all append the interface name */
> -		strncat (buf, "@", IP6_ADDR_BUFLEN - strlen (buf));
> -		strncat (buf, iface, IP6_ADDR_BUFLEN - strlen (buf));
> -	}
> -
> -	return buf;
> -
> -error:
> -	g_free (buf);
> -	return NULL;
> -}
> -
>  static gboolean
> -add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *iface)
> +add_ip6_config (DBusMessage *message, NMIP6Config *ip6, gboolean split, const char *iface)
>  {
>  	const struct in6_addr *addr;
> -	char *buf;
>  	int n, i;
>  	gboolean added = FALSE;
>  
> @@ -193,16 +158,31 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *ifac
>  		 * the first nameserver here.
>  		 */
>  		addr = nm_ip6_config_get_nameserver (ip6, 0);
> -		buf = ip6_addr_to_string (addr, iface);
> -		if (!buf)
> -			return FALSE;
> +		dbus_message_append_args (message,
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[0],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[1],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[2],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[3],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[4],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[5],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[6],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[7],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[8],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[9],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[10],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[11],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[12],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[13],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[14],
> +		                          DBUS_TYPE_BYTE, &addr->s6_addr[15],
> +		                          DBUS_TYPE_INVALID);
>  
>  		/* searches are preferred over domains */
>  		n = nm_ip6_config_get_num_searches (ip6);
>  		for (i = 0; i < n; i++) {
> -			g_string_append_printf (str, "server=/%s/%s\n",
> -				                    nm_ip6_config_get_search (ip6, i),
> -				                    buf);
> +			dbus_message_append_args (message,
> +			                          DBUS_TYPE_STRING, nm_ip6_config_get_search (ip6, i),
> +			                          DBUS_TYPE_INVALID);
>  			added = TRUE;
>  		}
>  
> @@ -210,14 +190,12 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *ifac
>  			/* If not searches, use any domains */
>  			n = nm_ip6_config_get_num_domains (ip6);
>  			for (i = 0; i < n; i++) {
> -				g_string_append_printf (str, "server=/%s/%s\n",
> -							            nm_ip6_config_get_domain (ip6, i),
> -							            buf);
> +				dbus_message_append_args (message,
> +				                          DBUS_TYPE_STRING, nm_ip6_config_get_domain (ip6, i),
> +				                          DBUS_TYPE_INVALID);
>  				added = TRUE;
>  			}
>  		}
> -
> -		g_free (buf);
>  	}
>  
>  	/* If no searches or domains, just add the namservers */
> @@ -225,11 +203,24 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *ifac
>  		n = nm_ip6_config_get_num_nameservers (ip6);
>  		for (i = 0; i < n; i++) {
>  			addr = nm_ip6_config_get_nameserver (ip6, i);
> -			buf = ip6_addr_to_string (addr, iface);
> -			if (buf) {
> -				g_string_append_printf (str, "server=%s\n", buf);
> -				g_free (buf);
> -			}
> +			dbus_message_append_args (message,
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[0],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[1],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[2],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[3],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[4],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[5],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[6],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[7],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[8],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[9],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[10],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[11],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[12],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[13],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[14],
> +			                          DBUS_TYPE_BYTE, &addr->s6_addr[15],
> +			                          DBUS_TYPE_INVALID);
>  		}
>  	}
>  
> @@ -237,55 +228,28 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *ifac
>  }
>  
>  static gboolean
> -update (NMDnsPlugin *plugin,
> -        const GSList *vpn_configs,
> -        const GSList *dev_configs,
> -        const GSList *other_configs,
> -        const char *hostname,
> -        const char *iface)
> +start_dnsmasq (NMDnsDnsmasq *self)
>  {
> -	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
> +	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
> +	const char *argv[13];
> +	char *dnsmasq_owner;
> + 	GError *error = NULL;
>  	GString *conf;
> -	GSList *iter;
> -	const char *argv[12];
> -	GError *error = NULL;
> + 	GPid pid = 0;
>  	int ignored;
> -	GPid pid = 0;
>  
> -	/* Kill the old dnsmasq; there doesn't appear to be a way to get dnsmasq
> -	 * to reread the config file using SIGHUP or similar.  This is a small race
> -	 * here when restarting dnsmasq when DNS requests could go to the upstream
> -	 * servers instead of to dnsmasq.
> -	 */
> -	nm_dns_plugin_child_kill (plugin);
> +	/* dnsmasq is probably already started; if it's the case, don't do
> +	 * anything more.
> + 	 */
> +	dnsmasq_owner = nm_dbus_manager_get_name_owner (priv->dbus_mgr, DNSMASQ_DBUS_SERVICE, NULL);
> +	if (dnsmasq_owner != NULL)
> +		return TRUE;
> +
> +	/* Start dnsmasq */
>  
>  	/* Build up the new dnsmasq config file */
>  	conf = g_string_sized_new (150);
>  
> -	/* Use split DNS for VPN configs */
> -	for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) {
> -		if (NM_IS_IP4_CONFIG (iter->data))
> -			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE);
> -		else if (NM_IS_IP6_CONFIG (iter->data))
> -			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE, iface);
> -	}
> -
> -	/* Now add interface configs without split DNS */
> -	for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) {
> -		if (NM_IS_IP4_CONFIG (iter->data))
> -			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
> -		else if (NM_IS_IP6_CONFIG (iter->data))
> -			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface);
> -	}
> -
> -	/* And any other random configs */
> -	for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) {
> -		if (NM_IS_IP4_CONFIG (iter->data))
> -			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
> -		else if (NM_IS_IP6_CONFIG (iter->data))
> -			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface);
> -	}
> -
>  	/* Write out the config file */
>  	if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) {
>  		nm_log_warn (LOGD_DNS, "Failed to write dnsmasq config file %s: (%d) %s",
> @@ -310,8 +274,9 @@ update (NMDnsPlugin *plugin,
>  	argv[7] = "--conf-file=" CONFFILE;
>  	argv[8] = "--cache-size=400";
>  	argv[9] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */
> -	argv[10] = "--conf-dir=" CONFDIR;
> -	argv[11] = NULL;
> +	argv[10] = "--enable-dbus";
> +	argv[11] = "--conf-dir=" CONFDIR;
> +	argv[12] = NULL;
>  
>  	/* And finally spawn dnsmasq */
>  	pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq");
> @@ -321,8 +286,114 @@ out:
>  	return pid ? TRUE : FALSE;
>  }
>  
> +static gboolean
> +update (NMDnsPlugin *plugin,
> +        const GSList *vpn_configs,
> +        const GSList *dev_configs,
> +        const GSList *other_configs,
> +        const char *hostname,
> +        const char *iface)
> +{
> +	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
> +	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
> +	DBusConnection *connection;
> +	DBusMessage *message = NULL;
> +	GSList *iter;
> +	GError *error = NULL;
> +	gboolean have_dnsmasq = FALSE;
> +	gboolean ret = FALSE;
> +	dbus_bool_t result;
> +
> +	have_dnsmasq = start_dnsmasq (self);
> +
> +	if (!have_dnsmasq)
> +		goto out;
> +
> +	connection = nm_dbus_manager_get_dbus_connection (priv->dbus_mgr);
> +	if (!connection) {
> +		nm_log_warn (LOGD_DNS, "Could not get the system bus to speak to dnsmasq.");
> +		goto out;
> +	}
> +
> +	message = dbus_message_new_method_call (DNSMASQ_DBUS_SERVICE, DNSMASQ_DBUS_PATH,
> +	                                        DNSMASQ_DBUS_INTERFACE, "SetServers");
> +
> +	/* Use split DNS for VPN configs */
> +	for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) {
> +		if (NM_IS_IP4_CONFIG (iter->data))
> +			add_ip4_config (message, NM_IP4_CONFIG (iter->data), TRUE);
> +		else if (NM_IS_IP6_CONFIG (iter->data))
> +			add_ip6_config (message, NM_IP6_CONFIG (iter->data), TRUE, iface);
> +	}
> +
> +	/* Now add interface configs without split DNS */
> +	for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) {
> +		if (NM_IS_IP4_CONFIG (iter->data))
> +			add_ip4_config (message, NM_IP4_CONFIG (iter->data), FALSE);
> +		else if (NM_IS_IP6_CONFIG (iter->data))
> +			add_ip6_config (message, NM_IP6_CONFIG (iter->data), FALSE, iface);
> +	}
> +
> +	/* And any other random configs */
> +	for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) {
> +		if (NM_IS_IP4_CONFIG (iter->data))
> +			add_ip4_config (message, NM_IP4_CONFIG (iter->data), FALSE);
> +		else if (NM_IS_IP6_CONFIG (iter->data))
> +			add_ip6_config (message, NM_IP6_CONFIG (iter->data), FALSE, iface);
> +	}
> +
> +	if (!nm_dbus_manager_get_name_owner (priv->dbus_mgr, DNSMASQ_DBUS_SERVICE, &error)) {
> +		if (error)
> +			nm_log_warn (LOGD_DNS, "dnsmasq owner not found on bus: %s", error->message);
> +		goto out;
> +	}
> +
> +	result = dbus_connection_send (connection, message, NULL);
> +	if (!result) {
> +		nm_log_err (LOGD_DNS, "Could not send dnsmasq SetServers method.");
> +		goto out;
> +	}
> +
> +	ret = TRUE;
> +
> +out:
> +	if (message)
> +		dbus_message_unref (message);
> +
> +	return ret;
> +}
> +
>  /****************************************************************/
>  
> +static void
> +name_owner_changed_cb (NMDBusManager *dbus_mgr,
> +                       const char *name,
> +                       const char *old_owner,
> +                       const char *new_owner,
> +                       gpointer user_data)
> +{
> +	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data);
> +	gboolean old_owner_good = (old_owner && strlen (old_owner));
> +	gboolean new_owner_good = (new_owner && strlen (new_owner));
> +
> +	/* Can't handle the signal if its not from dnsmasq */
> +	if (strcmp (DNSMASQ_DBUS_SERVICE, name))
> +		return;
> +
> +	if (!old_owner_good && new_owner_good) {
> +		nm_log_warn (LOGD_DNS, "dnsmasq appeared on DBus: %s",
> +		             new_owner);
> +		g_signal_emit_by_name (self, NM_DNS_PLUGIN_APPEARED);
> +	} else if (old_owner_good && new_owner_good) {
> +		nm_log_dbg (LOGD_DNS, "DBus name owner for dnsmasq changed: %s -> %s",
> +		             old_owner, new_owner);
> +		g_signal_emit_by_name (self, NM_DNS_PLUGIN_APPEARED);
> +	} else {
> +		nm_log_warn (LOGD_DNS, "dnsmasq disappeared from the bus.");
> +		g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED);
> +	}
> +}
> +
>  static const char *
>  dm_exit_code_to_msg (int status)
>  {
> @@ -400,13 +471,31 @@ nm_dns_dnsmasq_new (void)
>  static void
>  nm_dns_dnsmasq_init (NMDnsDnsmasq *self)
>  {
> +	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
> +
> +	priv->dbus_mgr = nm_dbus_manager_get ();
> +
> +	g_assert (priv->dbus_mgr);
> +
> +	priv->name_owner_id = g_signal_connect (priv->dbus_mgr,
> +	                                        NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
> +	                                        G_CALLBACK (name_owner_changed_cb),
> +	                                        self);
>  }
>  
>  static void
>  dispose (GObject *object)
>  {
> +	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (object);
> +
>  	unlink (CONFFILE);
>  
> +	if (priv->dbus_mgr) {
> +		if (priv->name_owner_id)
> +			g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id);
> +		g_object_unref (priv->dbus_mgr);
> +	}
> +
>  	G_OBJECT_CLASS (nm_dns_dnsmasq_parent_class)->dispose (object);
>  }
>  
> diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
> index 38ef08e..3197c27 100644
> --- a/src/dns-manager/nm-dns-manager.c
> +++ b/src/dns-manager/nm-dns-manager.c
> @@ -781,6 +781,27 @@ update_dns (NMDnsManager *self,
>  }
>  
>  static void
> +plugin_appeared (NMDnsPlugin *plugin, gpointer user_data)
> +{
> +	NMDnsManager *self = NM_DNS_MANAGER (user_data);
> +	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
> +	GError *error = NULL;
> +
> +	/* Not applicable to non-caching plugins */
> +	if (!nm_dns_plugin_is_caching (plugin))
> +		return;
> +
> +	/* Try to update DNS again; since it's now available on the bus this
> +	 * might work. */
> +	if (!update_dns (self, priv->last_iface, FALSE, &error)) {
> +		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
> +		             error ? error->code : -1,
> +		             error && error->message ? error->message : "(unknown)");
> +		g_clear_error (&error);
> +	}
> +}
> +
> +static void
>  plugin_failed (NMDnsPlugin *plugin, gpointer user_data)
>  {
>  	NMDnsManager *self = NM_DNS_MANAGER (user_data);
> @@ -1079,6 +1100,9 @@ load_plugins (NMDnsManager *self, const char **plugins)
>  
>  			nm_log_info (LOGD_DNS, "DNS: loaded plugin %s", nm_dns_plugin_get_name (plugin));
>  			priv->plugins = g_slist_append (priv->plugins, plugin);
> +			g_signal_connect (plugin, NM_DNS_PLUGIN_APPEARED,
> +			                  G_CALLBACK (plugin_appeared),
> +			                  self);
>  			g_signal_connect (plugin, NM_DNS_PLUGIN_FAILED,
>  			                  G_CALLBACK (plugin_failed),
>  			                  self);
> diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
> index b26f2b9..9500118 100644
> --- a/src/dns-manager/nm-dns-plugin.c
> +++ b/src/dns-manager/nm-dns-plugin.c
> @@ -44,6 +44,7 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A
>  
>  enum {
>  	FAILED,
> +	APPEARED,
>  	CHILD_QUIT,
>  	LAST_SIGNAL
>  };
> @@ -133,6 +134,12 @@ watch_cb (GPid pid, gint status, gpointer user_data)
>  	g_free (priv->progname);
>  	priv->progname = NULL;
>  
> +	if (priv->pidfile) {
> +		unlink (priv->pidfile);
> +		g_free (priv->pidfile);
> +		priv->pidfile = NULL;
> +	}
> +
>  	g_signal_emit (self, signals[CHILD_QUIT], 0, status);
>  }
>  
> @@ -316,6 +323,15 @@ nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class)
>  					  g_cclosure_marshal_VOID__VOID,
>  					  G_TYPE_NONE, 0);
>  
> +	signals[APPEARED] =
> +		g_signal_new (NM_DNS_PLUGIN_APPEARED,
> +					  G_OBJECT_CLASS_TYPE (object_class),
> +					  G_SIGNAL_RUN_FIRST,
> +					  G_STRUCT_OFFSET (NMDnsPluginClass, failed),
> +					  NULL, NULL,
> +					  g_cclosure_marshal_VOID__VOID,
> +					  G_TYPE_NONE, 0);
> +
>  	signals[CHILD_QUIT] =
>  		g_signal_new (NM_DNS_PLUGIN_CHILD_QUIT,
>  					  G_OBJECT_CLASS_TYPE (object_class),
> diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h
> index de4ad84..796ec6d 100644
> --- a/src/dns-manager/nm-dns-plugin.h
> +++ b/src/dns-manager/nm-dns-plugin.h
> @@ -30,6 +30,7 @@
>  #define NM_DNS_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass))
>  
>  #define NM_DNS_PLUGIN_FAILED "failed"
> +#define NM_DNS_PLUGIN_APPEARED "appeared"
>  #define NM_DNS_PLUGIN_CHILD_QUIT "child-quit"
>  
>  typedef struct {




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]