From be4f8242a9946a059d85cfa855edcb5d45d1811b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 13 May 2009 22:01:16 -0700 Subject: [PATCH] Add support for async service connect and timeout handling --- src/element.c | 6 ++++ src/service.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/element.c b/src/element.c index ecdf4bf..1ae88bb 100644 --- a/src/element.c +++ b/src/element.c @@ -1312,6 +1312,8 @@ int connman_element_set_enabled(struct connman_element *element, void connman_element_set_error(struct connman_element *element, enum connman_element_error error) { + struct connman_service *service; + DBG("element %p error %d", element, error); if (element->type == CONNMAN_ELEMENT_TYPE_ROOT) @@ -1322,6 +1324,10 @@ void connman_element_set_error(struct connman_element *element, if (element->driver && element->driver->change) element->driver->change(element); + + service = __connman_element_get_service(element); + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE); } int __connman_element_init(DBusConnection *conn, const char *device, diff --git a/src/service.c b/src/service.c index 3a971fe..c3d4e20 100644 --- a/src/service.c +++ b/src/service.c @@ -48,6 +48,8 @@ struct connman_service { char *profile; struct connman_device *device; struct connman_network *network; + DBusMessage *pending; + guint timeout; }; static void append_path(gpointer value, gpointer user_data) @@ -282,11 +284,39 @@ static DBusMessage *set_property(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } +static gboolean connect_timeout(gpointer user_data) +{ + struct connman_service *service = user_data; + + DBG("service %p", service); + + service->timeout = 0; + + if (service->pending != NULL) { + DBusMessage *reply; + + reply = __connman_error_operation_timeout(service->pending); + if (reply != NULL) + g_dbus_send_message(connection, reply); + + dbus_message_unref(service->pending); + service->pending = NULL; + } + + return FALSE; +} + static DBusMessage *connect_service(DBusConnection *conn, DBusMessage *msg, void *data) { struct connman_service *service = data; + if (service->pending != NULL) + return __connman_error_in_progress(msg); + + if (service->state == CONNMAN_SERVICE_STATE_READY) + return __connman_error_already_connected(msg); + if (service->network != NULL) { int err; @@ -297,7 +327,12 @@ static DBusMessage *connect_service(DBusConnection *conn, if (err < 0 && err != -EINPROGRESS) return __connman_error_failed(msg, -err); - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + service->pending = dbus_message_ref(msg); + + service->timeout = g_timeout_add_seconds(45, + connect_timeout, service); + + return NULL; } else if (service->device != NULL) { if (service->favorite == FALSE) return __connman_error_no_carrier(msg); @@ -305,7 +340,11 @@ static DBusMessage *connect_service(DBusConnection *conn, if (__connman_device_connect(service->device) < 0) return __connman_error_failed(msg, EINVAL); - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + service->pending = dbus_message_ref(msg); + service->timeout = g_timeout_add_seconds(15, + connect_timeout, service); + + return NULL; } return __connman_error_not_supported(msg); @@ -316,6 +355,19 @@ static DBusMessage *disconnect_service(DBusConnection *conn, { struct connman_service *service = data; + if (service->pending != NULL) { + DBusMessage *reply; + + reply = __connman_error_operation_aborted(service->pending); + if (reply != NULL) + g_dbus_send_message(conn, reply); + + dbus_message_unref(service->pending); + service->pending = NULL; + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + } + if (service->network != NULL) { int err; @@ -387,7 +439,8 @@ static DBusMessage *move_after(DBusConnection *conn, static GDBusMethodTable service_methods[] = { { "GetProperties", "", "a{sv}", get_properties }, { "SetProperty", "sv", "", set_property }, - { "Connect", "", "", connect_service }, + { "Connect", "", "", connect_service, + G_DBUS_METHOD_FLAG_ASYNC }, { "Disconnect", "", "", disconnect_service }, { "Remove", "", "", remove_service }, { "MoveBefore", "o", "", move_before }, @@ -409,6 +462,14 @@ static void service_free(gpointer data) g_hash_table_remove(service_hash, service->identifier); + if (service->timeout > 0) + g_source_remove(service->timeout); + + if (service->pending != NULL) { + dbus_message_unref(service->pending); + service->pending = NULL; + } + service->path = NULL; if (path != NULL) { @@ -622,6 +683,34 @@ int __connman_service_indicate_state(struct connman_service *service, if (state == CONNMAN_SERVICE_STATE_READY) { connman_service_set_favorite(service, TRUE); __connman_storage_save_service(service); + + if (service->timeout > 0) + g_source_remove(service->timeout); + + if (service->pending != NULL) { + g_dbus_send_reply(connection, service->pending, + DBUS_TYPE_INVALID); + + dbus_message_unref(service->pending); + service->pending = NULL; + } + + } + + if (state == CONNMAN_SERVICE_STATE_FAILURE) { + if (service->timeout > 0) + g_source_remove(service->timeout); + + if (service->pending != NULL) { + DBusMessage *reply; + + reply = __connman_error_failed(service->pending, EIO); + if (reply != NULL) + g_dbus_send_message(connection, reply); + + dbus_message_unref(service->pending); + service->pending = NULL; + } } return 0; -- 1.7.9.5