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