Fix broken mode and security string comparison
[connman] / src / service.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <gdbus.h>
27
28 #include "connman.h"
29
30 static DBusConnection *connection = NULL;
31
32 static GSequence *service_list = NULL;
33 static GHashTable *service_hash = NULL;
34
35 struct connman_service {
36         gint refcount;
37         char *identifier;
38         char *path;
39         enum connman_service_type type;
40         enum connman_service_mode mode;
41         enum connman_service_security security;
42         enum connman_service_state state;
43         connman_uint8_t strength;
44         connman_bool_t favorite;
45         unsigned int order;
46         char *name;
47         struct connman_device *device;
48 };
49
50 static void append_path(gpointer value, gpointer user_data)
51 {
52         struct connman_service *service = value;
53         DBusMessageIter *iter = user_data;
54
55         if (service->path == NULL)
56                 return;
57
58         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
59                                                         &service->path);
60 }
61
62 void __connman_service_list(DBusMessageIter *iter)
63 {
64         DBG("");
65
66         g_sequence_foreach(service_list, append_path, iter);
67 }
68
69 static const char *type2string(enum connman_service_type type)
70 {
71         switch (type) {
72         case CONNMAN_SERVICE_TYPE_UNKNOWN:
73                 break;
74         case CONNMAN_SERVICE_TYPE_ETHERNET:
75                 return "ethernet";
76         case CONNMAN_SERVICE_TYPE_WIFI:
77                 return "wifi";
78         case CONNMAN_SERVICE_TYPE_WIMAX:
79                 return "wimax";
80         }
81
82         return NULL;
83 }
84
85 static const char *mode2string(enum connman_service_mode mode)
86 {
87         switch (mode) {
88         case CONNMAN_SERVICE_MODE_UNKNOWN:
89                 break;
90         case CONNMAN_SERVICE_MODE_MANAGED:
91                 return "managed";
92         case CONNMAN_SERVICE_MODE_ADHOC:
93                 return "adhoc";
94         }
95
96         return NULL;
97 }
98
99 static const char *security2string(enum connman_service_security security)
100 {
101         switch (security) {
102         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
103                 break;
104         case CONNMAN_SERVICE_SECURITY_NONE:
105                 return "none";
106         case CONNMAN_SERVICE_SECURITY_WEP:
107                 return "wep";
108         case CONNMAN_SERVICE_SECURITY_WPA:
109                 return "wpa";
110         case CONNMAN_SERVICE_SECURITY_WPA2:
111                 return "wpa2";
112         }
113
114         return NULL;
115 }
116
117 static const char *state2string(enum connman_service_state state)
118 {
119         switch (state) {
120         case CONNMAN_SERVICE_STATE_UNKNOWN:
121                 break;
122         case CONNMAN_SERVICE_STATE_IDLE:
123                 return "idle";
124         case CONNMAN_SERVICE_STATE_CARRIER:
125                 return "carrier";
126         case CONNMAN_SERVICE_STATE_ASSOCIATION:
127                 return "association";
128         case CONNMAN_SERVICE_STATE_CONFIGURATION:
129                 return "configuration";
130         case CONNMAN_SERVICE_STATE_READY:
131                 return "ready";
132         case CONNMAN_SERVICE_STATE_DISCONNECT:
133                 return "disconnect";
134         case CONNMAN_SERVICE_STATE_FAILURE:
135                 return "failure";
136         }
137
138         return NULL;
139 }
140
141 static void state_changed(struct connman_service *service)
142 {
143         DBusMessage *signal;
144         DBusMessageIter entry, value;
145         const char *str, *key = "State";
146
147         if (service->path == NULL)
148                 return;
149
150         str = state2string(service->state);
151         if (str == NULL)
152                 return;
153
154         signal = dbus_message_new_signal(service->path,
155                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
156         if (signal == NULL)
157                 return;
158
159         dbus_message_iter_init_append(signal, &entry);
160
161         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
162
163         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
164                                         DBUS_TYPE_STRING_AS_STRING, &value);
165         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
166         dbus_message_iter_close_container(&entry, &value);
167
168         g_dbus_send_message(connection, signal);
169 }
170
171 static DBusMessage *get_properties(DBusConnection *conn,
172                                         DBusMessage *msg, void *data)
173 {
174         struct connman_service *service = data;
175         DBusMessage *reply;
176         DBusMessageIter array, dict;
177         const char *str;
178
179         DBG("conn %p", conn);
180
181         reply = dbus_message_new_method_return(msg);
182         if (reply == NULL)
183                 return NULL;
184
185         dbus_message_iter_init_append(reply, &array);
186
187         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
188                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
189                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
190                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
191
192         str = type2string(service->type);
193         if (str != NULL)
194                 connman_dbus_dict_append_variant(&dict, "Type",
195                                                 DBUS_TYPE_STRING, &str);
196
197         str = mode2string(service->mode);
198         if (str != NULL)
199                 connman_dbus_dict_append_variant(&dict, "Mode",
200                                                 DBUS_TYPE_STRING, &str);
201
202         str = security2string(service->security);
203         if (str != NULL)
204                 connman_dbus_dict_append_variant(&dict, "Security",
205                                                 DBUS_TYPE_STRING, &str);
206
207         str = state2string(service->state);
208         if (str != NULL)
209                 connman_dbus_dict_append_variant(&dict, "State",
210                                                 DBUS_TYPE_STRING, &str);
211
212         if (service->strength > 0)
213                 connman_dbus_dict_append_variant(&dict, "Strength",
214                                         DBUS_TYPE_BYTE, &service->strength);
215
216         connman_dbus_dict_append_variant(&dict, "Favorite",
217                                         DBUS_TYPE_BOOLEAN, &service->favorite);
218
219         if (service->name != NULL)
220                 connman_dbus_dict_append_variant(&dict, "Name",
221                                         DBUS_TYPE_STRING, &service->name);
222
223         dbus_message_iter_close_container(&array, &dict);
224
225         return reply;
226 }
227
228 static DBusMessage *connect_service(DBusConnection *conn,
229                                         DBusMessage *msg, void *data)
230 {
231         struct connman_service *service = data;
232
233         if (service->device != NULL) {
234                 if (__connman_device_connect(service->device) < 0)
235                         return __connman_error_failed(msg);
236
237                 service->state = CONNMAN_SERVICE_STATE_READY;
238
239                 state_changed(service);
240         }
241
242         return __connman_error_not_supported(msg);
243 }
244
245 static DBusMessage *disconnect_service(DBusConnection *conn,
246                                         DBusMessage *msg, void *data)
247 {
248         struct connman_service *service = data;
249
250         if (service->device != NULL) {
251                 if (__connman_device_connect(service->device) < 0)
252                         return __connman_error_failed(msg);
253
254                 service->state = CONNMAN_SERVICE_STATE_IDLE;
255
256                 state_changed(service);
257         }
258
259         return __connman_error_not_supported(msg);
260 }
261
262 static DBusMessage *remove_service(DBusConnection *conn,
263                                         DBusMessage *msg, void *data)
264 {
265         struct connman_service *service = data;
266
267         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
268                 return __connman_error_not_supported(msg);
269
270         connman_service_set_favorite(service, FALSE);
271
272         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
273 }
274
275 static DBusMessage *move_before(DBusConnection *conn,
276                                         DBusMessage *msg, void *data)
277 {
278         struct connman_service *service = data;
279
280         if (service->favorite == FALSE)
281                 return __connman_error_not_supported(msg);
282
283         return __connman_error_not_implemented(msg);
284 }
285
286 static DBusMessage *move_after(DBusConnection *conn,
287                                         DBusMessage *msg, void *data)
288 {
289         struct connman_service *service = data;
290
291         if (service->favorite == FALSE)
292                 return __connman_error_not_supported(msg);
293
294         return __connman_error_not_implemented(msg);
295 }
296
297 static GDBusMethodTable service_methods[] = {
298         { "GetProperties", "",  "a{sv}", get_properties     },
299         { "Connect",       "",  "",      connect_service    },
300         { "Disconnect",    "",  "",      disconnect_service },
301         { "Remove",        "",  "",      remove_service     },
302         { "MoveBefore",    "o", "",      move_before        },
303         { "MoveAfter",     "o", "",      move_after         },
304         { },
305 };
306
307 static GDBusSignalTable service_signals[] = {
308         { "PropertyChanged", "sv" },
309         { },
310 };
311
312 static void service_free(gpointer data)
313 {
314         struct connman_service *service = data;
315         char *path = service->path;
316
317         DBG("service %p", service);
318
319         g_hash_table_remove(service_hash, service->identifier);
320
321         service->path = NULL;
322
323         if (path != NULL) {
324                 __connman_profile_changed();
325
326                 g_dbus_unregister_interface(connection, path,
327                                                 CONNMAN_SERVICE_INTERFACE);
328                 g_free(path);
329         }
330
331         g_free(service->name);
332         g_free(service->identifier);
333         g_free(service);
334 }
335
336 /**
337  * connman_service_put:
338  * @service: service structure
339  *
340  * Release service if no longer needed
341  */
342 void connman_service_put(struct connman_service *service)
343 {
344         DBG("service %p", service);
345
346         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
347                 GSequenceIter *iter;
348
349                 iter = g_hash_table_lookup(service_hash, service->identifier);
350                 if (iter != NULL)
351                         g_sequence_remove(iter);
352                 else
353                         service_free(service);
354         }
355 }
356
357 static void __connman_service_initialize(struct connman_service *service)
358 {
359         DBG("service %p", service);
360
361         service->refcount = 1;
362
363         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
364         service->mode     = CONNMAN_SERVICE_MODE_UNKNOWN;
365         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
366         service->state    = CONNMAN_SERVICE_STATE_UNKNOWN;
367
368         service->favorite = FALSE;
369
370         service->order = 0;
371 }
372
373 /**
374  * connman_service_create:
375  *
376  * Allocate a new service.
377  *
378  * Returns: a newly-allocated #connman_service structure
379  */
380 struct connman_service *connman_service_create(void)
381 {
382         struct connman_service *service;
383
384         service = g_try_new0(struct connman_service, 1);
385         if (service == NULL)
386                 return NULL;
387
388         DBG("service %p", service);
389
390         __connman_service_initialize(service);
391
392         return service;
393 }
394
395 /**
396  * connman_service_ref:
397  * @service: service structure
398  *
399  * Increase reference counter of service
400  */
401 struct connman_service *connman_service_ref(struct connman_service *service)
402 {
403         g_atomic_int_inc(&service->refcount);
404
405         return service;
406 }
407
408 /**
409  * connman_service_unref:
410  * @service: service structure
411  *
412  * Decrease reference counter of service
413  */
414 void connman_service_unref(struct connman_service *service)
415 {
416         connman_service_put(service);
417 }
418
419 static gint service_compare(gconstpointer a, gconstpointer b,
420                                                         gpointer user_data)
421 {
422         struct connman_service *service_a = (void *) a;
423         struct connman_service *service_b = (void *) b;
424
425         if (service_a->order > service_b->order)
426                 return -1;
427
428         if (service_a->order < service_b->order)
429                 return 1;
430
431         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
432                 return -1;
433
434         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
435                 return 1;
436
437         return (gint) service_b->strength - (gint) service_a->strength;
438 }
439
440 /**
441  * connman_service_set_favorite:
442  * @service: service structure
443  * @favorite: favorite value
444  *
445  * Change the favorite setting of service
446  */
447 int connman_service_set_favorite(struct connman_service *service,
448                                                 connman_bool_t favorite)
449 {
450         GSequenceIter *iter;
451
452         iter = g_hash_table_lookup(service_hash, service->identifier);
453         if (iter == NULL)
454                 return -ENOENT;
455
456         if (service->favorite)
457                 return -EALREADY;
458
459         service->favorite = favorite;
460
461         g_sequence_sort_changed(iter, service_compare, NULL);
462
463         __connman_profile_changed();
464
465         return 0;
466 }
467
468 int __connman_service_set_carrier(struct connman_service *service,
469                                                 connman_bool_t carrier)
470 {
471         DBG("service %p carrier %d", service, carrier);
472
473         if (service == NULL)
474                 return -EINVAL;
475
476         switch (service->type) {
477         case CONNMAN_SERVICE_TYPE_UNKNOWN:
478         case CONNMAN_SERVICE_TYPE_WIFI:
479         case CONNMAN_SERVICE_TYPE_WIMAX:
480                 return -EINVAL;
481         case CONNMAN_SERVICE_TYPE_ETHERNET:
482                 break;
483         }
484
485         if (carrier == TRUE)
486                 service->state = CONNMAN_SERVICE_STATE_CARRIER;
487         else
488                 service->state = CONNMAN_SERVICE_STATE_IDLE;
489
490         state_changed(service);
491
492         return connman_service_set_favorite(service, carrier);
493 }
494
495 int __connman_service_indicate_configuration(struct connman_service *service)
496 {
497         DBG("service %p", service);
498
499         if (service == NULL)
500                 return -EINVAL;
501
502         service->state = CONNMAN_SERVICE_STATE_CONFIGURATION;
503
504         state_changed(service);
505
506         return 0;
507 }
508
509 int __connman_service_ready(struct connman_service *service)
510 {
511         DBG("service %p", service);
512
513         if (service == NULL)
514                 return -EINVAL;
515
516         service->state = CONNMAN_SERVICE_STATE_READY;
517
518         state_changed(service);
519
520         return 0;
521 }
522
523 int __connman_service_disconnect(struct connman_service *service)
524 {
525         DBG("service %p", service);
526
527         if (service == NULL)
528                 return -EINVAL;
529
530         service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
531
532         state_changed(service);
533
534         return 0;
535 }
536
537 /**
538  * connman_service_lookup:
539  * @identifier: service identifier
540  *
541  * Look up a service by identifier (reference count will not be increased)
542  */
543 struct connman_service *connman_service_lookup(const char *identifier)
544 {
545         GSequenceIter *iter;
546
547         iter = g_hash_table_lookup(service_hash, identifier);
548         if (iter != NULL)
549                 return g_sequence_get(iter);
550
551         return NULL;
552 }
553
554 /**
555  * connman_service_get:
556  * @identifier: service identifier
557  *
558  * Look up a service by identifier or create a new one if not found
559  */
560 struct connman_service *connman_service_get(const char *identifier)
561 {
562         struct connman_service *service;
563         GSequenceIter *iter;
564
565         iter = g_hash_table_lookup(service_hash, identifier);
566         if (iter != NULL) {
567                 service = g_sequence_get(iter);
568                 if (service != NULL)
569                         g_atomic_int_inc(&service->refcount);
570                 return service;
571         }
572
573         service = g_try_new0(struct connman_service, 1);
574         if (service == NULL)
575                 return NULL;
576
577         DBG("service %p", service);
578
579         __connman_service_initialize(service);
580
581         service->identifier = g_strdup(identifier);
582
583         iter = g_sequence_insert_sorted(service_list, service,
584                                                 service_compare, NULL);
585
586         g_hash_table_insert(service_hash, service->identifier, iter);
587
588         return service;
589 }
590
591 static int service_register(struct connman_service *service)
592 {
593         const char *path = __connman_profile_active();
594
595         DBG("service %p", service);
596
597         if (service->path != NULL)
598                 return -EALREADY;
599
600         service->path = g_strdup_printf("%s/%s", path, service->identifier);
601
602         DBG("path %s", service->path);
603
604         g_dbus_register_interface(connection, service->path,
605                                         CONNMAN_SERVICE_INTERFACE,
606                                         service_methods, service_signals,
607                                                         NULL, service, NULL);
608
609         __connman_profile_changed();
610
611         return 0;
612 }
613
614 /**
615  * connman_service_lookup_from_device:
616  * @device: device structure
617  *
618  * Look up a service by device (reference count will not be increased)
619  */
620 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
621 {
622         struct connman_service *service;
623         char *name;
624
625         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
626                                         connman_device_get_index(device));
627
628         service = connman_service_lookup(name);
629
630         g_free(name);
631
632         return service;
633 }
634
635 static enum connman_service_type convert_device_type(struct connman_device *device)
636 {
637         enum connman_device_type type = connman_device_get_type(device);
638
639         switch (type) {
640         case CONNMAN_DEVICE_TYPE_UNKNOWN:
641         case CONNMAN_DEVICE_TYPE_VENDOR:
642         case CONNMAN_DEVICE_TYPE_WIFI:
643         case CONNMAN_DEVICE_TYPE_WIMAX:
644         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
645         case CONNMAN_DEVICE_TYPE_GPS:
646         case CONNMAN_DEVICE_TYPE_HSO:
647         case CONNMAN_DEVICE_TYPE_NOZOMI:
648         case CONNMAN_DEVICE_TYPE_HUAWEI:
649         case CONNMAN_DEVICE_TYPE_NOVATEL:
650                 break;
651         case CONNMAN_DEVICE_TYPE_ETHERNET:
652                 return CONNMAN_SERVICE_TYPE_ETHERNET;
653         }
654
655         return CONNMAN_SERVICE_TYPE_UNKNOWN;
656 }
657
658 /**
659  * connman_service_create_from_device:
660  * @device: device structure
661  *
662  * Look up service by device and if not found, create one
663  */
664 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
665 {
666         struct connman_service *service;
667         char *name;
668
669         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
670                                         connman_device_get_index(device));
671
672         service = connman_service_get(name);
673         if (service == NULL)
674                 goto done;
675
676         if (service->path != NULL) {
677                 connman_service_put(service);
678                 service = NULL;
679                 goto done;
680         }
681
682         service->type = convert_device_type(device);
683
684         service->device = device;
685
686         service_register(service);
687
688 done:
689         g_free(name);
690
691         return service;
692 }
693
694 /**
695  * connman_service_lookup_from_network:
696  * @device: device structure
697  *
698  * Look up a service by network (reference count will not be increased)
699  */
700 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
701 {
702         struct connman_service *service;
703         const char *group;
704         char *name;
705
706         group = __connman_network_get_group(network);
707         if (group == NULL)
708                 return NULL;
709
710         name = g_strdup_printf("%s_%s",
711                                 __connman_network_get_type(network), group);
712
713         service = connman_service_lookup(name);
714
715         g_free(name);
716
717         return service;
718 }
719
720 static enum connman_service_type convert_network_type(struct connman_network *network)
721 {
722         enum connman_network_type type = connman_network_get_type(network);
723
724         switch (type) {
725         case CONNMAN_NETWORK_TYPE_UNKNOWN:
726         case CONNMAN_NETWORK_TYPE_VENDOR:
727         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
728         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
729         case CONNMAN_NETWORK_TYPE_HSO:
730                 break;
731         case CONNMAN_NETWORK_TYPE_WIFI:
732                 return CONNMAN_SERVICE_TYPE_WIFI;
733         case CONNMAN_NETWORK_TYPE_WIMAX:
734                 return CONNMAN_SERVICE_TYPE_WIMAX;
735         }
736
737         return CONNMAN_SERVICE_TYPE_UNKNOWN;
738 }
739
740 static enum connman_service_mode convert_wifi_mode(const char *mode)
741 {
742         if (mode == NULL)
743                 return CONNMAN_SERVICE_MODE_UNKNOWN;
744         else if (g_str_equal(mode, "managed") == TRUE)
745                 return CONNMAN_SERVICE_MODE_MANAGED;
746         else if (g_str_equal(mode, "adhoc") == TRUE)
747                 return CONNMAN_SERVICE_MODE_ADHOC;
748         else
749                 return CONNMAN_SERVICE_MODE_UNKNOWN;
750 }
751
752 static enum connman_service_mode convert_wifi_security(const char *security)
753 {
754         if (security == NULL)
755                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
756         else if (g_str_equal(security, "none") == TRUE)
757                 return CONNMAN_SERVICE_SECURITY_NONE;
758         else if (g_str_equal(security, "wep") == TRUE)
759                 return CONNMAN_SERVICE_SECURITY_WEP;
760         else if (g_str_equal(security, "wpa") == TRUE)
761                 return CONNMAN_SERVICE_SECURITY_WPA;
762         else if (g_str_equal(security, "wpa2") == TRUE)
763                 return CONNMAN_SERVICE_SECURITY_WPA2;
764         else
765                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
766 }
767
768 /**
769  * connman_service_create_from_network:
770  * @device: device structure
771  *
772  * Look up service by network and if not found, create one
773  */
774 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
775 {
776         struct connman_service *service;
777         GSequenceIter *iter;
778         const char *group, *str;
779         char *name;
780
781         group = __connman_network_get_group(network);
782         if (group == NULL)
783                 return NULL;
784
785         name = g_strdup_printf("%s_%s",
786                                 __connman_network_get_type(network), group);
787
788         service = connman_service_get(name);
789         if (service == NULL)
790                 goto done;
791
792         if (service->path != NULL) {
793                 connman_service_put(service);
794                 service = NULL;
795                 goto done;
796         }
797
798         service->type = convert_network_type(network);
799
800         service->name = g_strdup(connman_network_get_string(network, "Name"));
801         service->strength = connman_network_get_uint8(network, "Strength");
802
803         str = connman_network_get_string(network, "WiFi.Mode");
804         service->mode = convert_wifi_mode(str);
805
806         str = connman_network_get_string(network, "WiFi.Security");
807         service->security = convert_wifi_security(str);
808
809         iter = g_hash_table_lookup(service_hash, service->identifier);
810         if (iter != NULL)
811                 g_sequence_sort_changed(iter, service_compare, NULL);
812
813         service_register(service);
814
815 done:
816         g_free(name);
817
818         return service;
819 }
820
821 int __connman_service_init(void)
822 {
823         DBG("");
824
825         connection = connman_dbus_get_connection();
826
827         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
828                                                                 NULL, NULL);
829
830         service_list = g_sequence_new(service_free);
831
832         return 0;
833 }
834
835 void __connman_service_cleanup(void)
836 {
837         DBG("");
838
839         g_sequence_free(service_list);
840         service_list = NULL;
841
842         g_hash_table_destroy(service_hash);
843         service_hash = NULL;
844
845         dbus_connection_unref(connection);
846 }