Add skeleton for new storage support using SQLite3
[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         __connman_element_load(element);
461
462         g_static_rw_lock_writer_lock(&element_lock);
463
464         if (parent) {
465                 node = g_node_find(element_root, G_PRE_ORDER,
466                                                 G_TRAVERSE_ALL, parent);
467                 basepath = parent->path;
468
469                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
470                         element->subtype = parent->subtype;
471         } else {
472                 node = element_root;
473                 basepath = "";
474         }
475
476         if (element->name == NULL) {
477                 switch (element->type) {
478                 case CONNMAN_ELEMENT_TYPE_IPV4:
479                         element->name = g_strdup("ipv4");
480                         break;
481                 case CONNMAN_ELEMENT_TYPE_IPV6:
482                         element->name = g_strdup("ipv6");
483                         break;
484                 case CONNMAN_ELEMENT_TYPE_DHCP:
485                         element->name = g_strdup("dhcp");
486                         break;
487                 case CONNMAN_ELEMENT_TYPE_BOOTP:
488                         element->name = g_strdup("bootp");
489                         break;
490                 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
491                         element->name = g_strdup("zeroconf");
492                         break;
493                 default:
494                         break;
495                 }
496         }
497
498         element->path = g_strdup_printf("%s/%s", basepath, element->name);
499         element->parent = parent;
500
501         DBG("element %p path %s", element, element->path);
502
503         g_node_append_data(node, element);
504
505         g_static_rw_lock_writer_unlock(&element_lock);
506
507         __connman_element_store(element);
508
509         g_dbus_register_interface(connection, element->path,
510                                         CONNMAN_ELEMENT_INTERFACE,
511                                         element_methods, NULL, NULL,
512                                                         element, NULL);
513
514         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
515                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
516                                 DBUS_TYPE_OBJECT_PATH, &element->path,
517                                                         DBUS_TYPE_INVALID);
518
519         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
520                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
521                                 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
522                                 DBUS_TYPE_OBJECT_PATH, &element->path,
523                                                         DBUS_TYPE_INVALID);
524
525         g_thread_pool_push(element_thread, element, NULL);
526
527         return 0;
528 }
529
530 void connman_element_unregister(struct connman_element *element)
531 {
532         GNode *node;
533
534         DBG("element %p name %s", element, element->name);
535
536         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
537                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
538                                 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
539                                 DBUS_TYPE_OBJECT_PATH, &element->path,
540                                                         DBUS_TYPE_INVALID);
541
542         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
543                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
544                                 DBUS_TYPE_OBJECT_PATH, &element->path,
545                                                         DBUS_TYPE_INVALID);
546
547         g_dbus_unregister_interface(connection, element->path,
548                                                 CONNMAN_ELEMENT_INTERFACE);
549
550         g_static_rw_lock_writer_lock(&element_lock);
551
552         if (element->driver) {
553                 if (element->driver->remove)
554                         element->driver->remove(element);
555                 element->driver = NULL;
556         }
557
558         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
559         if (node != NULL) {
560                 g_node_unlink(node);
561                 g_node_destroy(node);
562         }
563
564         g_static_rw_lock_writer_unlock(&element_lock);
565
566         connman_element_unref(element);
567 }
568
569 void connman_element_update(struct connman_element *element)
570 {
571         DBG("element %p name %s", element, element->name);
572
573         g_static_rw_lock_reader_lock(&element_lock);
574
575         if (element->driver && element->driver->update)
576                 element->driver->update(element);
577
578         g_static_rw_lock_reader_unlock(&element_lock);
579
580         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
581                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
582                                 DBUS_TYPE_OBJECT_PATH, &element->path,
583                                                         DBUS_TYPE_INVALID);
584 }
585
586 static inline void set_driver(struct connman_element *element,
587                                                 struct connman_driver *driver)
588 {
589         g_static_rw_lock_reader_lock(&element_lock);
590         element->driver = driver;
591         g_static_rw_lock_reader_unlock(&element_lock);
592 }
593
594 static gboolean match_driver(struct connman_element *element,
595                                         struct connman_driver *driver)
596 {
597         if (element->type != driver->type &&
598                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
599                 return FALSE;
600
601         if (element->subtype == driver->subtype ||
602                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
603                 return TRUE;
604
605         return FALSE;
606 }
607
608 static gboolean probe_driver(GNode *node, gpointer data)
609 {
610         struct connman_element *element = node->data;
611         struct connman_driver *driver = data;
612
613         DBG("element %p name %s", element, element->name);
614
615         if (!element->driver && match_driver(element, driver) == TRUE) {
616                 element->driver = driver;
617
618                 if (driver->probe(element) < 0)
619                         element->driver = NULL;
620         }
621
622         return FALSE;
623 }
624
625 static void driver_probe(gpointer data, gpointer user_data)
626 {
627         struct connman_driver *driver = data;
628
629         DBG("driver %p name %s", driver, driver->name);
630
631         g_static_rw_lock_reader_lock(&element_lock);
632         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
633                                                         probe_driver, driver);
634         g_static_rw_lock_reader_unlock(&element_lock);
635 }
636
637 static void element_probe(gpointer data, gpointer user_data)
638 {
639         struct connman_element *element = data;
640         GSList *list;
641
642         DBG("element %p name %s", element, element->name);
643
644         if (connman_element_ref(element) == NULL)
645                 return;
646
647         g_static_rw_lock_reader_lock(&driver_lock);
648
649         for (list = driver_list; list; list = list->next) {
650                 struct connman_driver *driver = list->data;
651
652                 DBG("driver %p name %s", driver, driver->name);
653
654                 set_driver(element, driver);
655
656                 if (match_driver(element, driver) == TRUE &&
657                                                 driver->probe(element) == 0)
658                         break;
659
660                 set_driver(element, NULL);
661         }
662
663         g_static_rw_lock_reader_unlock(&driver_lock);
664
665         connman_element_unref(element);
666 }
667
668 int __connman_element_init(DBusConnection *conn)
669 {
670         struct connman_element *element;
671
672         DBG("conn %p", conn);
673
674         connection = dbus_connection_ref(conn);
675         if (connection == NULL)
676                 return -EIO;
677
678         g_static_rw_lock_writer_lock(&element_lock);
679
680         element = connman_element_create();
681
682         element->name = g_strdup("root");
683         element->path = g_strdup("/");
684         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
685
686         element_root = g_node_new(element);
687
688         g_static_rw_lock_writer_unlock(&element_lock);
689
690         element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
691
692         driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
693
694         return 0;
695 }
696
697 static gboolean free_node(GNode *node, gpointer data)
698 {
699         struct connman_element *element = node->data;
700
701         DBG("element %p name %s", element, element->name);
702
703         g_dbus_unregister_interface(connection, element->path,
704                                                 CONNMAN_ELEMENT_INTERFACE);
705
706         if (element->driver) {
707                 if (element->driver->remove)
708                         element->driver->remove(element);
709                 element->driver = NULL;
710         }
711
712         connman_element_unref(element);
713
714         node->data = NULL;
715
716         return FALSE;
717 }
718
719 void __connman_element_cleanup(void)
720 {
721         DBG("");
722
723         g_thread_pool_free(driver_thread, TRUE, TRUE);
724
725         g_thread_pool_free(element_thread, TRUE, TRUE);
726
727         g_static_rw_lock_writer_lock(&element_lock);
728
729         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
730                                                         free_node, NULL);
731
732         g_node_destroy(element_root);
733         element_root = NULL;
734
735         g_static_rw_lock_writer_unlock(&element_lock);
736
737         dbus_connection_unref(connection);
738 }