Add priority property to elements
[connman] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27
28 #include <glib.h>
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection;
34
35 static GStaticRWLock driver_lock = G_STATIC_RW_LOCK_INIT;
36 static GSList *driver_list = NULL;
37 static GThreadPool *driver_thread;
38
39 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
40 static GNode *element_root = NULL;
41 static GThreadPool *element_thread;
42
43 static const char *type2string(enum connman_element_type type)
44 {
45         switch (type) {
46         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
47                 return "unknown";
48         case CONNMAN_ELEMENT_TYPE_ROOT:
49                 return "root";
50         case CONNMAN_ELEMENT_TYPE_DEVICE:
51                 return "device";
52         case CONNMAN_ELEMENT_TYPE_NETWORK:
53                 return "network";
54         case CONNMAN_ELEMENT_TYPE_IPV4:
55                 return "ipv4";
56         case CONNMAN_ELEMENT_TYPE_IPV6:
57                 return "ipv6";
58         case CONNMAN_ELEMENT_TYPE_DHCP:
59                 return "dhcp";
60         case CONNMAN_ELEMENT_TYPE_BOOTP:
61                 return "bootp";
62         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
63                 return "zeroconf";
64         case CONNMAN_ELEMENT_TYPE_CONNECTION:
65                 return "42";
66         }
67
68         return NULL;
69 }
70
71 static const char *subtype2string(enum connman_element_subtype type)
72 {
73         switch (type) {
74         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
75                 return "unknown";
76         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
77                 return "ethernet";
78         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
79                 return "wifi";
80         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
81                 return "wimax";
82         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
83                 return "modem";
84         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
85                 return "bluetooth";
86         }
87
88         return NULL;
89 }
90
91 static void append_entry(DBusMessageIter *dict,
92                                 const char *key, int type, void *val)
93 {
94         DBusMessageIter entry, value;
95         const char *signature;
96
97         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
98                                                                 NULL, &entry);
99
100         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
101
102         switch (type) {
103         case DBUS_TYPE_STRING:
104                 signature = DBUS_TYPE_STRING_AS_STRING;
105                 break;
106         case DBUS_TYPE_UINT16:
107                 signature = DBUS_TYPE_UINT16_AS_STRING;
108                 break;
109         case DBUS_TYPE_UINT32:
110                 signature = DBUS_TYPE_UINT32_AS_STRING;
111                 break;
112         case DBUS_TYPE_OBJECT_PATH:
113                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
114                 break;
115         default:
116                 signature = DBUS_TYPE_VARIANT_AS_STRING;
117                 break;
118         }
119
120         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
121                                                         signature, &value);
122         dbus_message_iter_append_basic(&value, type, val);
123         dbus_message_iter_close_container(&entry, &value);
124
125         dbus_message_iter_close_container(dict, &entry);
126 }
127
128 static void append_property(DBusMessageIter *dict,
129                                 struct connman_property *property)
130 {
131         if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
132                 append_entry(dict, property->name, property->type,
133                                                         &property->value);
134                 return;
135         }
136 }
137
138 static DBusMessage *get_properties(DBusConnection *conn,
139                                         DBusMessage *msg, void *data)
140 {
141         struct connman_element *element = data;
142         GSList *list;
143         DBusMessage *reply;
144         DBusMessageIter array, dict;
145         const char *str;
146
147         DBG("conn %p", conn);
148
149         reply = dbus_message_new_method_return(msg);
150         if (reply == NULL)
151                 return NULL;
152
153         dbus_message_iter_init_append(reply, &array);
154
155         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
156                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
157                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
158                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
159
160         if (element->parent != NULL)
161                 append_entry(&dict, "Parent",
162                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
163
164         str = type2string(element->type);
165         if (str != NULL)
166                 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
167         str = subtype2string(element->subtype);
168         if (str != NULL)
169                 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
170
171         if (element->priority > 0)
172                 append_entry(&dict, "Priority",
173                                 DBUS_TYPE_UINT16, &element->priority);
174
175         if (element->ipv4.address != NULL)
176                 append_entry(&dict, "IPv4.Address",
177                                 DBUS_TYPE_STRING, &element->ipv4.address);
178         if (element->ipv4.netmask != NULL)
179                 append_entry(&dict, "IPv4.Netmask",
180                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
181         if (element->ipv4.gateway != NULL)
182                 append_entry(&dict, "IPv4.Gateway",
183                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
184
185         for (list = element->properties; list; list = list->next) {
186                 struct connman_property *property = list->data;
187
188                 append_property(&dict, property);
189         }
190
191         dbus_message_iter_close_container(&array, &dict);
192
193         return reply;
194 }
195
196 static GDBusMethodTable element_methods[] = {
197         { "GetProperties", "", "a{sv}", get_properties },
198         { },
199 };
200
201 struct append_filter {
202         enum connman_element_type type;
203         DBusMessageIter *iter;
204 };
205
206 static gboolean append_path(GNode *node, gpointer data)
207 {
208         struct connman_element *element = node->data;
209         struct append_filter *filter = data;
210
211         DBG("element %p name %s", element, element->name);
212
213         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
214                 return FALSE;
215
216         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
217                                         filter->type != element->type)
218                 return FALSE;
219
220         dbus_message_iter_append_basic(filter->iter,
221                                 DBUS_TYPE_OBJECT_PATH, &element->path);
222
223         return FALSE;
224 }
225
226 void __connman_element_list(enum connman_element_type type,
227                                                 DBusMessageIter *iter)
228 {
229         struct append_filter filter = { type, iter };
230
231         DBG("");
232
233         g_static_rw_lock_reader_lock(&element_lock);
234         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
235                                                         append_path, &filter);
236         g_static_rw_lock_reader_unlock(&element_lock);
237 }
238
239 static gint compare_priority(gconstpointer a, gconstpointer b)
240 {
241         const struct connman_driver *driver1 = a;
242         const struct connman_driver *driver2 = b;
243
244         return driver2->priority - driver1->priority;
245 }
246
247 int connman_driver_register(struct connman_driver *driver)
248 {
249         DBG("driver %p name %s", driver, driver->name);
250
251         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
252                 return -1;
253
254         if (!driver->probe)
255                 return -EINVAL;
256
257         g_static_rw_lock_writer_lock(&driver_lock);
258         driver_list = g_slist_insert_sorted(driver_list, driver,
259                                                         compare_priority);
260         g_static_rw_lock_writer_unlock(&driver_lock);
261
262         g_thread_pool_push(driver_thread, driver, NULL);
263
264         return 0;
265 }
266
267 static gboolean remove_driver(GNode *node, gpointer data)
268 {
269         struct connman_element *element = node->data;
270         struct connman_driver *driver = data;
271
272         DBG("element %p name %s", element, element->name);
273
274         if (element->driver == driver) {
275                 if (driver->remove)
276                         driver->remove(element);
277                 element->driver = NULL;
278         }
279
280         return FALSE;
281 }
282
283 void connman_driver_unregister(struct connman_driver *driver)
284 {
285         DBG("driver %p name %s", driver, driver->name);
286
287         g_static_rw_lock_reader_lock(&element_lock);
288         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
289                                                         remove_driver, driver);
290         g_static_rw_lock_reader_unlock(&element_lock);
291
292         g_static_rw_lock_writer_lock(&driver_lock);
293         driver_list = g_slist_remove(driver_list, driver);
294         g_static_rw_lock_writer_unlock(&driver_lock);
295 }
296
297 struct connman_element *connman_element_create(void)
298 {
299         struct connman_element *element;
300
301         element = g_new0(struct connman_element, 1);
302
303         DBG("element %p", element);
304
305         element->refcount = 1;
306
307         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
308         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
309         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
310
311         element->netdev.index = -1;
312
313         return element;
314 }
315
316 struct connman_element *connman_element_ref(struct connman_element *element)
317 {
318         DBG("element %p name %s refcount %d", element, element->name,
319                                 g_atomic_int_get(&element->refcount) + 1);
320
321         g_atomic_int_inc(&element->refcount);
322
323         return element;
324 }
325
326 void connman_element_unref(struct connman_element *element)
327 {
328         DBG("element %p name %s refcount %d", element, element->name,
329                                 g_atomic_int_get(&element->refcount) - 1);
330
331         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
332                 GSList *list;
333
334                 for (list = element->properties; list; list = list->next) {
335                         struct connman_property *property = list->data;
336                         if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
337                                         property->type == DBUS_TYPE_STRING)
338                                 g_free(property->value);
339                         g_free(property);
340                         list->data = NULL;
341                 }
342                 g_slist_free(element->properties);
343
344                 g_free(element->ipv4.address);
345                 g_free(element->ipv4.netmask);
346                 g_free(element->ipv4.gateway);
347                 g_free(element->ipv4.network);
348                 g_free(element->ipv4.broadcast);
349                 g_free(element->ipv4.nameserver);
350                 g_free(element->netdev.name);
351                 g_free(element->path);
352                 g_free(element->name);
353                 g_free(element);
354         }
355 }
356
357 int connman_element_add_static_property(struct connman_element *element,
358                                 const char *name, int type, const void *value)
359 {
360         struct connman_property *property;
361
362         DBG("element %p name %s", element, element->name);
363
364         if (type != DBUS_TYPE_STRING)
365                 return -EINVAL;
366
367         property = g_try_new0(struct connman_property, 1);
368         if (property == NULL)
369                 return -ENOMEM;
370
371         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
372
373         property->name = g_strdup(name);
374         property->type = type;
375
376         DBG("name %s type %d value %p", name, type, value);
377
378         switch (type) {
379         case DBUS_TYPE_STRING:
380                 property->value = g_strdup(*((const char **) value));
381                 break;
382         }
383
384         element->properties = g_slist_append(element->properties, property);
385
386         return 0;
387 }
388
389 int connman_element_set_property(struct connman_element *element,
390                         enum connman_property_type type, const void *value)
391 {
392         switch (type) {
393         case CONNMAN_PROPERTY_TYPE_INVALID:
394                 return -EINVAL;
395         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
396                 g_free(element->ipv4.address);
397                 element->ipv4.address = g_strdup(*((const char **) value));
398                 break;
399         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
400                 g_free(element->ipv4.netmask);
401                 element->ipv4.netmask = g_strdup(*((const char **) value));
402                 break;
403         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
404                 g_free(element->ipv4.gateway);
405                 element->ipv4.gateway = g_strdup(*((const char **) value));
406                 break;
407         }
408
409         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
410                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
411                                 DBUS_TYPE_OBJECT_PATH, &element->path,
412                                                         DBUS_TYPE_INVALID);
413
414         return 0;
415 }
416
417 int connman_element_get_value(struct connman_element *element,
418                                 enum connman_property_type type, void *value)
419 {
420         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
421                 return -EINVAL;
422
423         switch (type) {
424         case CONNMAN_PROPERTY_TYPE_INVALID:
425                 return -EINVAL;
426         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
427                 if (element->ipv4.address == NULL)
428                         return connman_element_get_value(element->parent,
429                                                                 type, value);
430                 *((char **) value) = element->ipv4.address;
431                 break;
432         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
433                 if (element->ipv4.netmask == NULL)
434                         return connman_element_get_value(element->parent,
435                                                                 type, value);
436                 *((char **) value) = element->ipv4.netmask;
437                 break;
438         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
439                 if (element->ipv4.gateway == NULL)
440                         return connman_element_get_value(element->parent,
441                                                                 type, value);
442                 *((char **) value) = element->ipv4.gateway;
443                 break;
444         }
445
446         return 0;
447 }
448
449 int connman_element_register(struct connman_element *element,
450                                         struct connman_element *parent)
451 {
452         GNode *node;
453         const gchar *basepath;
454
455         DBG("element %p name %s parent %p", element, element->name, parent);
456
457         if (connman_element_ref(element) == NULL)
458                 return -1;
459
460         g_static_rw_lock_writer_lock(&element_lock);
461
462         if (parent) {
463                 node = g_node_find(element_root, G_PRE_ORDER,
464                                                 G_TRAVERSE_ALL, parent);
465                 basepath = parent->path;
466
467                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
468                         element->subtype = parent->subtype;
469         } else {
470                 node = element_root;
471                 basepath = "";
472         }
473
474         if (element->name == NULL) {
475                 switch (element->type) {
476                 case CONNMAN_ELEMENT_TYPE_IPV4:
477                         element->name = g_strdup("ipv4");
478                         break;
479                 case CONNMAN_ELEMENT_TYPE_IPV6:
480                         element->name = g_strdup("ipv6");
481                         break;
482                 case CONNMAN_ELEMENT_TYPE_DHCP:
483                         element->name = g_strdup("dhcp");
484                         break;
485                 case CONNMAN_ELEMENT_TYPE_BOOTP:
486                         element->name = g_strdup("bootp");
487                         break;
488                 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
489                         element->name = g_strdup("zeroconf");
490                         break;
491                 default:
492                         break;
493                 }
494         }
495
496         element->path = g_strdup_printf("%s/%s", basepath, element->name);
497         element->parent = parent;
498
499         DBG("element %p path %s", element, element->path);
500
501         g_node_append_data(node, element);
502
503         g_static_rw_lock_writer_unlock(&element_lock);
504
505         g_dbus_register_interface(connection, element->path,
506                                         CONNMAN_ELEMENT_INTERFACE,
507                                         element_methods, NULL, NULL,
508                                                         element, NULL);
509
510         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
511                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
512                                 DBUS_TYPE_OBJECT_PATH, &element->path,
513                                                         DBUS_TYPE_INVALID);
514
515         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
516                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
517                                 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
518                                 DBUS_TYPE_OBJECT_PATH, &element->path,
519                                                         DBUS_TYPE_INVALID);
520
521         g_thread_pool_push(element_thread, element, NULL);
522
523         return 0;
524 }
525
526 void connman_element_unregister(struct connman_element *element)
527 {
528         GNode *node;
529
530         DBG("element %p name %s", element, element->name);
531
532         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
533                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
534                                 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
535                                 DBUS_TYPE_OBJECT_PATH, &element->path,
536                                                         DBUS_TYPE_INVALID);
537
538         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
539                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
540                                 DBUS_TYPE_OBJECT_PATH, &element->path,
541                                                         DBUS_TYPE_INVALID);
542
543         g_dbus_unregister_interface(connection, element->path,
544                                                 CONNMAN_ELEMENT_INTERFACE);
545
546         g_static_rw_lock_writer_lock(&element_lock);
547
548         if (element->driver) {
549                 if (element->driver->remove)
550                         element->driver->remove(element);
551                 element->driver = NULL;
552         }
553
554         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
555         if (node != NULL) {
556                 g_node_unlink(node);
557                 g_node_destroy(node);
558         }
559
560         g_static_rw_lock_writer_unlock(&element_lock);
561
562         connman_element_unref(element);
563 }
564
565 void connman_element_update(struct connman_element *element)
566 {
567         DBG("element %p name %s", element, element->name);
568
569         g_static_rw_lock_reader_lock(&element_lock);
570
571         if (element->driver && element->driver->update)
572                 element->driver->update(element);
573
574         g_static_rw_lock_reader_unlock(&element_lock);
575
576         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
577                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
578                                 DBUS_TYPE_OBJECT_PATH, &element->path,
579                                                         DBUS_TYPE_INVALID);
580 }
581
582 static inline void set_driver(struct connman_element *element,
583                                                 struct connman_driver *driver)
584 {
585         g_static_rw_lock_reader_lock(&element_lock);
586         element->driver = driver;
587         g_static_rw_lock_reader_unlock(&element_lock);
588 }
589
590 static gboolean match_driver(struct connman_element *element,
591                                         struct connman_driver *driver)
592 {
593         if (element->type != driver->type &&
594                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
595                 return FALSE;
596
597         if (element->subtype == driver->subtype ||
598                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
599                 return TRUE;
600
601         return FALSE;
602 }
603
604 static gboolean probe_driver(GNode *node, gpointer data)
605 {
606         struct connman_element *element = node->data;
607         struct connman_driver *driver = data;
608
609         DBG("element %p name %s", element, element->name);
610
611         if (!element->driver && match_driver(element, driver) == TRUE) {
612                 element->driver = driver;
613
614                 if (driver->probe(element) < 0)
615                         element->driver = NULL;
616         }
617
618         return FALSE;
619 }
620
621 static void driver_probe(gpointer data, gpointer user_data)
622 {
623         struct connman_driver *driver = data;
624
625         DBG("driver %p name %s", driver, driver->name);
626
627         g_static_rw_lock_reader_lock(&element_lock);
628         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
629                                                         probe_driver, driver);
630         g_static_rw_lock_reader_unlock(&element_lock);
631 }
632
633 static void element_probe(gpointer data, gpointer user_data)
634 {
635         struct connman_element *element = data;
636         GSList *list;
637
638         DBG("element %p name %s", element, element->name);
639
640         if (connman_element_ref(element) == NULL)
641                 return;
642
643         g_static_rw_lock_reader_lock(&driver_lock);
644
645         for (list = driver_list; list; list = list->next) {
646                 struct connman_driver *driver = list->data;
647
648                 DBG("driver %p name %s", driver, driver->name);
649
650                 set_driver(element, driver);
651
652                 if (match_driver(element, driver) == TRUE &&
653                                                 driver->probe(element) == 0)
654                         break;
655
656                 set_driver(element, NULL);
657         }
658
659         g_static_rw_lock_reader_unlock(&driver_lock);
660
661         connman_element_unref(element);
662 }
663
664 int __connman_element_init(DBusConnection *conn)
665 {
666         struct connman_element *element;
667
668         DBG("conn %p", conn);
669
670         connection = dbus_connection_ref(conn);
671         if (connection == NULL)
672                 return -EIO;
673
674         g_static_rw_lock_writer_lock(&element_lock);
675
676         element = connman_element_create();
677
678         element->name = g_strdup("root");
679         element->path = g_strdup("/");
680         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
681
682         element_root = g_node_new(element);
683
684         g_static_rw_lock_writer_unlock(&element_lock);
685
686         element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
687
688         driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
689
690         return 0;
691 }
692
693 static gboolean free_node(GNode *node, gpointer data)
694 {
695         struct connman_element *element = node->data;
696
697         DBG("element %p name %s", element, element->name);
698
699         g_dbus_unregister_interface(connection, element->path,
700                                                 CONNMAN_ELEMENT_INTERFACE);
701
702         if (element->driver) {
703                 if (element->driver->remove)
704                         element->driver->remove(element);
705                 element->driver = NULL;
706         }
707
708         connman_element_unref(element);
709
710         node->data = NULL;
711
712         return FALSE;
713 }
714
715 void __connman_element_cleanup(void)
716 {
717         DBG("");
718
719         g_thread_pool_free(driver_thread, TRUE, TRUE);
720
721         g_thread_pool_free(element_thread, TRUE, TRUE);
722
723         g_static_rw_lock_writer_lock(&element_lock);
724
725         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
726                                                         free_node, NULL);
727
728         g_node_destroy(element_root);
729         element_root = NULL;
730
731         g_static_rw_lock_writer_unlock(&element_lock);
732
733         dbus_connection_unref(connection);
734 }