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 | 172 +++++++++++++++++++++++++++++++++++++++--------------
src/provider.c | 42 +++++++++++--
3 files changed, 169 insertions(+), 49 deletions(-)
diff --git a/include/provider.h b/include/provider.h
index 548bd61..254af94 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,
+ const char *path);
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 22ed946..2102ee4 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)
@@ -410,11 +449,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);
@@ -426,6 +467,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);
@@ -447,8 +495,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,
@@ -469,7 +518,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);
@@ -482,6 +536,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) {
@@ -492,6 +547,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)
@@ -550,7 +607,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)
@@ -558,10 +617,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;
@@ -760,7 +817,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)
@@ -771,7 +827,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);
@@ -857,11 +913,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);
@@ -893,17 +950,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:
@@ -927,17 +992,19 @@ static void set_dbus_ident(char *ident)
}
}
-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;
const char *type = NULL, *name = NULL;
const char *host = NULL, *domain = NULL;
- char *ident, *me;
- int err;
+ char *ident, *me = NULL;
+ int err = 0;
dbus_bool_t result;
struct connection_data *data;
+ struct config_create_data *user_data = NULL;
dbus_message_iter_init(msg, &iter);
dbus_message_iter_recurse(&iter, &array);
@@ -988,7 +1055,11 @@ static int create_configuration(DBusMessage *msg)
return -EINPROGRESS;
}
} 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)
return -ENOMEM;
@@ -1016,12 +1087,27 @@ 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);
g_free(me);
return err;
diff --git a/src/provider.c b/src/provider.c
index cd11db9..ab8ced4 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,
+ const char *identifier)
+{
+ DBusMessage *reply;
+
+ 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
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman