manager: Remove support for GetState method and StateChanged signal
[platform/upstream/connman.git] / src / notifier.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 GSList *notifier_list = NULL;
33 static GHashTable *service_hash = NULL;
34
35 static gint compare_priority(gconstpointer a, gconstpointer b)
36 {
37         const struct connman_notifier *notifier1 = a;
38         const struct connman_notifier *notifier2 = b;
39
40         return notifier2->priority - notifier1->priority;
41 }
42
43 /**
44  * connman_notifier_register:
45  * @notifier: notifier module
46  *
47  * Register a new notifier module
48  *
49  * Returns: %0 on success
50  */
51 int connman_notifier_register(struct connman_notifier *notifier)
52 {
53         DBG("notifier %p name %s", notifier, notifier->name);
54
55         notifier_list = g_slist_insert_sorted(notifier_list, notifier,
56                                                         compare_priority);
57
58         return 0;
59 }
60
61 /**
62  * connman_notifier_unregister:
63  * @notifier: notifier module
64  *
65  * Remove a previously registered notifier module
66  */
67 void connman_notifier_unregister(struct connman_notifier *notifier)
68 {
69         DBG("notifier %p name %s", notifier, notifier->name);
70
71         notifier_list = g_slist_remove(notifier_list, notifier);
72 }
73
74 #define MAX_TECHNOLOGIES 10
75
76 static volatile int registered[MAX_TECHNOLOGIES];
77 static volatile int enabled[MAX_TECHNOLOGIES];
78 static volatile int connected[MAX_TECHNOLOGIES];
79
80 void __connman_notifier_list_registered(DBusMessageIter *iter, void *user_data)
81 {
82         int i;
83
84         __sync_synchronize();
85         for (i = 0; i < MAX_TECHNOLOGIES; i++) {
86                 const char *type = __connman_service_type2string(i);
87
88                 if (type == NULL)
89                         continue;
90
91                 if (registered[i] > 0)
92                         dbus_message_iter_append_basic(iter,
93                                                 DBUS_TYPE_STRING, &type);
94         }
95 }
96
97 void __connman_notifier_list_enabled(DBusMessageIter *iter, void *user_data)
98 {
99         int i;
100
101         __sync_synchronize();
102         for (i = 0; i < MAX_TECHNOLOGIES; i++) {
103                 const char *type = __connman_service_type2string(i);
104
105                 if (type == NULL)
106                         continue;
107
108                 if (enabled[i] > 0)
109                         dbus_message_iter_append_basic(iter,
110                                                 DBUS_TYPE_STRING, &type);
111         }
112 }
113
114 void __connman_notifier_list_connected(DBusMessageIter *iter, void *user_data)
115 {
116         int i;
117
118         __sync_synchronize();
119         for (i = 0; i < MAX_TECHNOLOGIES; i++) {
120                 const char *type = __connman_service_type2string(i);
121
122                 if (type == NULL)
123                         continue;
124
125                 if (connected[i] > 0)
126                         dbus_message_iter_append_basic(iter,
127                                                 DBUS_TYPE_STRING, &type);
128         }
129 }
130
131 static void technology_registered(enum connman_service_type type,
132                                                 connman_bool_t registered)
133 {
134         DBG("type %d registered %d", type, registered);
135
136         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
137                 CONNMAN_MANAGER_INTERFACE, "AvailableTechnologies",
138                 DBUS_TYPE_STRING, __connman_notifier_list_registered, NULL);
139 }
140
141 static void technology_enabled(enum connman_service_type type,
142                                                 connman_bool_t enabled)
143 {
144         GSList *list;
145
146         DBG("type %d enabled %d", type, enabled);
147
148         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
149                 CONNMAN_MANAGER_INTERFACE, "EnabledTechnologies",
150                 DBUS_TYPE_STRING, __connman_notifier_list_enabled, NULL);
151
152         for (list = notifier_list; list; list = list->next) {
153                 struct connman_notifier *notifier = list->data;
154
155                 if (notifier->service_enabled)
156                         notifier->service_enabled(type, enabled);
157         }
158 }
159
160 unsigned int __connman_notifier_count_connected(void)
161 {
162         unsigned int i, count = 0;
163
164         __sync_synchronize();
165         for (i = 0; i < MAX_TECHNOLOGIES; i++) {
166                 if (connected[i] > 0)
167                         count++;
168         }
169
170         return count;
171 }
172
173 const char *__connman_notifier_get_state(void)
174 {
175         unsigned int count = __connman_notifier_count_connected();
176
177         if (count > 0)
178                 return "online";
179
180         return "offline";
181 }
182
183 static void state_changed(connman_bool_t connected)
184 {
185         unsigned int count = __connman_notifier_count_connected();
186         char *state = "offline";
187
188         if (count > 1)
189                 return;
190
191         if (count == 1) {
192                 if (connected == FALSE)
193                         return;
194
195                 state = "online";
196         }
197
198         connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
199                                 CONNMAN_MANAGER_INTERFACE, "State",
200                                                 DBUS_TYPE_STRING, &state);
201 }
202
203 static void technology_connected(enum connman_service_type type,
204                                                 connman_bool_t connected)
205 {
206         DBG("type %d connected %d", type, connected);
207
208         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
209                 CONNMAN_MANAGER_INTERFACE, "ConnectedTechnologies",
210                 DBUS_TYPE_STRING, __connman_notifier_list_connected, NULL);
211
212         state_changed(connected);
213 }
214
215 void __connman_notifier_register(enum connman_service_type type)
216 {
217         DBG("type %d", type);
218
219         switch (type) {
220         case CONNMAN_SERVICE_TYPE_UNKNOWN:
221         case CONNMAN_SERVICE_TYPE_SYSTEM:
222         case CONNMAN_SERVICE_TYPE_GPS:
223         case CONNMAN_SERVICE_TYPE_VPN:
224         case CONNMAN_SERVICE_TYPE_GADGET:
225                 return;
226         case CONNMAN_SERVICE_TYPE_ETHERNET:
227         case CONNMAN_SERVICE_TYPE_WIFI:
228         case CONNMAN_SERVICE_TYPE_WIMAX:
229         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
230         case CONNMAN_SERVICE_TYPE_CELLULAR:
231                 break;
232         }
233
234         if (__sync_fetch_and_add(&registered[type], 1) == 0)
235                 technology_registered(type, TRUE);
236 }
237
238 void __connman_notifier_unregister(enum connman_service_type type)
239 {
240         DBG("type %d", type);
241
242         __sync_synchronize();
243         if (registered[type] == 0) {
244                 connman_error("notifier unregister underflow");
245                 return;
246         }
247
248         switch (type) {
249         case CONNMAN_SERVICE_TYPE_UNKNOWN:
250         case CONNMAN_SERVICE_TYPE_SYSTEM:
251         case CONNMAN_SERVICE_TYPE_GPS:
252         case CONNMAN_SERVICE_TYPE_VPN:
253         case CONNMAN_SERVICE_TYPE_GADGET:
254                 return;
255         case CONNMAN_SERVICE_TYPE_ETHERNET:
256         case CONNMAN_SERVICE_TYPE_WIFI:
257         case CONNMAN_SERVICE_TYPE_WIMAX:
258         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
259         case CONNMAN_SERVICE_TYPE_CELLULAR:
260                 break;
261         }
262
263         if (__sync_fetch_and_sub(&registered[type], 1) != 1)
264                 return;
265
266         technology_registered(type, FALSE);
267 }
268
269 void __connman_notifier_enable(enum connman_service_type type)
270 {
271         DBG("type %d", type);
272
273         switch (type) {
274         case CONNMAN_SERVICE_TYPE_UNKNOWN:
275         case CONNMAN_SERVICE_TYPE_SYSTEM:
276         case CONNMAN_SERVICE_TYPE_GPS:
277         case CONNMAN_SERVICE_TYPE_VPN:
278         case CONNMAN_SERVICE_TYPE_GADGET:
279                 return;
280         case CONNMAN_SERVICE_TYPE_ETHERNET:
281         case CONNMAN_SERVICE_TYPE_WIFI:
282         case CONNMAN_SERVICE_TYPE_WIMAX:
283         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
284         case CONNMAN_SERVICE_TYPE_CELLULAR:
285                 break;
286         }
287
288         if (__sync_fetch_and_add(&enabled[type], 1) == 0)
289                 technology_enabled(type, TRUE);
290 }
291
292 void __connman_notifier_disable(enum connman_service_type type)
293 {
294         DBG("type %d", type);
295
296         __sync_synchronize();
297         if (enabled[type] == 0) {
298                 connman_error("notifier disable underflow");
299                 return;
300         }
301
302         switch (type) {
303         case CONNMAN_SERVICE_TYPE_UNKNOWN:
304         case CONNMAN_SERVICE_TYPE_SYSTEM:
305         case CONNMAN_SERVICE_TYPE_GPS:
306         case CONNMAN_SERVICE_TYPE_VPN:
307         case CONNMAN_SERVICE_TYPE_GADGET:
308                 return;
309         case CONNMAN_SERVICE_TYPE_ETHERNET:
310         case CONNMAN_SERVICE_TYPE_WIFI:
311         case CONNMAN_SERVICE_TYPE_WIMAX:
312         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
313         case CONNMAN_SERVICE_TYPE_CELLULAR:
314                 break;
315         }
316
317         if (__sync_fetch_and_sub(&enabled[type], 1) != 1)
318                 return;
319
320         technology_enabled(type, FALSE);
321 }
322
323 void __connman_notifier_connect(enum connman_service_type type)
324 {
325         DBG("type %d", type);
326
327         switch (type) {
328         case CONNMAN_SERVICE_TYPE_UNKNOWN:
329         case CONNMAN_SERVICE_TYPE_SYSTEM:
330         case CONNMAN_SERVICE_TYPE_GPS:
331         case CONNMAN_SERVICE_TYPE_VPN:
332         case CONNMAN_SERVICE_TYPE_GADGET:
333                 return;
334         case CONNMAN_SERVICE_TYPE_ETHERNET:
335         case CONNMAN_SERVICE_TYPE_WIFI:
336         case CONNMAN_SERVICE_TYPE_WIMAX:
337         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
338         case CONNMAN_SERVICE_TYPE_CELLULAR:
339                 break;
340         }
341
342         if (__sync_fetch_and_add(&connected[type], 1) == 0)
343                 technology_connected(type, TRUE);
344 }
345
346 void __connman_notifier_disconnect(enum connman_service_type type)
347 {
348         DBG("type %d", type);
349
350         __sync_synchronize();
351         if (connected[type] == 0) {
352                 connman_error("notifier disconnect underflow");
353                 return;
354         }
355
356         switch (type) {
357         case CONNMAN_SERVICE_TYPE_UNKNOWN:
358         case CONNMAN_SERVICE_TYPE_SYSTEM:
359         case CONNMAN_SERVICE_TYPE_GPS:
360         case CONNMAN_SERVICE_TYPE_VPN:
361         case CONNMAN_SERVICE_TYPE_GADGET:
362                 return;
363         case CONNMAN_SERVICE_TYPE_ETHERNET:
364         case CONNMAN_SERVICE_TYPE_WIFI:
365         case CONNMAN_SERVICE_TYPE_WIMAX:
366         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
367         case CONNMAN_SERVICE_TYPE_CELLULAR:
368                 break;
369         }
370
371         if (__sync_fetch_and_sub(&connected[type], 1) != 1)
372                 return;
373
374         technology_connected(type, FALSE);
375 }
376
377 static void technology_default(enum connman_service_type type)
378 {
379         const char *str;
380
381         str = __connman_service_type2string(type);
382         if (str == NULL)
383                 str = "";
384
385         connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
386                         CONNMAN_MANAGER_INTERFACE, "DefaultTechnology",
387                                                 DBUS_TYPE_STRING, &str);
388 }
389
390 void __connman_notifier_default_changed(struct connman_service *service)
391 {
392         enum connman_service_type type = connman_service_get_type(service);
393         char *interface;
394         GSList *list;
395
396         technology_default(type);
397
398         interface = connman_service_get_interface(service);
399         __connman_tethering_update_interface(interface);
400         g_free(interface);
401
402         for (list = notifier_list; list; list = list->next) {
403                 struct connman_notifier *notifier = list->data;
404
405                 if (notifier->default_changed)
406                         notifier->default_changed(service);
407         }
408 }
409
410 void __connman_notifier_service_add(struct connman_service *service,
411                                         const char *name)
412 {
413         GSList *list;
414
415         for (list = notifier_list; list; list = list->next) {
416                 struct connman_notifier *notifier = list->data;
417
418                 if (notifier->service_add)
419                         notifier->service_add(service, name);
420         }
421 }
422
423 void __connman_notifier_service_remove(struct connman_service *service)
424 {
425         GSList *list;
426
427         if (g_hash_table_lookup(service_hash, service) != NULL) {
428                 /*
429                  * This is a tempory check for consistency. It can be
430                  * removed when there are no reports for the following
431                  * error message.
432                  */
433                 connman_error("Service state machine inconsistency detected.");
434
435                 g_hash_table_remove(service_hash, service);
436         }
437
438         for (list = notifier_list; list; list = list->next) {
439                 struct connman_notifier *notifier = list->data;
440
441                 if (notifier->service_remove)
442                         notifier->service_remove(service);
443         }
444 }
445
446 void __connman_notifier_proxy_changed(struct connman_service *service)
447 {
448         GSList *list;
449
450         for (list = notifier_list; list; list = list->next) {
451                 struct connman_notifier *notifier = list->data;
452
453                 if (notifier->proxy_changed)
454                         notifier->proxy_changed(service);
455         }
456 }
457
458 static void offlinemode_changed(dbus_bool_t enabled)
459 {
460         DBG("enabled %d", enabled);
461
462         connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
463                                 CONNMAN_MANAGER_INTERFACE, "OfflineMode",
464                                                 DBUS_TYPE_BOOLEAN, &enabled);
465 }
466
467 void __connman_notifier_offlinemode(connman_bool_t enabled)
468 {
469         GSList *list;
470
471         DBG("enabled %d", enabled);
472
473         offlinemode_changed(enabled);
474
475         for (list = notifier_list; list; list = list->next) {
476                 struct connman_notifier *notifier = list->data;
477
478                 if (notifier->offline_mode)
479                         notifier->offline_mode(enabled);
480         }
481 }
482
483 static void notify_idle_state(connman_bool_t idle)
484 {
485         GSList *list;
486
487         DBG("idle %d", idle);
488
489         for (list = notifier_list; list; list = list->next) {
490                 struct connman_notifier *notifier = list->data;
491
492                 if (notifier->idle_state)
493                         notifier->idle_state(idle);
494         }
495 }
496
497 void __connman_notifier_service_state_changed(struct connman_service *service,
498                                         enum connman_service_state state)
499 {
500         GSList *list;
501         unsigned int old_size;
502         connman_bool_t found;
503
504         for (list = notifier_list; list; list = list->next) {
505                 struct connman_notifier *notifier = list->data;
506
507                 if (notifier->service_state_changed)
508                         notifier->service_state_changed(service, state);
509         }
510
511         old_size = g_hash_table_size(service_hash);
512         found = g_hash_table_lookup(service_hash, service) != NULL;
513
514         switch (state) {
515         case CONNMAN_SERVICE_STATE_UNKNOWN:
516         case CONNMAN_SERVICE_STATE_FAILURE:
517         case CONNMAN_SERVICE_STATE_DISCONNECT:
518         case CONNMAN_SERVICE_STATE_IDLE:
519                 if (found == FALSE)
520                         break;
521
522                 g_hash_table_remove(service_hash, service);
523                 if (old_size == 1)
524                         notify_idle_state(TRUE);
525
526                 break;
527         case CONNMAN_SERVICE_STATE_ASSOCIATION:
528         case CONNMAN_SERVICE_STATE_CONFIGURATION:
529         case CONNMAN_SERVICE_STATE_READY:
530         case CONNMAN_SERVICE_STATE_ONLINE:
531                 if (found == TRUE)
532                         break;
533
534                 g_hash_table_insert(service_hash, service, service);
535                 if (old_size == 0)
536                         notify_idle_state(FALSE);
537
538                 break;
539         }
540 }
541
542 void __connman_notifier_ipconfig_changed(struct connman_service *service,
543                                         struct connman_ipconfig *ipconfig)
544 {
545         GSList *list;
546
547         for (list = notifier_list; list; list = list->next) {
548                 struct connman_notifier *notifier = list->data;
549
550                 if (notifier->ipconfig_changed)
551                         notifier->ipconfig_changed(service, ipconfig);
552         }
553 }
554
555 static connman_bool_t technology_supported(enum connman_service_type type)
556 {
557         switch (type) {
558         case CONNMAN_SERVICE_TYPE_UNKNOWN:
559         case CONNMAN_SERVICE_TYPE_SYSTEM:
560         case CONNMAN_SERVICE_TYPE_GPS:
561         case CONNMAN_SERVICE_TYPE_VPN:
562         case CONNMAN_SERVICE_TYPE_GADGET:
563                 return FALSE;
564         case CONNMAN_SERVICE_TYPE_ETHERNET:
565         case CONNMAN_SERVICE_TYPE_WIFI:
566         case CONNMAN_SERVICE_TYPE_WIMAX:
567         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
568         case CONNMAN_SERVICE_TYPE_CELLULAR:
569                 break;
570         }
571
572         return TRUE;
573 }
574
575 connman_bool_t __connman_notifier_is_registered(enum connman_service_type type)
576 {
577         DBG("type %d", type);
578
579         if (technology_supported(type) == FALSE)
580                 return FALSE;
581
582         __sync_synchronize();
583         if (registered[type] > 0)
584                 return TRUE;
585
586         return FALSE;
587 }
588
589 connman_bool_t __connman_notifier_is_enabled(enum connman_service_type type)
590 {
591         DBG("type %d", type);
592
593         if (technology_supported(type) == FALSE)
594                 return FALSE;
595
596         __sync_synchronize();
597         if (enabled[type] > 0)
598                 return TRUE;
599
600         return FALSE;
601 }
602
603 int __connman_notifier_init(void)
604 {
605         DBG("");
606
607         connection = connman_dbus_get_connection();
608
609         service_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
610                                                 NULL, NULL);
611
612
613         return 0;
614 }
615
616 void __connman_notifier_cleanup(void)
617 {
618         DBG("");
619
620         g_hash_table_destroy(service_hash);
621         service_hash = NULL;
622
623         dbus_connection_unref(connection);
624 }