summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2012-11-12 14:07:43 +0200
committerPatrik Flykt <patrik.flykt@linux.intel.com>2012-11-23 12:58:52 +0200
commit9c1129aa6a665f7663fcbf73b20994c8592e46d5 (patch)
tree78a7d3dfb3f067841155be11bce6c6f65dbbe50a
parentae693881d0d2bac1d9edea534918b6cc238b06ce (diff)
downloadconnman-9c1129aa6a665f7663fcbf73b20994c8592e46d5.tar.gz
connman-9c1129aa6a665f7663fcbf73b20994c8592e46d5.tar.bz2
connman-9c1129aa6a665f7663fcbf73b20994c8592e46d5.zip
provider: Add callback when creating vpn provider
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.
-rw-r--r--include/provider.h4
-rw-r--r--plugins/vpn.c168
-rw-r--r--src/provider.c42
3 files changed, 166 insertions, 48 deletions
diff --git a/include/provider.h b/include/provider.h
index 548bd610..c9a3b917 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 c0cde951..b29dcc04 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 cd11db97..665ef2ed 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)