technology: Implement Technology Scan and scan start/stop functionality
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Wed, 1 Feb 2012 14:43:56 +0000 (16:43 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Sat, 4 Feb 2012 00:15:35 +0000 (01:15 +0100)
When Technology Scan D-Bus method call is called, add caller to a scan
list and start a scan for the service type. When a device reports scan
completed, check whether it was the last device scanning and reply to
the callers accordingly.

Also check for scanning status when removing devices and technology
objects.

src/connman.h
src/technology.c

index db58316..d6ce040 100644 (file)
@@ -393,6 +393,8 @@ int __connman_technology_update_rfkill(unsigned int index,
 int __connman_technology_remove_rfkill(unsigned int index,
                                        enum connman_service_type type);
 
+void __connman_technology_scan_started(struct connman_device *device);
+void __connman_technology_scan_stopped(struct connman_device *device);
 void __connman_technology_add_interface(enum connman_service_type type,
                                int index, const char *name, const char *ident);
 void __connman_technology_remove_interface(enum connman_service_type type,
index c208b95..12ed5af 100644 (file)
@@ -70,6 +70,8 @@ struct connman_technology {
 
        DBusMessage *pending_reply;
        guint pending_timeout;
+
+       GSList *scan_pending;
 };
 
 static GSList *driver_list = NULL;
@@ -744,17 +746,6 @@ static DBusMessage *set_property(DBusConnection *conn,
        return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
-static GDBusMethodTable technology_methods[] = {
-       { "GetProperties", "",   "a{sv}", get_properties },
-       { "SetProperty",   "sv", "",      set_property   },
-       { },
-};
-
-static GDBusSignalTable technology_signals[] = {
-       { "PropertyChanged", "sv" },
-       { },
-};
-
 static struct connman_technology *technology_find(enum connman_service_type type)
 {
        GSList *list;
@@ -771,6 +762,99 @@ static struct connman_technology *technology_find(enum connman_service_type type
        return NULL;
 }
 
+static void reply_scan_pending(struct connman_technology *technology, int err)
+{
+       DBusMessage *reply;
+
+       DBG("technology %p err %d", technology, err);
+
+       while (technology->scan_pending != NULL) {
+               DBusMessage *msg = technology->scan_pending->data;
+
+               DBG("reply to %s", dbus_message_get_sender(msg));
+
+               if (err == 0)
+                       reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+               else
+                       reply = __connman_error_failed(msg, -err);
+               g_dbus_send_message(connection, reply);
+               dbus_message_unref(msg);
+
+               technology->scan_pending =
+                       g_slist_delete_link(technology->scan_pending,
+                                       technology->scan_pending);
+       }
+}
+
+void __connman_technology_scan_started(struct connman_device *device)
+{
+       DBG("device %p", device);
+}
+
+void __connman_technology_scan_stopped(struct connman_device *device)
+{
+       int count = 0;
+       struct connman_technology *technology;
+       enum connman_service_type type;
+       GSList *list;
+
+       type = __connman_device_get_service_type(device);
+       technology = technology_find(type);
+
+       DBG("technology %p device %p", technology, device);
+
+       if (technology == NULL)
+               return;
+
+       for (list = technology->device_list; list != NULL; list = list->next) {
+               struct connman_device *other_device = list->data;
+
+               if (device == other_device)
+                       continue;
+
+               if (__connman_device_get_service_type(other_device) != type)
+                       continue;
+
+               if (__connman_device_scanning(other_device))
+                       count += 1;
+       }
+
+       if (count == 0)
+               reply_scan_pending(technology, 0);
+}
+
+static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+       struct connman_technology *technology = data;
+       int err;
+
+       DBG ("technology %p request from %s", technology,
+                       dbus_message_get_sender(msg));
+
+       dbus_message_ref(msg);
+       technology->scan_pending =
+               g_slist_prepend(technology->scan_pending, msg);
+
+       err = __connman_device_request_scan(technology->type);
+       if (err < 0)
+               reply_scan_pending(technology, err);
+
+       return NULL;
+}
+
+static GDBusMethodTable technology_methods[] = {
+       { "GetProperties", "",   "a{sv}", get_properties },
+       { "SetProperty",   "sv", "",      set_property   },
+       { "Scan",          "",    "",     scan,
+                                               G_DBUS_METHOD_FLAG_ASYNC },
+       { },
+};
+
+static GDBusSignalTable technology_signals[] = {
+       { "PropertyChanged", "sv" },
+       { },
+};
+
 static struct connman_technology *technology_get(enum connman_service_type type)
 {
        struct connman_technology *technology;
@@ -853,6 +937,8 @@ static void technology_put(struct connman_technology *technology)
        if (__sync_fetch_and_sub(&technology->refcount, 1) > 0)
                return;
 
+       reply_scan_pending(technology, -EINTR);
+
        if (technology->driver) {
                technology->driver->remove(technology);
                technology->driver = NULL;
@@ -986,6 +1072,9 @@ int __connman_technology_remove_device(struct connman_device *device)
                return -ENXIO;
        }
 
+       if (__connman_device_scanning(device))
+               __connman_technology_scan_stopped(device);
+
        technology->device_list = g_slist_remove(technology->device_list,
                                                                device);
        technology_put(technology);