[PATCH v5 27/42] provider: Add callback when creating vpn provider

Jukka Rissanen jukka.rissanen at linux.intel.com
Mon Nov 12 04:07:43 PST 2012


Because the vpnd Create() in manager API only creates and does
not connect the vpn, we must do the connect part after the
vpn is created. This requires a callback which is called when
the connection is established. Eventually this patch becomes
obsolete because the CreateProvider() connman API is deprecated.
---
 include/provider.h |   4 +-
 plugins/vpn.c      | 168 +++++++++++++++++++++++++++++++++++++++--------------
 src/provider.c     |  42 ++++++++++++--
 3 files changed, 166 insertions(+), 48 deletions(-)

diff --git a/include/provider.h b/include/provider.h
index 548bd61..c9a3b91 100644
--- a/include/provider.h
+++ b/include/provider.h
@@ -112,6 +112,8 @@ int connman_provider_append_route(struct connman_provider *provider,
 
 const char *connman_provider_get_driver_name(struct connman_provider *provider);
 const char *connman_provider_get_save_group(struct connman_provider *provider);
+typedef void (* connection_ready_cb) (DBusMessage *msg, int error_code,
+					void *user_data);
 
 struct connman_provider_driver {
 	const char *name;
@@ -125,7 +127,7 @@ struct connman_provider_driver {
 				const char *key, const char *value);
 	const char * (*get_property) (struct connman_provider *provider,
 				const char *key);
-	int (*create) (DBusMessage *msg);
+	int (*create) (DBusMessage *msg, connection_ready_cb callback);
 	int (*set_routes) (struct connman_provider *provider,
 				enum connman_provider_route_type type);
 	connman_bool_t (*check_routes) (struct connman_provider *provider);
diff --git a/plugins/vpn.c b/plugins/vpn.c
index c0cde95..b29dcc0 100644
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -60,6 +60,12 @@ struct vpn_route {
 	char *gateway;
 };
 
+struct config_create_data {
+	connection_ready_cb callback;
+	DBusMessage *message;
+	char *path;
+};
+
 struct connection_data {
 	char *path;
 	char *ident;
@@ -67,6 +73,7 @@ struct connection_data {
 	int index;
 	DBusPendingCall *call;
 	connman_bool_t connect_pending;
+	struct config_create_data *cb_data;
 
 	char *state;
 	char *type;
@@ -222,26 +229,58 @@ static void resolv_host_addr(struct connection_data *data)
 						resolv_result, data);
 }
 
+static void free_config_cb_data(struct config_create_data *cb_data)
+{
+	if (cb_data == NULL)
+		return;
+
+	g_free(cb_data->path);
+	cb_data->path = NULL;
+
+	if (cb_data->message != NULL) {
+		dbus_message_unref(cb_data->message);
+		cb_data->message = NULL;
+	}
+
+	cb_data->callback = NULL;
+
+	g_free(cb_data);
+}
+
 static void set_provider_state(struct connection_data *data)
 {
-	if (g_str_equal(data->state, "ready") == TRUE)
-		connman_provider_set_state(data->provider,
-					CONNMAN_PROVIDER_STATE_READY);
-	else if (g_str_equal(data->state, "configuration") == TRUE)
-		connman_provider_set_state(data->provider,
-					CONNMAN_PROVIDER_STATE_CONNECT);
-	else if (g_str_equal(data->state, "idle") == TRUE)
-		connman_provider_set_state(data->provider,
-					CONNMAN_PROVIDER_STATE_IDLE);
-	else if (g_str_equal(data->state, "disconnect") == TRUE)
-		connman_provider_set_state(data->provider,
-					CONNMAN_PROVIDER_STATE_DISCONNECT);
-	else if (g_str_equal(data->state, "failure") == TRUE)
-		connman_provider_set_state(data->provider,
-					CONNMAN_PROVIDER_STATE_FAILURE);
-	else
-		connman_provider_set_state(data->provider,
-					CONNMAN_PROVIDER_STATE_UNKNOWN);
+	enum connman_provider_state state = CONNMAN_PROVIDER_STATE_UNKNOWN;
+	int err = 0;
+
+	if (g_str_equal(data->state, "ready") == TRUE) {
+		state = CONNMAN_PROVIDER_STATE_READY;
+		goto set;
+	} else if (g_str_equal(data->state, "configuration") == TRUE) {
+		state = CONNMAN_PROVIDER_STATE_CONNECT;
+	} else if (g_str_equal(data->state, "idle") == TRUE) {
+		state = CONNMAN_PROVIDER_STATE_IDLE;
+	} else if (g_str_equal(data->state, "disconnect") == TRUE) {
+		err = ECONNREFUSED;
+		state = CONNMAN_PROVIDER_STATE_DISCONNECT;
+		goto set;
+	} else if (g_str_equal(data->state, "failure") == TRUE) {
+		err = ECONNREFUSED;
+		state = CONNMAN_PROVIDER_STATE_FAILURE;
+		goto set;
+	}
+
+	connman_provider_set_state(data->provider, state);
+	return;
+
+set:
+	if (data->cb_data != NULL)
+		data->cb_data->callback(data->cb_data->message,
+					err, data->ident);
+
+	connman_provider_set_state(data->provider, state);
+
+	free_config_cb_data(data->cb_data);
+	data->cb_data = NULL;
 }
 
 static int create_provider(struct connection_data *data, void *user_data)
@@ -415,11 +454,13 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
 {
 	DBusMessage *reply;
 	DBusError error;
+	struct connection_data *data;
+	struct config_create_data *cb_data = user_data;
 
 	if (dbus_pending_call_get_completed(call) == FALSE)
 		return;
 
-	DBG("user_data %p", user_data);
+	DBG("user_data %p path %s", user_data, cb_data ? cb_data->path : NULL);
 
 	reply = dbus_pending_call_steal_reply(call);
 
@@ -431,6 +472,13 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
 			connman_error("Connect reply: %s (%s)", error.message,
 								error.name);
 			dbus_error_free(&error);
+
+			if (cb_data != NULL) {
+				cb_data->callback(cb_data->message,
+						ECONNREFUSED, NULL);
+				free_config_cb_data(cb_data);
+			}
+			data->cb_data = NULL;
 			goto done;
 		}
 		dbus_error_free(&error);
@@ -452,8 +500,9 @@ static int connect_provider(struct connection_data *data, void *user_data)
 {
 	DBusPendingCall *call;
 	DBusMessage *message;
+	struct config_create_data *cb_data = user_data;
 
-	DBG("data %p", data);
+	DBG("data %p user %p path %s", data, cb_data, data->path);
 
 	message = dbus_message_new_method_call(VPN_SERVICE, data->path,
 					VPN_CONNECTION_INTERFACE,
@@ -474,7 +523,12 @@ static int connect_provider(struct connection_data *data, void *user_data)
 		return -EINVAL;
 	}
 
-	dbus_pending_call_set_notify(call, connect_reply, NULL, NULL);
+	if (cb_data != NULL) {
+		g_free(cb_data->path);
+		cb_data->path = g_strdup(data->path);
+	}
+
+	dbus_pending_call_set_notify(call, connect_reply, cb_data, NULL);
 
 	dbus_message_unref(message);
 
@@ -487,6 +541,7 @@ static void add_connection(const char *path, DBusMessageIter *properties,
 	struct connection_data *data;
 	int err;
 	char *ident = get_ident(path);
+	connman_bool_t found = FALSE;
 
 	data = g_hash_table_lookup(vpn_connections, ident);
 	if (data != NULL) {
@@ -497,6 +552,8 @@ static void add_connection(const char *path, DBusMessageIter *properties,
 		 */
 		if (data->connect_pending == FALSE)
 			return;
+
+		found = TRUE;
 	} else {
 		data = create_connection_data(path);
 		if (data == NULL)
@@ -555,7 +612,9 @@ static void add_connection(const char *path, DBusMessageIter *properties,
 		dbus_message_iter_next(properties);
 	}
 
-	g_hash_table_insert(vpn_connections, g_strdup(data->ident), data);
+	if (found == FALSE)
+		g_hash_table_insert(vpn_connections, g_strdup(data->ident),
+									data);
 
 	err = create_provider(data, user_data);
 	if (err < 0)
@@ -563,10 +622,8 @@ static void add_connection(const char *path, DBusMessageIter *properties,
 
 	resolv_host_addr(data);
 
-	if (data->connect_pending == TRUE) {
-		connect_provider(data, NULL);
-		data->connect_pending = FALSE;
-	}
+	if (data->connect_pending == TRUE)
+		connect_provider(data, data->cb_data);
 
 	return;
 
@@ -765,7 +822,6 @@ static int provider_connect(struct connman_provider *provider)
 		return -EINVAL;
 
 	return connect_provider(data, NULL);
-
 }
 
 static void disconnect_reply(DBusPendingCall *call, void *user_data)
@@ -776,7 +832,7 @@ static void disconnect_reply(DBusPendingCall *call, void *user_data)
 	if (dbus_pending_call_get_completed(call) == FALSE)
 		return;
 
-	DBG("");
+	DBG("user %p", user_data);
 
 	reply = dbus_pending_call_steal_reply(call);
 
@@ -862,11 +918,12 @@ static void configuration_create_reply(DBusPendingCall *call, void *user_data)
 	const char *path;
 	char *ident;
 	struct connection_data *data;
+	struct config_create_data *cb_data = user_data;
 
 	if (dbus_pending_call_get_completed(call) == FALSE)
 		return;
 
-	DBG("user %p", user_data);
+	DBG("user %p", cb_data);
 
 	reply = dbus_pending_call_steal_reply(call);
 
@@ -898,17 +955,25 @@ static void configuration_create_reply(DBusPendingCall *call, void *user_data)
 	data = g_hash_table_lookup(vpn_connections, ident);
 	if (data == NULL) {
 		/*
-		 * We have not yet received service created message
-		 * from vpnd. So create a dummy connection struct
-		 * and wait a while.
+		 * Someone removed the data. We cannot really continue.
 		 */
-		data = create_connection_data(path);
+		DBG("Pending data not found for %s, cannot continue!", ident);
+	} else {
+		data->call = NULL;
 		data->connect_pending = TRUE;
 
-		g_hash_table_insert(vpn_connections, g_strdup(ident), data);
+		if (data->cb_data == NULL)
+			data->cb_data = cb_data;
+		else
+			DBG("Connection callback data already in use!");
 
-	} else {
-		connect_provider(data, NULL);
+		/*
+		 * Connection is created in add_connections() after
+		 * we have received the ConnectionAdded signal.
+		 */
+
+		DBG("cb %p msg %p", data->cb_data,
+			data->cb_data ? data->cb_data->message : NULL);
 	}
 
 done:
@@ -1071,9 +1136,9 @@ static void append_routes(DBusMessageIter *iter, void *user_data)
 	}
 }
 
-static int create_configuration(DBusMessage *msg)
+static int create_configuration(DBusMessage *msg, connection_ready_cb callback)
 {
-	DBusMessage *new_msg;
+	DBusMessage *new_msg = NULL;
 	DBusPendingCall *call;
 	DBusMessageIter iter, array, new_iter, new_dict;
 	const char *type = NULL, *name = NULL;
@@ -1082,6 +1147,7 @@ static int create_configuration(DBusMessage *msg)
 	int err = 0;
 	dbus_bool_t result;
 	struct connection_data *data;
+	struct config_create_data *user_data = NULL;
 	GSList *networks = NULL;
 
 	/*
@@ -1174,7 +1240,11 @@ static int create_configuration(DBusMessage *msg)
 			goto done;
 		}
 	} else {
-		data = create_connection_data(ident);
+		char *path = g_strdup_printf("%s/connection/%s", VPN_PATH,
+								ident);
+		data = create_connection_data(path);
+		g_free(path);
+
 		if (data == NULL) {
 			err = -ENOMEM;
 			goto done;
@@ -1202,17 +1272,31 @@ static int create_configuration(DBusMessage *msg)
 		goto done;
 	}
 
+	if (data->cb_data == NULL) {
+		user_data = g_try_new(struct config_create_data, 1);
+		if (user_data != NULL) {
+			user_data->callback = callback;
+			user_data->message = dbus_message_ref(msg);
+			user_data->path = NULL;
+
+			DBG("cb %p msg %p", user_data, msg);
+		}
+	} else {
+		DBG("Configuration callback data already pending, "
+			"discarding new data.");
+	}
+
 	dbus_pending_call_set_notify(call, configuration_create_reply,
-								NULL, NULL);
+							user_data, NULL);
 	data->call = call;
 
 done:
-	dbus_message_unref(new_msg);
+	if (new_msg != NULL)
+		dbus_message_unref(new_msg);
 
 	if (networks != NULL)
 		g_slist_free_full(networks, destroy_route);
 
-
 	g_free(me);
 	return err;
 }
diff --git a/src/provider.c b/src/provider.c
index cd11db9..665ef2e 100644
--- a/src/provider.c
+++ b/src/provider.c
@@ -335,6 +335,41 @@ int connman_provider_create_service(struct connman_provider *provider)
 	return 0;
 }
 
+static struct connman_provider *provider_lookup(const char *identifier)
+{
+	return g_hash_table_lookup(provider_hash, identifier);
+}
+
+static void connection_ready(DBusMessage *msg, int error_code, void *user_data)
+{
+	DBusMessage *reply;
+	const char *identifier = user_data;
+
+	DBG("msg %p error %d", msg, error_code);
+
+	if (error_code != 0) {
+		reply = __connman_error_failed(msg, -error_code);
+		if (g_dbus_send_message(connection, reply) == FALSE)
+			DBG("reply %p send failed", reply);
+	} else {
+		const char *path;
+		struct connman_provider *provider;
+
+		provider = provider_lookup(identifier);
+		if (provider == NULL) {
+			reply = __connman_error_failed(msg, -EINVAL);
+			g_dbus_send_message(connection, reply);
+			return;
+		}
+
+		path = __connman_service_get_path(provider->vpn_service);
+
+		g_dbus_send_reply(connection, msg,
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID);
+	}
+}
+
 int __connman_provider_create_and_connect(DBusMessage *msg)
 {
 	struct connman_provider_driver *driver;
@@ -346,12 +381,9 @@ int __connman_provider_create_and_connect(DBusMessage *msg)
 	if (driver == NULL || driver->create == NULL)
 		return -EINVAL;
 
-	/*
-	 * XXX: we need a callback here which is called when connection
-	 * is ready
-	 */
+	DBG("msg %p", msg);
 
-	return driver->create(msg);
+	return driver->create(msg, connection_ready);
 }
 
 const char * __connman_provider_get_ident(struct connman_provider *provider)
-- 
1.7.11.4




More information about the connman mailing list