[PATCH 3/4] Support per-service nameservers.

Forest Bond forest at alittletooquiet.net
Thu Apr 22 12:56:15 PDT 2010


Each DBus Service object has a new property "Nameservers", which is a
read/write array of strings.  When the service goes online, these nameservers
are appended to the resolver; when it goes offline, they are removed.
---
 src/connman.h |    2 +
 src/service.c |  180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 176 insertions(+), 6 deletions(-)

diff --git a/src/connman.h b/src/connman.h
index 16ded2d..96ade69 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -392,6 +392,8 @@ struct connman_service *__connman_service_create_from_network(struct connman_net
 void __connman_service_update_from_network(struct connman_network *network);
 void __connman_service_remove_from_network(struct connman_network *network);
 
+void __connman_service_replace_nameservers(
+			struct connman_service *service, GList *nameservers);
 void __connman_service_create_ipconfig(struct connman_service *service,
 								int index);
 struct connman_ipconfig *__connman_service_get_ipconfig(
diff --git a/src/service.c b/src/service.c
index 9e1dc03..0ac9e91 100644
--- a/src/service.c
+++ b/src/service.c
@@ -30,6 +30,7 @@
 #include "connman.h"
 
 #define CONNECT_TIMEOUT		120
+#define NAMESERVERS_MAXLEN	128
 
 static DBusConnection *connection = NULL;
 
@@ -76,6 +77,7 @@ struct connman_service {
 	DBusMessage *pending;
 	guint timeout;
 	struct connman_location *location;
+	GList *nameservers;
 };
 
 static void append_path(gpointer value, gpointer user_data)
@@ -245,6 +247,37 @@ static enum connman_service_error string2error(const char *error)
 	return CONNMAN_SERVICE_ERROR_UNKNOWN;
 }
 
+static char *nameservers2string(GList *nameservers) {
+	gchar *nameserver_array[NAMESERVERS_MAXLEN + 1];
+	unsigned int index;
+	GList *list;
+
+	index = 0;
+	for (list = g_list_first(nameservers); list;
+						list = g_list_next(list)) {
+		nameserver_array[index] = list->data;
+		index++;
+	}
+	/* terminating entry */
+	nameserver_array[index] = NULL;
+	return g_strjoinv(",", nameserver_array);
+}
+
+static GList *string2nameservers(const char *str) {
+	gchar **parts;
+	GList *list = NULL;
+	unsigned int index;
+
+	parts = g_strsplit(str, ",", 0);
+	for (index = 0; parts[index] != NULL; index++) {
+		list = g_list_append(list, parts[index]);
+	}
+	/* Free pointer array only; strings must be freed by caller. */
+	g_free(parts);
+
+	return list;
+}
+
 static connman_bool_t is_connecting(struct connman_service *service)
 {
 	switch (service->state) {
@@ -283,6 +316,51 @@ static connman_bool_t is_connected(const struct connman_service *service)
 	return FALSE;
 }
 
+static void nameservers_free(GList *nameservers) {
+	GList *list;
+
+	while (nameservers != NULL) {
+		list = nameservers;
+		nameservers = g_list_remove_link(nameservers, list);
+		g_free(list->data);
+		g_list_free(list);
+	}
+}
+
+static void service_enable_nameservers(struct connman_service *service) {
+	char *interface;
+	GList *list;
+
+	interface = connman_service_get_interface(service);
+	for (list = g_list_first(service->nameservers); list;
+						list = g_list_next(list)) {
+		connman_resolver_append(interface, NULL, list->data);
+	}
+}
+
+static void service_disable_nameservers(struct connman_service *service) {
+	char *interface;
+	GList *list;
+
+	interface = connman_service_get_interface(service);
+	for (list = g_list_first(service->nameservers); list;
+						list = g_list_next(list)) {
+		connman_resolver_remove(interface, NULL, list->data);
+	}
+}
+
+void __connman_service_replace_nameservers(
+			struct connman_service *service, GList *nameservers) {
+	DBG("service %p", service);
+
+	if (service->state == CONNMAN_SERVICE_STATE_ONLINE)
+		service_disable_nameservers(service);
+	nameservers_free(service->nameservers);
+	service->nameservers = nameservers;
+	if (service->state == CONNMAN_SERVICE_STATE_ONLINE)
+		service_enable_nameservers(service);
+}
+
 static struct connman_service *get_default(void)
 {
 	struct connman_service *service;
@@ -490,6 +568,54 @@ static void append_ipv4config(DBusMessageIter *iter, void *user_data)
 		__connman_ipconfig_append_ipv4config(service->ipconfig, iter);
 }
 
+static void append_nameservers(DBusMessageIter *iter, void *user_data)
+{
+	struct connman_service *service = user_data;
+	GList *list;
+
+	for (list = g_list_first(service->nameservers); list;
+						list = g_list_next(list)) {
+		dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+								&list->data);
+	}
+}
+
+static int set_nameservers(struct connman_service *service, DBusMessageIter *iter)
+{
+	DBusMessageIter sub;
+	GList *nameservers = NULL;
+	unsigned int count = 0;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return -EINVAL;
+
+	if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
+		return -EINVAL;
+
+	dbus_message_iter_recurse(iter, &sub);
+
+	while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+		char *nameserver;
+
+		count++;
+		if (count > NAMESERVERS_MAXLEN) {
+			/* too many nameservers */
+			nameservers_free(nameservers);
+			return -EINVAL;
+		}
+
+		dbus_message_iter_get_basic(&sub, &nameserver);
+
+		nameservers = g_list_append(nameservers, g_strdup(nameserver));
+
+		dbus_message_iter_next(&sub);
+	}
+
+	__connman_service_replace_nameservers(service, nameservers);
+
+	return 0;
+}
+
 static void append_proxy(DBusMessageIter *iter, void *user_data)
 {
 	struct connman_service *service = user_data;
@@ -517,6 +643,16 @@ static void ipv4_configuration_changed(struct connman_service *service)
 							service);
 }
 
