Hi Marcel:
After two days' hacking and debugging work, I worked out below auto connect
patch, please review.
The Methodology is single auto connection according to our discussion on last
mail.
The patch can achieve below functions:
The favorite service with high order can be connected automatically after
system booting and flight-mode off.
1. The single_auto_connection() is triggered when new service is created.
2. The timeout call back is used to track the connection state and try the
sequence items. So this part can be independent with other parts, and make
implementation simple.
3. The new trigger can refresh the old single_auto_connection().
I can only verify the one favorite service scenario at home. I will verify
multiple favorite services state tomorrow at office.
diff --git a/src/service.c b/src/service.c
index 6400d10..2174edb 100644
--- a/src/service.c
+++ b/src/service.c
@@ -27,6 +27,8 @@
#include "connman.h"
+#define AUTO_RETRY_PERIOD 10
+
static DBusConnection *connection = NULL;
static GSequence *service_list = NULL;
@@ -421,8 +423,27 @@ static gboolean connect_timeout(gpointer user_data)
service->timeout = 0;
- if (service->network != NULL)
- __connman_network_disconnect(service->network);
+ if (service->network != NULL) {
+ if (connman_network_get_connected(service->network)) {
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_READY);
+ service->pending = NULL;
+ } else {
+ __connman_network_disconnect(service->network);
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE);
+ }
+ } else if (service->device != NULL) {
+ if (!connman_device_get_disconnected(service->device)) {
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_READY);
+ service->pending = NULL;
+ } else {
+ __connman_device_disconnect(service->device);
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE);
+ }
+ }
if (service->pending != NULL) {
DBusMessage *reply;
@@ -433,14 +454,95 @@ static gboolean connect_timeout(gpointer user_data)
dbus_message_unref(service->pending);
service->pending = NULL;
-
- __connman_service_indicate_state(service,
- CONNMAN_SERVICE_STATE_FAILURE);
}
return FALSE;
}
+static int connect_service_err_handle(struct connman_service *service, int err)
+{
+ if (err != -EINPROGRESS) {
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE);
+ return -err;
+ } else {
+ service->timeout = g_timeout_add_seconds(45,
+ connect_timeout, service);
+ return -EINPROGRESS;
+ }
+}
+
+int __connman_service_connect(struct connman_service *service)
+{
+ DBG("service %p", service);
+
+ if (service->pending != NULL)
+ return -EINPROGRESS;
+
+ if (service->state == CONNMAN_SERVICE_STATE_READY)
+ return -EALREADY;
+
+ if (service->network != NULL) {
+ int err;
+
+ if (service->hidden == TRUE)
+ return -EINVAL;
+
+ connman_network_set_string(service->network,
+ "WiFi.Passphrase", service->passphrase);
+
+ err = __connman_network_connect(service->network);
+ if (err < 0)
+ return connect_service_err_handle(service, err);
+
+ } else if (service->device != NULL) {
+ int err;
+ if (service->favorite == FALSE)
+ /*fix me, Not sure the errno is right*/
+ return -ENODEV;
+
+ err = __connman_device_connect(service->device);
+ if (err < 0)
+ return connect_service_err_handle(service, err);
+
+ } else
+ /*fix me, Not sure the errno is right*/
+ return -EPERM;
+
+ return 0;
+}
+
+int __connman_service_disconnect(struct connman_service *service)
+{
+ DBG("service %p", service);
+
+ if (service->pending != NULL)
+ return -EAGAIN;
+
+ if (service->network != NULL) {
+ int err;
+
+ err = __connman_network_disconnect(service->network);
+ if (err < 0)
+ return err;
+
+ } else if (service->device != NULL) {
+ int err;
+
+ if (service->favorite == FALSE)
+ return 0;
+
+ err = __connman_device_disconnect(service->device);
+ if (err < 0)
+ return err;
+
+ } else
+ /*fix me, Not sure the errno is right*/
+ return -EPERM;
+
+ return 0;
+}
+
static DBusMessage *connect_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -812,7 +914,7 @@ int connman_service_set_favorite(struct connman_service
*service,
connman_bool_t favorite)
{
GSequenceIter *iter;
-
+ DBG("service %p favorite %d", service, favorite);
iter = g_hash_table_lookup(service_hash, service->identifier);
if (iter == NULL)
return -ENOENT;
@@ -1136,6 +1238,9 @@ struct connman_service
*__connman_service_create_from_device(struct connman_devi
done:
g_free(name);
+ if (service->favorite)
+ single_auto_connect();
+
return service;
}
@@ -1270,6 +1375,8 @@ static void update_from_network(struct connman_service
*service,
g_sequence_sort_changed(iter, service_compare, NULL);
}
+static void single_auto_connect(void);
+
/**
* connman_service_create_from_network:
* @network: network structure
@@ -1322,6 +1429,8 @@ struct connman_service
*__connman_service_create_from_network(struct connman_net
done:
g_free(name);
+ if (service->favorite)
+ single_auto_connect();
return service;
}
@@ -1369,7 +1478,7 @@ static int service_load(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_CELLULAR:
service->favorite = g_key_file_get_boolean(keyfile,
service->identifier, "Favorite", NULL);
-
+ DBG("service %p, favorite %d", service, service->favorite);
str = g_key_file_get_string(keyfile,
service->identifier, "Failure", NULL);
if (str != NULL) {
@@ -1526,3 +1635,104 @@ void __connman_service_cleanup(void)
dbus_connection_unref(connection);
}
+
+struct try_data {
+ struct connman_service *last_service;
+ GSequenceIter *last_iter;
+ guint timeout;
+};
+
+struct try_data auto_connect_data = {.last_iter = NULL,
+ .last_service = NULL,
+ .timeout = 0};
+
+static gboolean service_is_connecting(struct connman_service *service)
+{
+ if (service->state == CONNMAN_SERVICE_STATE_ASSOCIATION ||
+ service->state == CONNMAN_SERVICE_STATE_CONFIGURATION ||
+ service->state == CONNMAN_SERVICE_STATE_CARRIER)
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean try_service(gpointer user_data)
+{
+ struct try_data *data = user_data;
+ struct connman_service *last_service = data->last_service;
+ struct connman_service *service;
+ GSequenceIter *last_iter = data->last_iter;
+ GSequenceIter *iter;
+ DBG("Last service %p", last_service);
+
+ if (last_service != NULL) {
+ if (last_service->state == CONNMAN_SERVICE_STATE_READY) {
+ DBG("Auto connect to service: %s", last_service->name);
+ return FALSE;
+ }
+ if (service_is_connecting(last_service)) {
+ DBG("service: %s is connecting", last_service->name);
+ return TRUE;
+ }
+ }
+
+ if (last_iter == NULL)
+ iter = g_sequence_get_begin_iter(service_list);
+ else
+ iter = g_sequence_iter_next(last_iter);
+
+ if (g_sequence_iter_is_end(iter)) {
+ DBG("Finish going through service sequence");
+ return FALSE;
+ }
+ service = g_sequence_get(iter);
+ while (service == NULL ||
+ service->state == CONNMAN_SERVICE_STATE_FAILURE) {
+ iter = g_sequence_iter_next(iter);
+ if (g_sequence_iter_is_end(iter)) {
+ DBG("Finish going through service sequence");
+ return FALSE;
+ }
+ service = g_sequence_get(iter);
+ }
+
+ if (!service->favorite) {
+ DBG("Finish going through favorite sequence");
+ return FALSE;
+ }
+
+ if (service->state == CONNMAN_SERVICE_STATE_READY) {
+ DBG("service: %s is connected, ignore others", service->name);
+ return FALSE;
+ }
+
+ data->last_service = service;
+ data->last_iter = iter;
+
+ if (!service_is_connecting(service)) {
+ DBG("connect service %s", service->name);
+ __connman_service_connect(service);
+ }
+
+ return TRUE;
+}
+
+static void clear_auto_connect(void)
+{
+ DBG("");
+ auto_connect_data.last_service = NULL;
+ auto_connect_data.last_iter = NULL;
+ g_source_remove(auto_connect_data.timeout);
+ auto_connect_data.timeout = NULL;
+}
+
+static void single_auto_connect(void)
+{
+ DBG("");
+ if (auto_connect_data.timeout != NULL)
+ clear_auto_connect();
+
+ auto_connect_data.timeout =
+ g_timeout_add_seconds(AUTO_RETRY_PERIOD,
+ try_service,
+ &auto_connect_data);
+}
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman