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