+static void nameservers_changed(struct connman_service *service)
+{
+	connman_dbus_property_changed_array(service->path,
+					CONNMAN_SERVICE_INTERFACE,
+							"Nameservers",
+							DBUS_TYPE_STRING,
+							append_nameservers,
+							service);
+}
+
 static DBusMessage *get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
@@ -660,6 +796,9 @@ static DBusMessage *get_properties(DBusConnection *conn,
 	connman_dbus_dict_append_dict(&dict, "IPv4.Configuration",
 						append_ipv4config, service);
 
+	connman_dbus_dict_append_array(&dict, "Nameservers",
+				DBUS_TYPE_STRING, append_nameservers, service);
+
 	connman_dbus_dict_append_dict(&dict, "Proxy", append_proxy, service);
 
 	connman_dbus_dict_close(&array, &dict);
@@ -804,6 +943,17 @@ static DBusMessage *set_property(DBusConnection *conn,
 		ipv4_configuration_changed(service);
 
 		__connman_storage_save_service(service);
+	} else if (g_str_equal(name, "Nameservers") == TRUE) {
+		int err;
+
+		err = set_nameservers(service, &value);
+
+		if (err < 0)
+			return __connman_error_failed(msg, -err);
+
+		nameservers_changed(service);
+
+		__connman_storage_save_service(service);
 	} else
 		return __connman_error_invalid_property(msg);
 
@@ -1607,9 +1757,15 @@ int __connman_service_indicate_state(struct connman_service *service,
 	if (state == CONNMAN_SERVICE_STATE_CONFIGURATION)
 		__connman_ipconfig_enable(service->ipconfig);
 
+	if (service->state == CONNMAN_SERVICE_STATE_ONLINE)
+		service_disable_nameservers(service);
+
 	service->state = state;
 	state_changed(service);
 
+	if (state == CONNMAN_SERVICE_STATE_ONLINE)
+		service_enable_nameservers(service);
+
 	if (state == CONNMAN_SERVICE_STATE_IDLE) {
 		connman_bool_t reconnect;
 
@@ -1861,12 +2017,8 @@ int __connman_service_disconnect(struct connman_service *service)
 
 	__connman_ipconfig_disable(service->ipconfig);
 
-	if (err < 0) {
-		if (err != -EINPROGRESS)
-			return err;
-
-		return -EINPROGRESS;
-	}
+	if (err < 0)
+		return err;
 
 	return 0;
 }
@@ -2732,6 +2884,13 @@ static int service_load(struct connman_service *service)
 		__connman_ipconfig_load(service->ipconfig, keyfile,
 					service->identifier, "IPv4.");
 
+	str = g_key_file_get_string(keyfile, service->identifier,
+							"Nameservers", NULL);
+	if (str != NULL) {
+		__connman_service_replace_nameservers(
+					service, string2nameservers(str));
+	}
+
 done:
 	g_key_file_free(keyfile);
 
@@ -2865,6 +3024,15 @@ update:
 		__connman_ipconfig_save(service->ipconfig, keyfile,
 					service->identifier, "IPv4.");
 
+	if (service->nameservers != NULL) {
+		str = nameservers2string(service->nameservers);
+		if (str != NULL) {
+			g_key_file_set_string(keyfile, service->identifier,
+							"Nameservers", str);
+			g_free(str);
+		}
+	}
+
 	data = g_key_file_to_data(keyfile, &length, NULL);
 
 	if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
-- 
1.6.0.4



More information about the connman mailing list