summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)