Revise net-config power configuration
[framework/connectivity/net-config.git] / src / signal-handler.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Danny JS Seo <S.Seo@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <dbus/dbus-glib-lowlevel.h>
25
26 #include <vconf.h>
27 #include <vconf-keys.h>
28
29 #include "log.h"
30 #include "dbus.h"
31 #include "util.h"
32 #include "wifi-state.h"
33 #include "wifi-indicator.h"
34 #include "wifi-background-scan.h"
35 #include "neterror.h"
36
37 #define CONNMAN_SIGNAL_PROPERTY_CHANGED         "PropertyChanged"
38
39 #define CONNMAN_MANAGER_SIGNAL_FILTER           "type='signal',interface='net.connman.Manager'"
40 #define CONNMAN_TECHNOLOGY_SIGNAL_FILTER        "type='signal',interface='net.connman.Technology'"
41 #define CONNMAN_SERVICE_SIGNAL_FILTER           "type='signal',interface='net.connman.Service'"
42
43 static DBusConnection *signal_connection = NULL;
44
45 static int __netconfig_get_state(DBusMessage *msg, char *state)
46 {
47         char *key_name = NULL;
48         char *svc_state = NULL;
49         DBusMessageIter iter, sub_iter;
50         int Error = NETCONFIG_ERROR_INTERNAL;
51
52         /* Get state */
53         dbus_message_iter_init(msg, &iter);
54         int ArgType = dbus_message_iter_get_arg_type(&iter);
55
56         if (ArgType != DBUS_TYPE_STRING)
57                 goto done;
58
59         dbus_message_iter_get_basic(&iter, &key_name);
60         if (strcmp(key_name, "State") != 0)
61                 goto done;
62
63         dbus_message_iter_next(&iter);
64         ArgType = dbus_message_iter_get_arg_type(&iter);
65         if (ArgType != DBUS_TYPE_VARIANT)
66                 goto done;
67
68         dbus_message_iter_recurse(&iter, &sub_iter);
69         ArgType = dbus_message_iter_get_arg_type(&sub_iter);
70         if (ArgType != DBUS_TYPE_STRING)
71                 goto done;
72
73         dbus_message_iter_get_basic(&sub_iter, &svc_state);
74         snprintf(state, strlen(svc_state) + 1, "%s", svc_state);
75         Error = NETCONFIG_NO_ERROR;
76
77 done:
78         return Error;
79 }
80
81 static char *__netconfig_get_property(DBusMessage * msg, char **property)
82 {
83         DBusMessageIter args, variant;
84         char *sigvalue = NULL;
85
86         /** read these parameters */
87         if (!dbus_message_iter_init(msg, &args))
88                 ERR("Message does not have parameters");
89         else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
90                 ERR("Argument is not string");
91         else {
92                 dbus_message_iter_get_basic(&args, &sigvalue);
93                 dbus_message_iter_next(&args);
94                 dbus_message_iter_recurse(&args, &variant);
95                 if (dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_STRING)
96                         dbus_message_iter_get_basic(&variant, property);
97                 else
98                         *property = NULL;
99         }
100
101         return sigvalue;
102 }
103
104 static void __netconfig_wifi_technology_state_signal_handler(
105                 const char *sigvalue, const char *property)
106 {
107         static char previous_technology_state[DBUS_STATE_MAX_BUFLEN] = {0};
108
109         if (sigvalue == NULL || property == NULL)
110                 return;
111
112         if (g_str_equal(sigvalue, "State") != TRUE)
113                 return;
114
115         if (g_str_equal(property, "unknown") == TRUE)
116                 return;
117
118         if (g_str_equal(previous_technology_state, property) == TRUE)
119                 return;
120
121         g_strlcpy(previous_technology_state, property, sizeof(previous_technology_state));
122
123         INFO("Technology state value is %s, property %s", sigvalue, property);
124
125         if (g_str_equal(property, "offline") == TRUE) {
126                 gchar *wifi_tech_state = NULL;
127
128                 wifi_tech_state = netconfig_wifi_get_technology_state();
129                 INFO("Wi-Fi technology state: %s", wifi_tech_state);
130
131                 if (wifi_tech_state == NULL)
132                         netconfig_wifi_update_power_state(FALSE);
133                 else
134                         g_free(wifi_tech_state);
135         } else if (g_str_equal(property, "enabled") == TRUE)
136                 netconfig_wifi_update_power_state(TRUE);
137 }
138
139 static void netconfig_wifi_set_essid(const char *active_profile)
140 {
141         int err;
142         int state = -1;
143         char *essid_name = NULL;
144         DBusConnection *connection = NULL;
145         DBusMessage *message = NULL;
146         int MessageType = 0;
147
148         if (active_profile == NULL) {
149                 ERR("Can't get active_profile");
150                 return;
151         }
152
153         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
154         if (connection == NULL) {
155                 ERR("Failed to get system bus");
156                 return;
157         }
158
159         message = netconfig_invoke_dbus_method(CONNMAN_SERVICE, connection, active_profile,
160                         CONNMAN_SERVICE_INTERFACE, "GetProperties");
161
162         if (message == NULL) {
163                 ERR("Failed to get service properties");
164                 dbus_connection_unref(connection);
165                 return;
166         }
167
168         MessageType = dbus_message_get_type(message);
169
170         if (MessageType == DBUS_MESSAGE_TYPE_ERROR) {
171                 const char *ptr = dbus_message_get_error_name(message);
172                 ERR("Error!!! Error message received [%s]", ptr);
173                 goto done;
174         }
175
176         state = netconfig_extract_service_state(message, &essid_name);
177
178         if (state < 0) {
179                 ERR("state is not ready");
180                 goto done;
181         }
182
183         err = vconf_set_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, essid_name);
184         if (err != 0) {
185                 ERR("Can't set essid [%d]", err);
186         }
187
188 done:
189         g_free(essid_name);
190         essid_name = NULL;
191
192         dbus_message_unref(message);
193
194         dbus_connection_unref(connection);
195 }
196
197 static void netconfig_wifi_unset_essid(void)
198 {
199         vconf_set_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, "");
200 }
201
202 static void __netconfig_wifi_service_state_signal_handler(DBusMessage *msg, const char *profile)
203 {
204         char state[DBUS_STATE_MAX_BUFLEN] = {0};
205         static char current_profile[DBUS_PATH_MAX_BUFLEN] = {0};
206
207         if (profile == NULL)
208                 return;
209
210         if (__netconfig_get_state(msg, state) == NETCONFIG_NO_ERROR) {
211                 int value = 0;
212
213                 DBG("Signaled profile [%s] ==> state %s", profile, state);
214
215                 vconf_get_int(VCONFKEY_WIFI_STATE, &value);
216
217                 if (strcmp(state, "ready") == 0 || strcmp(state, "online") == 0) {
218                         if (value > VCONFKEY_WIFI_OFF && value != VCONFKEY_WIFI_CONNECTED) {
219
220                                 INFO("Wifi connected");
221
222                                 if ((vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_CONNECTED)) < 0)
223                                         ERR("Error!!! vconf_set_int failed");
224
225                                 netconfig_wifi_state_set_service_state(NETCONFIG_WIFI_CONNECTED);
226
227                                 netconfig_wifi_set_essid(profile);
228
229                                 netconfig_wifi_indicator_start();
230
231                                 g_strlcpy(current_profile, profile, sizeof(current_profile));
232                         }
233                 } else if (strcmp(state, "failure") == 0 || strcmp(state, "disconnect") == 0 || strcmp(state, "idle") == 0) {
234                         if (value > VCONFKEY_WIFI_UNCONNECTED) {
235
236                                 INFO("Wifi [%s] Disconnected", profile);
237                                 DBG("Current profile is %s", current_profile);
238
239                                 if ((strcmp(profile, current_profile)) == 0) {
240                                         if ((vconf_set_int (VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED)) < 0)
241                                                 ERR("Error!!! vconf_set_int failed");
242
243                                         netconfig_wifi_state_set_service_state(NETCONFIG_WIFI_IDLE);
244
245                                         netconfig_wifi_unset_essid();
246
247                                         netconfig_wifi_indicator_stop();
248
249                                         memset(current_profile, 0, sizeof(current_profile));
250                                 }
251                         }
252                 } else if (strcmp(state, "association") == 0 || strcmp(state, "configuration") == 0) {
253                         netconfig_wifi_state_set_service_state(NETCONFIG_WIFI_CONNECTING);
254                 }
255         } else
256                 DBG("Signaled profile [%s] has error to get its state", profile);
257 }
258
259 static DBusHandlerResult __netconfig_signal_filter_handler(
260                 DBusConnection *conn, DBusMessage *msg, void *user_data)
261 {
262         char *sigvalue = NULL;
263
264         if (msg == NULL) {
265                 INFO("Invalid Message. Ignore");
266
267                 /* We have handled this message, don't pass it on */
268                 return DBUS_HANDLER_RESULT_HANDLED;
269         }
270
271         if (dbus_message_is_signal(msg, CONNMAN_MANAGER_INTERFACE,
272                         CONNMAN_SIGNAL_PROPERTY_CHANGED)) {
273                 /* We have handled this message, don't pass it on */
274                 return DBUS_HANDLER_RESULT_HANDLED;
275         } else if (dbus_message_is_signal(msg, CONNMAN_TECHNOLOGY_INTERFACE,
276                         CONNMAN_SIGNAL_PROPERTY_CHANGED)) {
277                 char *property = NULL;
278                 char *tech_path = NULL;
279
280                 sigvalue = __netconfig_get_property(msg, &property);
281                 if (sigvalue == NULL)
282                         return DBUS_HANDLER_RESULT_HANDLED;
283
284                 tech_path = (char *)dbus_message_get_path(msg);
285
286                 if (strstr(tech_path, "/wifi") != NULL) {
287                         __netconfig_wifi_technology_state_signal_handler((const char *)sigvalue, (const char *)property);
288                         return DBUS_HANDLER_RESULT_HANDLED;
289                 }
290
291                 /* We have handled this message, don't pass it on */
292                 return DBUS_HANDLER_RESULT_HANDLED;
293         } else if (dbus_message_is_signal(msg, CONNMAN_SERVICE_INTERFACE, CONNMAN_SIGNAL_PROPERTY_CHANGED)) {
294                 sigvalue = netconfig_dbus_get_string(msg);
295
296                 if (sigvalue == NULL)
297                         return DBUS_HANDLER_RESULT_HANDLED;
298
299                 if (strcmp(sigvalue, "State") == 0) {
300                         char *profile = NULL;
301
302                         profile = (char *)dbus_message_get_path(msg);
303
304                         if (strstr(profile, "wifi_") != NULL) {
305                                 __netconfig_wifi_service_state_signal_handler(msg, profile);
306                                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
307                         }
308                 }
309         }
310
311         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
312 }
313
314 void netconfig_register_signal(void)
315 {
316         DBusConnection *conn = NULL;
317         DBusError err;
318
319         DBG("Register DBus signal filters");
320
321         dbus_error_init(&err);
322         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
323         if (conn == NULL) {
324                 ERR("Error! Failed to connect to the D-BUS daemon: [%s]",
325                                 err.message);
326                 dbus_error_free(&err);
327                 return;
328         }
329
330         signal_connection = conn;
331
332         dbus_connection_setup_with_g_main(conn, NULL);
333
334         /* listening to messages from all objects as no path is specified */
335         /* see signals from the given interface */
336         dbus_bus_add_match(conn, CONNMAN_MANAGER_SIGNAL_FILTER, &err);
337         dbus_connection_flush(conn);
338         if (dbus_error_is_set(&err)) {
339                 ERR("Error! Match Error (%s)", err.message);
340                 dbus_error_free(&err);
341                 return;
342         }
343
344         dbus_bus_add_match(conn, CONNMAN_TECHNOLOGY_SIGNAL_FILTER, &err);
345         dbus_connection_flush(conn);
346         if (dbus_error_is_set(&err)) {
347                 ERR("Error! Match Error (%s)", err.message);
348                 dbus_error_free(&err);
349                 return;
350         }
351
352         dbus_bus_add_match(conn, CONNMAN_SERVICE_SIGNAL_FILTER, &err);
353         dbus_connection_flush(conn);
354         if (dbus_error_is_set(&err)) {
355                 ERR("Error! Match Error (%s)", err.message);
356                 dbus_error_free(&err);
357                 return;
358         }
359
360         if (dbus_connection_add_filter(conn, __netconfig_signal_filter_handler, NULL, NULL)
361                         == FALSE) {
362                 ERR("Error! dbus_connection_add_filter() failed");
363                 return;
364         }
365
366         INFO("Successfully register signal filters");
367 }
368
369 void netconfig_deregister_signal(void)
370 {
371         if (signal_connection == NULL) {
372                 ERR("Error! Already de-registered. Nothing to be done");
373                 return;
374         }
375
376         dbus_connection_remove_filter(signal_connection, __netconfig_signal_filter_handler,
377                         NULL);
378         INFO("Successfully remove DBus signal filters");
379
380         dbus_connection_unref(signal_connection);
381         signal_connection = NULL;
382 }