eb3927da5b5d583c880654c887034cfd8bf1b000
[platform/core/connectivity/libnet-client.git] / src / network-internal.c
1 /*
2  * Network Client Library
3  *
4  * Copyright 2012 Samsung Electronics Co., Ltd
5  *
6  * Licensed under the Flora License, Version 1.1 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.tizenopensource.org/license
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <dlfcn.h>
21
22 #include "network-internal.h"
23 #include "network-dbus-request.h"
24
25 struct gdbus_connection_data {
26         GDBusConnection *connection;
27         int conn_ref_count;
28         GCancellable *cancellable;
29         void *handle_libnetwork;
30 };
31
32 /*****************************************************************************
33  * Extern Global Variables
34  *****************************************************************************/
35
36 /*****************************************************************************
37  * Global Variables
38  *****************************************************************************/
39
40 static pthread_mutex_t managed_idler_list_mutex = PTHREAD_MUTEX_INITIALIZER;
41 static GSList *managed_idler_list;
42
43 /*****************************************************************************
44  * Global Functions Definition
45  *****************************************************************************/
46
47 static void __net_managed_idler_list_lock(void)
48 {
49         pthread_mutex_lock(&managed_idler_list_mutex);
50 }
51
52 static void __net_managed_idler_list_unlock(void)
53 {
54         pthread_mutex_unlock(&managed_idler_list_mutex);
55 }
56
57 static void __net_remove_idler(gpointer data)
58 {
59         managed_idler_data_t *idler = (managed_idler_data_t *) data;
60
61         NETWORK_LOG(NETWORK_HIGH, "Remove idler [%d]", idler->id);
62
63         g_source_remove(idler->id);
64         _network_info_unref(idler->network_info);
65         g_free(idler);
66 }
67
68 /**
69  * NOTE: When API user is a dynamically loadable module,
70  * the API user module may get unloaded post net_deregister_client() call.
71  * To clean residual memory, this destructor is called before unloading.
72  */
73 void __attribute__ ((destructor)) _net_destructor(void)
74 {
75         __net_managed_idler_list_lock();
76
77         g_slist_free_full(managed_idler_list, __net_remove_idler);
78
79         __net_managed_idler_list_unlock();
80
81         NETWORK_LOG(NETWORK_HIGH, "net-client destructed");
82 }
83
84 gboolean _net_add_idler_to_list(managed_idler_data_t *idler_data)
85 {
86         __net_managed_idler_list_lock();
87
88         GSList *found = g_slist_find(managed_idler_list, idler_data);
89         if (found) {
90                 __net_managed_idler_list_unlock();
91                 return FALSE;
92         }
93
94         managed_idler_list = g_slist_prepend(managed_idler_list, idler_data);
95
96         __net_managed_idler_list_unlock();
97         return TRUE;
98 }
99
100 gboolean _net_remove_idler_from_list(managed_idler_data_t *idler_data)
101 {
102         __net_managed_idler_list_lock();
103
104         GSList *found = g_slist_find(managed_idler_list, idler_data);
105         if (!found) {
106                 __net_managed_idler_list_unlock();
107                 return FALSE;
108         }
109
110         /**
111          * Just remove the entry, no need to free idler_data here,
112          * it freed in __net_dbus_idler_cb
113          */
114         managed_idler_list = g_slist_delete_link(managed_idler_list, found);
115
116         __net_managed_idler_list_unlock();
117         return TRUE;
118 }
119
120 void _network_info_ref(network_info_t *network_info)
121 {
122         __atomic_add_fetch(&network_info->refcount, 1, __ATOMIC_ACQ_REL);
123
124         NETWORK_LOG(NETWORK_HIGH, "%p ref %d", network_info,
125                         __atomic_load_n(&network_info->refcount, __ATOMIC_ACQUIRE));
126 }
127
128 void _network_info_unref(network_info_t *network_info)
129 {
130         if (__atomic_load_n(&network_info->refcount, __ATOMIC_ACQUIRE) == 0) {
131                 NETWORK_LOG(NETWORK_ERROR, "This should not happen, some error scenario!!!");
132                 return;
133         }
134
135         NETWORK_LOG(NETWORK_HIGH, "%p ref %d", network_info,
136                         __atomic_load_n(&network_info->refcount, __ATOMIC_ACQUIRE) - 1);
137
138         if (__atomic_sub_fetch(&network_info->refcount, 1, __ATOMIC_ACQ_REL) > 0)
139                 return;
140
141         g_free(network_info);
142 }
143
144 char* _net_print_error(net_err_t error)
145 {
146         /* LCOV_EXCL_START */
147         switch (error) {
148                 /** No error */
149         case NET_ERR_NONE:
150                 return "NET_ERR_NONE";
151
152                 /* Common Error value */
153
154                 /** Error unknown */
155         case NET_ERR_UNKNOWN:
156                 return "NET_ERR_UNKNOWN";
157
158                 /* Client Register related Errors used in API return */
159
160                 /** Application is already registered */
161         case NET_ERR_APP_ALREADY_REGISTERED:
162                 return "NET_ERR_APP_ALREADY_REGISTERED";
163                 /** Application is not registered */
164         case NET_ERR_APP_NOT_REGISTERED:
165                 return "NET_ERR_APP_NOT_REGISTERED";
166
167                 /* Connection Related Error */
168
169                 /** No active connection exists for the given profile name */
170         case NET_ERR_NO_ACTIVE_CONNECTIONS:
171                 return "NET_ERR_NO_ACTIVE_CONNECTIONS";
172                 /** Active connection already exists for the given profile name  */
173         case NET_ERR_ACTIVE_CONNECTION_EXISTS:
174                 return "NET_ERR_ACTIVE_CONNECTION_EXISTS";
175
176                 /** Connection failure : out of range */
177         case NET_ERR_CONNECTION_OUT_OF_RANGE:
178                 return "NET_ERR_CONNECTION_OUT_OF_RANGE";
179                 /** Connection failure : pin missing */
180         case NET_ERR_CONNECTION_PIN_MISSING:
181                 return "NET_ERR_CONNECTION_PIN_MISSING";
182                 /** Connection failure : dhcp failed */
183         case NET_ERR_CONNECTION_DHCP_FAILED:
184                 return "NET_ERR_CONNECTION_DHCP_FAILED";
185                 /** Connection failure */
186         case NET_ERR_CONNECTION_CONNECT_FAILED:
187                 return "NET_ERR_CONNECTION_CONNECT_FAILED";
188                 /** Connection failure : login failed */
189         case NET_ERR_CONNECTION_LOGIN_FAILED:
190                 return "NET_ERR_CONNECTION_LOGIN_FAILED";
191                 /** Connection failure : authentication failed */
192         case NET_ERR_CONNECTION_AUTH_FAILED:
193                 return "NET_ERR_CONNECTION_AUTH_FAILED";
194                 /** Connection failure : invalid key */
195         case NET_ERR_CONNECTION_INVALID_KEY:
196                 return "NET_ERR_CONNECTION_INVALID_KEY";
197
198                 /* Other Error */
199
200                 /** Access is denied */
201         case NET_ERR_ACCESS_DENIED:
202                 return "NET_ERR_ACCESS_DENIED";
203                 /** Operation is in progress */
204         case NET_ERR_IN_PROGRESS:
205                 return "NET_ERR_IN_PROGRESS";
206                 /** Operation was aborted by client or network*/
207         case NET_ERR_OPERATION_ABORTED:
208                 return "NET_ERR_OPERATION_ABORTED";
209                 /** Invalid value of API parameter */
210         case NET_ERR_INVALID_PARAM:
211                 return "NET_ERR_INVALID_PARAM";
212                 /** invalid operation depending on current state */
213         case NET_ERR_INVALID_OPERATION:
214                 return "NET_ERR_INVALID_OPERATION";
215
216                 /** Feature not supported */
217         case NET_ERR_NOT_SUPPORTED:
218                 return "NET_ERR_NOT_SUPPORTED";
219                 /** TimeOut Error */
220         case NET_ERR_TIME_OUT:
221                 return "NET_ERR_TIME_OUT";
222                 /** Network service is not available*/
223         case NET_ERR_NO_SERVICE:
224                 return "NET_ERR_NO_SERVICE";
225                 /** DBus can't find appropriate method */
226         case NET_ERR_UNKNOWN_METHOD:
227                 return "NET_ERR_UNKNOWN_METHOD";
228                 /** Operation is restricted */
229         case NET_ERR_SECURITY_RESTRICTED:
230                 return "NET_ERR_SECURITY_RESTRICTED";
231                 /** WiFi driver on/off failed */
232         case NET_ERR_WIFI_DRIVER_FAILURE:
233                 return "NET_ERR_WIFI_DRIVER_FAILURE";
234         default:
235                 return "INVALID";
236         }
237         /* LCOV_EXCL_STOP */
238 }
239
240 int _net_is_valid_service_type(net_service_type_t service_type)
241 {
242         switch (service_type) {
243         case NET_SERVICE_INTERNET:
244         case NET_SERVICE_MMS:
245         case NET_SERVICE_PREPAID_INTERNET:
246         case NET_SERVICE_PREPAID_MMS:
247         case NET_SERVICE_TETHERING:
248         case NET_SERVICE_APPLICATION:
249                 break;
250         default:
251                 return FALSE;
252         }
253
254         return TRUE; //LCOV_EXCL_LINE
255 }
256
257 net_device_t _net_get_tech_type_from_path(const char *profile_name)
258 {
259         __NETWORK_FUNC_ENTER__;
260
261         net_device_t device_type = NET_DEVICE_UNKNOWN;
262
263         /* LCOV_EXCL_START */
264         if (g_str_has_prefix(profile_name,
265                         CONNMAN_WIFI_SERVICE_PROFILE_PREFIX) == TRUE)
266                 device_type = NET_DEVICE_WIFI;
267         else if (g_str_has_prefix(profile_name,
268                         CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX) == TRUE)
269                 device_type = NET_DEVICE_CELLULAR;
270         else if (g_str_has_prefix(profile_name,
271                         CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX) == TRUE)
272                 device_type = NET_DEVICE_ETHERNET;
273         else if (g_str_has_prefix(profile_name,
274                         CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX) == TRUE)
275                 device_type = NET_DEVICE_BLUETOOTH;
276         else if (g_str_has_prefix(profile_name,
277                         CONNMAN_MESH_PROFILE_PREFIX) == TRUE)
278                 device_type = NET_DEVICE_MESH;
279         /* LCOV_EXCL_STOP */
280
281         __NETWORK_FUNC_EXIT__;
282         return device_type;
283 }
284
285 int _net_get_tech_state(GVariant *msg, network_tech_state_info_t* tech_state)
286 {
287         __NETWORK_FUNC_ENTER__;
288
289         net_err_t Error = NET_ERR_NONE;
290         GVariantIter *iter_main = NULL;
291         GVariantIter *var = NULL;
292         GVariant *value = NULL;
293         gchar *tech_prefix;
294         gchar *path = NULL;
295         gchar *key = NULL;
296         gboolean data;
297
298         /* LCOV_EXCL_START */
299         if (g_strcmp0(tech_state->technology, "wifi") == 0)
300                 tech_prefix = CONNMAN_WIFI_TECHNOLOGY_PREFIX;
301         else if (g_strcmp0(tech_state->technology, "cellular") == 0)
302                 tech_prefix = CONNMAN_CELLULAR_TECHNOLOGY_PREFIX;
303         else if (g_strcmp0(tech_state->technology, "ethernet") == 0)
304                 tech_prefix = CONNMAN_ETHERNET_TECHNOLOGY_PREFIX;
305         else if (g_strcmp0(tech_state->technology, "bluetooth") == 0)
306                 tech_prefix = CONNMAN_BLUETOOTH_TECHNOLOGY_PREFIX;
307         else if (g_strcmp0(tech_state->technology, "mesh") == 0)
308                 tech_prefix = CONNMAN_MESH_TECHNOLOGY_PREFIX;
309         else {
310                 NETWORK_LOG(NETWORK_ERROR, "Invalid technology type");
311                 Error = NET_ERR_INVALID_PARAM;
312                 goto done;
313         }
314         /* LCOV_EXCL_STOP */
315
316         g_variant_get(msg, "(a(oa{sv}))", &iter_main);
317         while (g_variant_iter_loop(iter_main, "(oa{sv})", &path, &var)) {
318
319                 if (path == NULL || g_strcmp0(path, tech_prefix) != 0)
320                         continue;
321
322                 while (g_variant_iter_loop(var, "{sv}", &key, &value)) {
323                         if (g_strcmp0(key, "Powered") == 0) {
324                                 data = g_variant_get_boolean(value);
325
326                                 if (data)
327                                         tech_state->Powered = TRUE;
328                                 else
329                                         tech_state->Powered = FALSE; //LCOV_EXCL_LINE
330                         } else if (g_strcmp0(key, "Connected") == 0) {
331                                 data = g_variant_get_boolean(value);
332
333                                 if (data)
334                                         tech_state->Connected = TRUE;
335                                 else
336                                         tech_state->Connected = FALSE; //LCOV_EXCL_LINE
337                         } else if (g_strcmp0(key, "Tethering") == 0) {
338                                 /* For further use */
339                         }
340                 }
341         }
342         g_variant_iter_free(iter_main);
343
344 done:
345         __NETWORK_FUNC_EXIT__;
346         return Error;
347 }
348
349 void _net_clear_request_table(network_info_t *network_info)
350 {
351         __NETWORK_FUNC_ENTER__;
352
353         int i;
354
355         if (network_info) {
356                 for (i = 0; i < NETWORK_REQUEST_TYPE_MAX; i++)
357                         memset(&(network_info->request_table[i]), 0, sizeof(network_request_table_t));
358         }
359
360         __NETWORK_FUNC_EXIT__;
361 }
362
363 int _net_dbus_create_gdbus_call(network_info_t *network_info)
364 {
365         GError *error = NULL;
366
367 #if !GLIB_CHECK_VERSION(2, 36, 0)
368         g_type_init();
369 #endif
370
371         if (network_info) {
372                 network_info->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
373                 if (network_info->connection == NULL) {
374                         /* LCOV_EXCL_START */
375                         if (error != NULL) {
376                                 NETWORK_LOG(NETWORK_ERROR,
377                                                 "Failed to connect to the D-BUS daemon [%s]", error->message);
378                                 g_error_free(error);
379                         }
380                         /* LCOV_EXCL_STOP */
381                         return NET_ERR_UNKNOWN;
382                 }
383
384                 network_info->cancellable = g_cancellable_new();
385         }
386
387         return NET_ERR_NONE;
388 }
389
390 void _net_dbus_close_gdbus_call(network_info_t *network_info)
391 {
392         if (network_info) {
393                 g_cancellable_cancel(network_info->cancellable);
394                 g_object_unref(network_info->cancellable);
395                 network_info->cancellable = NULL;
396
397                 g_object_unref(network_info->connection);
398                 network_info->connection = NULL;
399         }
400 }