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