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