Header files unification
[platform/core/telephony/tel-plugin-indicator.git] / src / desc-indicator.c
1 /*
2  * tel-plugin-indicator
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <storage.h>
29 #include <co_ps.h>
30 #include <co_context.h>
31
32 #define INDICATOR_UPDATE_INTERVAL       1
33 #define INDICATOR_PROCFILE              "/proc/net/dev"
34 #define INDICATOR_BUFF_SIZE             4096
35 #define NO_RX_PKT_TIMEOUT       30
36 //enum
37
38 typedef enum _cellular_state {
39         CELLULAR_OFF = 0x00,
40         CELLULAR_NORMAL_CONNECTED = 0x01,
41         CELLULAR_SECURE_CONNECTED = 0x02,
42         CELLULAR_USING = 0x03,
43 } cellular_state;
44
45 typedef enum _indicator_state {
46         INDICATOR_NORMAL = 0x00,
47         INDICATOR_RX = 0x01,
48         INDICATOR_TX = 0x02,
49         INDICATOR_RXTX = 0x03,
50 } indicator_state;
51
52 typedef struct _indicator_device_state {
53         gchar *devname;
54         gboolean active;
55         guint64 prev_rx;
56         guint64 prev_tx;
57         guint64 curr_rx;
58         guint64 curr_tx;
59 }indicator_device_state;
60
61 typedef struct _indicator_data {
62         indicator_device_state indicator_info;
63         GSource* src;
64 }indicator_data;
65
66 static gboolean _indicator_update_callback(gpointer user_data);
67
68 static void _indicator_initialize(indicator_data *data)
69 {
70         if (data) {
71                 data->indicator_info.prev_rx = 0;
72                 data->indicator_info.prev_tx = 0;
73                 data->indicator_info.curr_rx = 0;
74                 data->indicator_info.curr_tx = 0;
75         } else {
76                 err("user data is NULL");
77         }
78 }
79
80
81 static gboolean _indicator_start_updater(Server *s, TcorePlugin *plugin)
82 {
83         TcoreStorage *strg_vconf;
84         indicator_data *data = NULL;
85
86         dbg("indicator is started");
87         strg_vconf = tcore_server_find_storage(s, "vconf");
88
89         data = tcore_plugin_ref_user_data(plugin);
90         if(!data) {
91                 err("user data is NULL");
92                 return FALSE;
93         }
94
95         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, CELLULAR_NORMAL_CONNECTED);
96         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, INDICATOR_NORMAL);
97
98         if(data->src != 0) {
99                 return FALSE;
100         }
101
102         _indicator_initialize(data);
103
104         data->src = g_timeout_source_new_seconds(INDICATOR_UPDATE_INTERVAL);
105         g_source_set_callback(data->src, _indicator_update_callback, plugin, NULL);
106         g_source_set_priority(data->src, G_PRIORITY_HIGH);
107         g_source_attach(data->src, NULL);
108         g_source_unref(data->src);
109
110         return TRUE;
111 }
112
113 static gboolean _indicator_stop_updater(Server *s, TcorePlugin *plugin)
114 {
115         TcoreStorage *strg_vconf;
116         int t_rx = 0, t_tx = 0;
117         indicator_data *data = NULL;
118
119         dbg("indicator is stopped");
120         data = tcore_plugin_ref_user_data(plugin);
121         if (!data) {
122                 err("user data is NULL");
123                 return FALSE;
124         }
125         strg_vconf = tcore_server_find_storage(s, "vconf");
126
127         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, CELLULAR_OFF);
128         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, INDICATOR_NORMAL);
129
130         t_rx = tcore_storage_get_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV);
131         t_tx = tcore_storage_get_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT);
132         t_rx += (int)data->indicator_info.curr_rx;
133         t_tx += (int)data->indicator_info.curr_tx;
134
135         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV, t_rx);
136         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT, t_tx);
137         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_LAST_RCV, (int)data->indicator_info.curr_rx);
138         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_LAST_SNT, (int)data->indicator_info.curr_tx);
139
140         if(data->src == 0){
141                 return TRUE;
142         }
143
144         g_source_destroy(data->src);
145         data->src = 0;
146
147         return TRUE;
148 }
149
150 static gint _indicator_get_proc_ver(gchar *buff)
151 {
152         if (strstr(buff, "compressed")) return 3;
153         if (strstr(buff, "bytes")) return 2;
154         return 1;
155 }
156
157 static gint _indicator_get_pkt(gchar *buff, gint proc_ver, guint64 *rx_pkt, guint64 *tx_pkt)
158 {
159         gint result = -1;
160         gchar s_rx[100];
161         gchar s_tx[100];
162
163         memset(s_rx, 0 , 100);
164         memset(s_tx, 0 , 100);
165
166         if (buff == NULL)
167                 return result;
168
169         switch (proc_ver) {
170         case 3:
171                 result = sscanf(buff,
172                                 "%s %*s %*s %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s %*s %*s",
173                                 s_rx, s_tx);
174                 break;
175         case 2:
176                 result = sscanf(buff,
177                                 "%s %*s %*s %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s %*s %*s",
178                                 s_rx, s_tx);
179                 break;
180         case 1:
181                 result = sscanf(buff,
182                                 "%s %*s %*s %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s %*s %*s",
183                                 s_rx, s_tx);
184                 break;
185         default:
186                 dbg("stats unknown version");
187                 break;
188         }
189
190         *rx_pkt = g_ascii_strtoull(s_rx, NULL, 10);
191         *tx_pkt = g_ascii_strtoull(s_tx, NULL, 10);
192
193         return result;
194 }
195
196 static gboolean _indicator_get_pktcnt(indicator_data *data)
197 {
198         FILE *pf = NULL;
199         gint proc_ver = 0;
200         char *res;
201         gchar buff[INDICATOR_BUFF_SIZE];
202
203         if (!data) {
204                 err("user data is NULL");
205                 return FALSE;
206         }
207
208         pf = fopen(INDICATOR_PROCFILE, "r");
209         if (pf == NULL) {
210                 err("indicator fail to open file(%s), errno(%d)", INDICATOR_PROCFILE, errno);
211                 return FALSE;
212         }
213
214         res = fgets(buff, sizeof(buff), pf);
215         if (res == NULL)
216                 err("fegts fails");
217         res = fgets(buff, sizeof(buff), pf);
218         if (res == NULL)
219                 err("fegts fails");
220         proc_ver = _indicator_get_proc_ver(buff);
221
222         while (fgets(buff, sizeof(buff), pf)) {
223                 gint result = 0;
224                 guint64 rx_pkt = 0;
225                 guint64 tx_pkt = 0;
226                 gchar *ifname, *entry;
227
228                 ifname = buff;
229                 while (*ifname == ' ')
230                         ifname++;
231                 entry = strrchr(ifname, ':');
232                 *entry++ = 0;
233
234                 result = _indicator_get_pkt(entry, proc_ver, &rx_pkt, &tx_pkt);
235                 if (result <= 0) {
236                         err("stats fail to get proc field");
237                         fclose(pf);
238                         return FALSE;
239                 }
240
241                 if ( g_strcmp0(ifname, data->indicator_info.devname) == 0 ){
242                         data->indicator_info.prev_rx = data->indicator_info.curr_rx;
243                         data->indicator_info.prev_tx = data->indicator_info.curr_tx;
244                         data->indicator_info.curr_rx = rx_pkt;
245                         data->indicator_info.curr_tx = tx_pkt;
246                         break;
247                 }
248         }
249
250         fclose(pf);
251         return TRUE;
252 }
253
254 static gboolean _indicator_update(Server *s, indicator_data *data)
255 {
256         guint64 rx_changes = 0;
257         guint64 tx_changes = 0;
258         TcoreStorage *strg_vconf;
259
260         strg_vconf = tcore_server_find_storage(s, "vconf");
261         if(!data) return FALSE;
262         if(!data->indicator_info.active) return FALSE;
263
264         rx_changes = data->indicator_info.curr_rx - data->indicator_info.prev_rx;
265         tx_changes = data->indicator_info.curr_tx - data->indicator_info.prev_tx;
266
267         if (rx_changes != 0 || tx_changes != 0)
268                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, CELLULAR_USING);
269         else
270                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, CELLULAR_NORMAL_CONNECTED);
271
272         if (rx_changes > 0 && tx_changes > 0)
273                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, INDICATOR_RXTX);
274         else if (rx_changes > 0 && tx_changes == 0)
275                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, INDICATOR_RX);
276         else if (rx_changes == 0 && tx_changes > 0)
277                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, INDICATOR_TX);
278         else
279                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, INDICATOR_NORMAL);
280
281         return TRUE;
282 }
283
284 static gboolean _indicator_update_callback(gpointer user_data)
285 {
286         gboolean rv = FALSE;
287         TcorePlugin *indicator_plugin = NULL;
288         Server *s = NULL;
289         indicator_data *data = NULL;
290
291         indicator_plugin = (TcorePlugin *)user_data;
292         s = tcore_plugin_ref_server(indicator_plugin);
293         data = tcore_plugin_ref_user_data(indicator_plugin);
294         if(!data){
295                 err("user data is NULL");
296                 return FALSE;
297         }
298
299         rv = _indicator_get_pktcnt(data);
300         if(!rv){
301                 data->src = 0;
302                 return FALSE;
303         }
304
305         rv = _indicator_update(s, data);
306         if(!rv){
307                 data->src = 0;
308                 return FALSE;
309         }
310
311         return TRUE;
312 }
313
314 static TcoreHookReturn __on_hook_modem_powered(TcorePlugin *source,
315         TcoreNotification command, guint data_len, void *data, void *user_data)
316 {
317         TelModemPowerStatus *power_status = NULL;
318
319         dbg("powered event called");
320         tcore_check_return_value(data != NULL, TCORE_HOOK_RETURN_STOP_PROPAGATION);
321
322         power_status = (TelModemPowerStatus *)data;
323         if (*power_status == TEL_MODEM_POWER_ERROR) {
324                 Server *s = NULL;
325                 indicator_data *data = NULL;
326                 TcorePlugin *plugin = (TcorePlugin *)user_data;
327
328                 data = tcore_plugin_ref_user_data(plugin);
329                 if (data) {
330                         data->indicator_info.active = FALSE;
331                         g_free(data->indicator_info.devname);
332                         data->indicator_info.devname = NULL;
333                         s = tcore_plugin_ref_server(source);
334                         if (s) {
335                                 _indicator_stop_updater(s, plugin);
336                         }
337                 }else {
338                         err("user data is NULL");
339                 }
340         }
341
342         return TCORE_HOOK_RETURN_CONTINUE;
343 }
344
345 static TcoreHookReturn __on_hook_ps_callstatus(TcorePlugin *source,
346         TcoreNotification command, guint data_len, void *data, void *user_data)
347 {
348         unsigned int con_id = 0;
349         CoreObject *co_ps = NULL, *co_context = NULL;
350         TcorePsCallStatusInfo *cstatus = NULL;
351         TcorePlugin *plugin = NULL;
352         indicator_data *indata = NULL;
353         Server *s = NULL;
354         gboolean res = FALSE;
355
356         dbg("call status event");
357         tcore_check_return_value((data != NULL) || (user_data != NULL), TCORE_HOOK_RETURN_STOP_PROPAGATION);
358
359         plugin = (TcorePlugin *)user_data;
360         indata = tcore_plugin_ref_user_data(plugin);
361         tcore_check_return_value((indata != NULL) , TCORE_HOOK_RETURN_STOP_PROPAGATION);
362
363         s = tcore_plugin_ref_server(source);
364         co_ps = tcore_plugin_ref_core_object(source, CORE_OBJECT_TYPE_PS);
365         dbg("ps object(%p)", co_ps);
366         co_context = tcore_ps_ref_context_by_role(co_ps, TCORE_CONTEXT_ROLE_INTERNET);
367         res = tcore_context_get_id(co_context, &con_id);
368         if (res == FALSE) {
369                 err("get context id failed");
370                 return TCORE_HOOK_RETURN_CONTINUE;
371         }
372         dbg("context(%p) con_id(%d)", co_context, con_id);
373
374         cstatus = (TcorePsCallStatusInfo *) data;
375         if (!cstatus) {
376                 err("PS status is NULL");
377                 return TCORE_HOOK_RETURN_CONTINUE;
378         }
379         dbg("call status event cid(%d) state(%d)", cstatus->context_id, cstatus->state);
380
381         if(con_id != cstatus->context_id)
382                 return TCORE_HOOK_RETURN_CONTINUE;
383
384         if (cstatus->state == TCORE_PS_CALL_STATE_CTX_DEFINED) {
385                 /* do nothing. */
386                 dbg("Just noti for PDP define complete, do nothing.");
387                 return TCORE_HOOK_RETURN_CONTINUE;
388         }
389         else if (cstatus->state == TCORE_PS_CALL_STATE_CONNECTED) {
390                 indata->indicator_info.active = TRUE;
391                 res = tcore_context_get_ipv4_devname(co_context, &indata->indicator_info.devname);
392                 if (res == FALSE) {
393                         err("get context ipv4 failed");
394                         return TCORE_HOOK_RETURN_CONTINUE;
395                 }
396                 _indicator_start_updater(s, plugin);
397                 return TCORE_HOOK_RETURN_CONTINUE;
398         }
399
400         indata->indicator_info.active = FALSE;
401         g_free(indata->indicator_info.devname);
402         indata->indicator_info.devname = NULL;
403         _indicator_stop_updater(s, plugin);
404         return TCORE_HOOK_RETURN_CONTINUE;
405 }
406
407 static TcoreHookReturn __on_hook_modem_plugin_added(Server *s,
408                         TcoreServerNotification command,
409                         guint data_len, void *data, void *user_data)
410 {
411         TcorePlugin *modem_plugin;
412         TcorePlugin *indicator_plugin = (TcorePlugin *)user_data;
413
414         modem_plugin = (TcorePlugin *)data;
415         tcore_check_return_value_assert(NULL != modem_plugin, TCORE_HOOK_RETURN_STOP_PROPAGATION);
416
417         tcore_plugin_add_notification_hook(modem_plugin, TCORE_NOTIFICATION_MODEM_POWER,
418                                                                                 __on_hook_modem_powered, indicator_plugin);
419         tcore_plugin_add_notification_hook(modem_plugin, TCORE_NOTIFICATION_PS_CALL_STATUS,
420                                                                                 __on_hook_ps_callstatus, indicator_plugin);
421
422         return TCORE_HOOK_RETURN_CONTINUE;
423 }
424
425 static TcoreHookReturn __on_hook_modem_plugin_removed(Server *s,
426                         TcoreServerNotification command,
427                         guint data_len, void *data, void *user_data)
428 {
429         TcorePlugin *modem_plugin;
430
431         modem_plugin = (TcorePlugin *)data;
432         tcore_check_return_value_assert(NULL != modem_plugin, TCORE_HOOK_RETURN_STOP_PROPAGATION);
433
434         tcore_plugin_remove_notification_hook(modem_plugin, TCORE_NOTIFICATION_MODEM_POWER,
435                                         __on_hook_modem_powered);
436         tcore_plugin_remove_notification_hook(modem_plugin, TCORE_NOTIFICATION_PS_CALL_STATUS,
437                                         __on_hook_ps_callstatus);
438
439         return TCORE_HOOK_RETURN_CONTINUE;
440 }
441
442 static gboolean on_load()
443 {
444         dbg("Indicator plugin load!");
445         return TRUE;
446 }
447
448 static gboolean on_init(TcorePlugin *p)
449 {
450         Server *s = NULL;
451         GSList *list = NULL;
452         indicator_data *data = NULL;
453         TelReturn ret = TEL_RETURN_FAILURE;
454
455         data = tcore_malloc0(sizeof(indicator_data));
456         if (!data) {
457                 err("Failed to allocate memory");
458                 return FALSE;
459         }
460         ret = tcore_plugin_link_user_data(p, data);
461         if (ret != TEL_RETURN_SUCCESS) {
462                 err("Unable to link user data");
463                 free(data);
464                 return FALSE;
465         }
466
467         s = tcore_plugin_ref_server(p);
468         list = tcore_server_get_modem_plugin_list(s);
469         while (list) {  /* Process for pre-loaded Modem Plug-in */
470                 TcorePlugin *modem_plugin;
471
472                 modem_plugin = list->data;
473                 if ( NULL != modem_plugin) {
474                         tcore_plugin_add_notification_hook(modem_plugin, TCORE_NOTIFICATION_MODEM_POWER,
475                                                                                                 __on_hook_modem_powered, p);
476                         tcore_plugin_add_notification_hook(modem_plugin, TCORE_NOTIFICATION_PS_CALL_STATUS,
477                                                                                                 __on_hook_ps_callstatus, p);
478                 }
479                 list = g_slist_next(list);
480         }
481         g_slist_free(list);
482
483         /* Register for post-loaded Modem Plug-ins */
484         tcore_server_add_notification_hook(s, TCORE_SERVER_NOTIFICATION_ADDED_MODEM_PLUGIN,
485                                         __on_hook_modem_plugin_added, p);
486         tcore_server_add_notification_hook(s, TCORE_SERVER_NOTIFICATION_REMOVED_MODEM_PLUGIN,
487                                         __on_hook_modem_plugin_removed, p);
488         dbg("initialized Indicator plugin!");
489         return TRUE;
490 }
491
492 static void on_unload(TcorePlugin *p)
493 {
494         indicator_data *data = NULL;
495         dbg("i'm unload!");
496
497         data = tcore_plugin_ref_user_data(p);
498         if (data->src) {
499                 g_source_destroy(data->src);
500                 data->src = NULL;
501         }
502         tcore_free(data);
503         data = NULL;
504         return;
505 }
506
507 struct tcore_plugin_define_desc plugin_define_desc =
508 {
509         .name = "INDICATOR",
510         .priority = TCORE_PLUGIN_PRIORITY_MID + 2,
511         .version = 1,
512         .load = on_load,
513         .init = on_init,
514         .unload = on_unload
515 };