4dfa790e04219b61e452fbfd061dccf6cf6b616c
[platform/core/telephony/tel-plugin-indicator.git] / src / desc-indicator.c
1 /*
2  * tel-plugin-indicator
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: DongHoo Park <donghoo.park@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 <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <glib.h>
27
28 #include <tcore.h>
29 #include <server.h>
30 #include <plugin.h>
31 #include <storage.h>
32 #include <co_ps.h>
33 #include <co_context.h>
34
35 #define INDICATOR_UPDATE_INTERVAL       1
36 #define INDICATOR_PROCFILE              "/proc/net/dev"
37 #define INDICATOR_BUFF_SIZE             4096
38 #define DATABASE_PATH           "/opt/dbspace/.dnet.db"
39 #define NO_RX_PKT_TIMEOUT       30
40 //enum
41 typedef enum _indicator_state {
42         INDICATOR_OFF = 0x00,
43         INDICATOR_ON = 0x01,
44         INDICATOR_ONLINE = 0x03,
45 } indicator_state;
46
47 typedef enum _ps_call_state {
48         PS_CALL_STATE_RESULT_OK = 0x00,
49         PS_CALL_STATE_RESULT_CONNECT = 0x01,
50         PS_CALL_STATE_RESULT_NO_CARRIER = 0x03,
51 } ps_call_state;
52
53 struct indicator_device_state {
54         gchar *devname;
55         gboolean active;
56         guint64 prev_rx;
57         guint64 prev_tx;
58         guint64 curr_rx;
59         guint64 curr_tx;
60 };
61
62 //global variable
63 static struct  indicator_device_state indicator_info = {
64         NULL,FALSE,0,0,0,0
65 };
66
67 static GSource* src;
68 static gboolean _indicator_update_callback(gpointer user_data);
69
70 static void _indicator_initialize(Server *s)
71 {
72         indicator_info.prev_rx = 0;
73         indicator_info.prev_tx = 0;
74         indicator_info.curr_rx = 0;
75         indicator_info.curr_tx = 0;
76 }
77
78 static gboolean _indicator_start_updater(Server *s)
79 {
80         Storage *strg_vconf;
81         gpointer vconf_handle;
82
83         dbg("indicator is started");
84
85         strg_vconf = tcore_server_find_storage(s, "vconf");
86         vconf_handle = tcore_storage_create_handle(strg_vconf, "vconf");
87         if (!vconf_handle)
88                 err("fail to create vconf db_handle");
89
90         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, INDICATOR_ON);
91
92         if(src != 0)
93                 return FALSE;
94
95         _indicator_initialize(s);
96
97         src = g_timeout_source_new_seconds(INDICATOR_UPDATE_INTERVAL);
98         g_source_set_callback(src, _indicator_update_callback, s, NULL);
99         g_source_set_priority(src, G_PRIORITY_HIGH);
100         g_source_attach(src, NULL);
101         g_source_unref(src);
102
103         return TRUE;
104 }
105
106 static gboolean _indicator_stop_updater(Server *s)
107 {
108         Storage *strg_vconf;
109         gpointer vconf_handle;
110         int t_rx = 0, t_tx = 0;
111
112         dbg("indicator is stopped");
113         strg_vconf = tcore_server_find_storage(s, "vconf");
114         vconf_handle = tcore_storage_create_handle(strg_vconf, "vconf");
115         if (!vconf_handle)
116                 err("fail to create vconf db_handle");
117
118         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, INDICATOR_OFF);
119
120         t_rx = tcore_storage_get_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV);
121         t_tx = tcore_storage_get_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT);
122         t_rx += (int)indicator_info.curr_rx;
123         t_tx += (int)indicator_info.curr_tx;
124
125         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV, t_rx);
126         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT, t_tx);
127         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_LAST_RCV, (int)indicator_info.curr_rx);
128         tcore_storage_set_int(strg_vconf, STORAGE_KEY_CELLULAR_PKT_LAST_SNT, (int)indicator_info.curr_tx);
129
130         if(src == 0)
131                 return TRUE;
132
133         g_source_destroy(src);
134         src = 0;
135
136         return TRUE;
137 }
138
139 static gint _indicator_get_proc_ver(gchar *buff)
140 {
141         if (strstr(buff, "compressed")) return 3;
142         if (strstr(buff, "bytes")) return 2;
143         return 1;
144 }
145
146 static gint _indicator_get_pkt(gchar *buff, gint proc_ver, guint64 *rx_pkt, guint64 *tx_pkt)
147 {
148         gint result = -1;
149         gchar s_rx[100];
150         gchar s_tx[100];
151
152         memset(s_rx, 0 , 100);
153         memset(s_tx, 0 , 100);
154
155         if (buff == NULL)
156                 return result;
157
158         switch (proc_ver) {
159         case 3:
160                 result = sscanf(buff,
161                                 "%s %*s %*s %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s %*s %*s",
162                                 s_rx, s_tx);
163                 break;
164         case 2:
165                 result = sscanf(buff,
166                                 "%s %*s %*s %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s %*s %*s",
167                                 s_rx, s_tx);
168                 break;
169         case 1:
170                 result = sscanf(buff,
171                                 "%s %*s %*s %*s %*s %*s %*s %*s %s %*s %*s %*s %*s %*s %*s %*s",
172                                 s_rx, s_tx);
173                 break;
174         default:
175                 dbg("stats unknown version");
176                 break;
177         }
178
179         *rx_pkt = g_ascii_strtoull(s_rx, NULL, 10);
180         *tx_pkt = g_ascii_strtoull(s_tx, NULL, 10);
181
182         return result;
183 }
184
185 static gboolean _indicator_get_pktcnt(gpointer user_data)
186 {
187         FILE *pf = NULL;
188         gint proc_ver = 0;
189         gchar buff[INDICATOR_BUFF_SIZE];
190         gchar *rv = NULL;
191
192         pf = fopen(INDICATOR_PROCFILE, "r");
193         if (pf == NULL) {
194                 err("indicator fail to open file(%s), errno(%d)", INDICATOR_PROCFILE, errno);
195                 return FALSE;
196         }
197
198         rv = fgets(buff, sizeof(buff), pf);
199         rv = fgets(buff, sizeof(buff), pf);
200         proc_ver = _indicator_get_proc_ver(buff);
201
202         while (fgets(buff, sizeof(buff), pf)) {
203                 gint result = 0;
204                 guint64 rx_pkt = 0;
205                 guint64 tx_pkt = 0;
206                 gchar *ifname, *entry;
207
208                 ifname = buff;
209                 while (*ifname == ' ')
210                         ifname++;
211                 entry = strrchr(ifname, ':');
212                 *entry++ = 0;
213
214                 result = _indicator_get_pkt(entry, proc_ver, &rx_pkt, &tx_pkt);
215                 if (result <= 0) {
216                         err("stats fail to get proc field");
217                         fclose(pf);
218                         return FALSE;
219                 }
220
221                 if ( g_strcmp0(ifname, indicator_info.devname) == 0 ){
222                         indicator_info.prev_rx = indicator_info.curr_rx;
223                         indicator_info.prev_tx = indicator_info.curr_tx;
224                         indicator_info.curr_rx = rx_pkt;
225                         indicator_info.curr_tx = tx_pkt;
226                         break;
227                 }
228         }
229
230         fclose(pf);
231         return TRUE;
232 }
233
234 static gboolean _indicator_update(Server *s)
235 {
236         gint pkt_state = 0;
237         Storage *strg_vconf;
238         gpointer vconf_handle;
239
240         strg_vconf = tcore_server_find_storage(s, "vconf");
241         vconf_handle = tcore_storage_create_handle(strg_vconf, "vconf");
242         if (!vconf_handle)
243                 err("fail to create vconf db_handle");
244
245         pkt_state  = tcore_storage_get_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE);
246
247         if(!indicator_info.active) return FALSE;
248
249         if ((indicator_info.curr_rx > indicator_info.prev_rx)
250                         || (indicator_info.curr_tx > indicator_info.prev_tx)) {
251                 if(pkt_state != INDICATOR_ONLINE)
252                         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, INDICATOR_ONLINE);
253         }
254         else{ //rx, tx are the same as before
255                 if(pkt_state != INDICATOR_ON)
256                         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_SERVICE_STATE, INDICATOR_ON);
257         }
258
259         return TRUE;
260 }
261
262 static gboolean _indicator_update_callback(gpointer user_data)
263 {
264         gboolean rv = FALSE;
265         Server *s = NULL;
266
267         s = (Server *)user_data;
268
269         rv = _indicator_get_pktcnt(NULL);
270         if(!rv){
271                 src = 0;
272                 return FALSE;
273         }
274
275         rv = _indicator_update(s);
276         if(!rv){
277                 src = 0;
278                 return FALSE;
279         }
280
281         return TRUE;
282 }
283
284 static enum tcore_hook_return __on_hook_powered(Server *s, CoreObject *source,
285                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
286 {
287         struct tnoti_modem_power *modem_power = NULL;
288
289         dbg("powered event called");
290         g_return_val_if_fail(data != NULL, TCORE_HOOK_RETURN_STOP_PROPAGATION);
291
292         modem_power = (struct tnoti_modem_power *)data;
293         if ( modem_power->state == MODEM_STATE_ERROR ){
294                 indicator_info.active = FALSE;
295                 g_free(indicator_info.devname);
296                 indicator_info.devname = NULL;
297                 _indicator_stop_updater(s);
298         }
299
300         return TCORE_HOOK_RETURN_CONTINUE;
301 }
302
303 static enum tcore_hook_return __on_hook_callstatus(Server *s, CoreObject *source,
304                 enum tcore_notification_command command, unsigned int data_len, void *data,
305                 void *user_data)
306 {
307         int con_id = 0;
308         CoreObject *co_ps = NULL, *co_context = NULL;
309         struct tnoti_ps_call_status *cstatus = NULL;
310
311         dbg("call status event");
312         g_return_val_if_fail(data != NULL, TCORE_HOOK_RETURN_STOP_PROPAGATION);
313
314         co_ps = source;
315         dbg("ps object(%p)", co_ps);
316         co_context = tcore_ps_ref_context_by_role(co_ps, CONTEXT_ROLE_INTERNET);
317         con_id = tcore_context_get_id(co_context);
318         dbg("context(%p) con_id(%d)", co_context, con_id);
319
320         cstatus = (struct tnoti_ps_call_status *) data;
321         dbg("call status event cid(%d) state(%d) reason(%d)", cstatus->context_id, cstatus->state, cstatus->result);
322
323         if(con_id != cstatus->context_id)
324                 return TCORE_HOOK_RETURN_CONTINUE;
325
326         if (cstatus->state == PS_CALL_STATE_RESULT_OK) {
327                 /* do nothing. */
328                 dbg("Just noti for PDP define complete, do nothing.");
329                 return TCORE_HOOK_RETURN_CONTINUE;
330         }
331         else if (cstatus->state == PS_CALL_STATE_RESULT_CONNECT) {
332                 indicator_info.active = TRUE;
333                 indicator_info.devname = tcore_context_get_ipv4_devname(co_context);
334                 _indicator_start_updater(s);
335                 return TCORE_HOOK_RETURN_CONTINUE;
336         }
337
338         indicator_info.active = FALSE;
339         g_free(indicator_info.devname);
340         indicator_info.devname = NULL;
341         _indicator_stop_updater(s);
342
343         return TCORE_HOOK_RETURN_CONTINUE;
344 }
345
346 static gboolean on_load()
347 {
348         dbg("Indicator plugin load!");
349         return TRUE;
350 }
351
352 static gboolean on_init(TcorePlugin *p)
353 {
354         Server *s = NULL;
355         s = tcore_plugin_ref_server(p);
356         tcore_server_add_notification_hook(s, TNOTI_MODEM_POWER, __on_hook_powered, NULL);
357         tcore_server_add_notification_hook(s, TNOTI_PS_CALL_STATUS, __on_hook_callstatus, NULL);
358         dbg("initialized Indicator plugin!");
359         return TRUE;
360 }
361
362 static void on_unload(TcorePlugin *p)
363 {
364         dbg("i'm unload!");
365         return;
366 }
367
368 struct tcore_plugin_define_desc plugin_define_desc =
369 {
370         .name = "INDICATOR",
371         .priority = TCORE_PLUGIN_PRIORITY_MID + 2,
372         .version = 1,
373         .load = on_load,
374         .init = on_init,
375         .unload = on_unload
376 };