2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "stc-manager.h"
20 #include "stc-monitor.h"
21 #include "stc-monitor-app.h"
22 #include "stc-monitor-rstn.h"
23 #include "stc-monitor-proc.h"
24 #include "stc-monitor-ipt.h"
25 #include "table-statistics.h"
26 #include "helper-net-cls.h"
27 #include "stc-manager-plugin-tether.h"
29 static void __print_app(gpointer key, gpointer value,
32 stc_app_value_s *app_value = (stc_app_value_s *)value;
34 STC_LOGD("PkgID[%s] AppID[\033[0;32m%s\033[0;m] "
35 "type[%d] state[%d] classid[\033[1;36m%d\033[0;m] "
36 "counter[in(%lld) out(%lld)]",
37 app_value->pkg_id, app_value->app_id,
38 app_value->type, app_value->state,
40 app_value->data_usage.in_bytes,
41 app_value->data_usage.out_bytes);
44 static void __app_update_statistics(gpointer key,
45 gpointer value, gpointer data)
47 stc_app_value_s *app_value = (stc_app_value_s *)value;
48 time_t *touch_time = (time_t *)data;
49 GSList *conn_list = stc_get_connection_list();
51 for (; conn_list != NULL; conn_list = conn_list->next) {
52 stc_connection_s *conn = conn_list->data;
53 stc_db_classid_iftype_key stat_key;
54 stc_db_app_stats stat;
56 memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key));
57 memset(&stat, 0 , sizeof(stc_db_app_stats));
62 /* Do not update statistics for Tethering
63 * if tethering is in-active found */
64 if (conn && conn->tether_state == FALSE &&
65 !strcmp(app_value->app_id, STC_TOTAL_TETHERING))
68 /* Do not update statistics for Wi-Fi
69 * if tethering is active on wlan0 iface */
70 if (conn && conn->tether_state &&
71 conn->tether_iface.type == STC_IFACE_WIFI &&
72 !strcmp(app_value->app_id, STC_TOTAL_WIFI))
75 stat_key.classid = app_value->classid;
77 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
78 conn->tether_state == TRUE)
79 stat_key.iftype = conn->tether_iface.type;
80 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
81 stat_key.iftype = conn->tether_iface.type;
83 stat_key.iftype = conn->type;
85 if (STC_IFACE_DATACALL == stat_key.iftype)
86 stat_key.subscriber_id = g_strdup(conn->subscriber_id);
88 stat_key.subscriber_id = g_strdup(SUBSCRIBERID_NONE);
90 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
91 conn->tether_state == TRUE)
92 g_strlcpy(stat_key.ifname, conn->tether_iface.ifname,
94 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
95 g_strlcpy(stat_key.ifname, conn->tether_iface.ifname,
98 g_strlcpy(stat_key.ifname, conn->ifname,
101 stat.app_id = g_strdup(app_value->app_id);
102 stat.snd_count = app_value->counter.out_bytes;
103 stat.rcv_count = app_value->counter.in_bytes;
104 stat.is_roaming = conn->roaming;
106 if (strstr(stat.app_id, "_BACKGROUND")) {
107 stat.ground = STC_APP_STATE_BACKGROUND;
109 if (strstr(stat.app_id, "TOTAL_"))
110 stat.ground = STC_APP_STATE_UNKNOWN;
112 stat.ground = STC_APP_STATE_FOREGROUND;
115 table_statistics_insert(&stat_key, &stat, *touch_time);
117 app_value->counter.out_bytes = 0;
118 app_value->counter.in_bytes = 0;
121 FREE(stat_key.subscriber_id);
127 static gboolean __add_app_monitor_for_tethering(gpointer key,
128 gpointer value, gpointer data)
130 stc_app_value_s *app_value = (stc_app_value_s *)value;
131 stc_connection_s *connection = (stc_connection_s *)data;
132 stc_s *stc = stc_get_manager();
133 struct nfacct_rule counter;
137 STC_LOGI("Add appid(%s) classid(%d)", app_value->app_id,
140 if (stc == NULL || connection == NULL)
144 stc->carg = MALLOC0(counter_arg_s, 1);
145 if (stc->carg == NULL)
148 stc->carg->sock = stc_monitor_get_contr_sock();
151 memset(&counter, 0, sizeof(struct nfacct_rule));
153 counter.carg = stc->carg;
154 counter.classid = app_value->classid;
155 counter.intend = NFACCT_TETH_COUNTER;
157 if (connection->tether_state != TRUE ||
158 connection->tether_iface.ifname == NULL)
161 counter.iftype = connection->tether_iface.type;
162 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
164 /* get the ip address of the station based on its mac address */
165 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
166 if (ret != STC_ERROR_NONE)
169 /* tethering iptables rule */
170 stc_monitor_tether_add_in(&counter, ipaddr);
171 stc_monitor_tether_add_out(&counter, ipaddr);
177 static gboolean __remove_app_monitor_for_tethering(gpointer key,
178 gpointer value, gpointer data)
180 stc_app_value_s *app_value = (stc_app_value_s *)value;
181 stc_connection_s *connection = (stc_connection_s *)data;
182 stc_s *stc = stc_get_manager();
183 struct nfacct_rule counter;
187 STC_LOGI("Remove appid(%s) classid(%d)", app_value->app_id,
190 if (stc == NULL || connection == NULL)
194 stc->carg = MALLOC0(counter_arg_s, 1);
195 if (stc->carg == NULL)
198 stc->carg->sock = stc_monitor_get_contr_sock();
201 memset(&counter, 0, sizeof(struct nfacct_rule));
203 counter.carg = stc->carg;
204 counter.classid = app_value->classid;
205 counter.intend = NFACCT_TETH_COUNTER;
207 if (connection->tether_state != TRUE ||
208 connection->tether_iface.ifname == NULL)
211 counter.iftype = connection->tether_iface.type;
212 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
214 /* get the ip address of the station based on its mac address */
215 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
216 if (ret != STC_ERROR_NONE)
219 stc_monitor_tether_del_in(&counter, ipaddr);
220 stc_monitor_tether_del_out(&counter, ipaddr);
226 static void __app_value_destroy(gpointer data)
228 stc_app_value_s *app_value = (stc_app_value_s *)data;
230 FREE(app_value->pkg_id);
231 FREE(app_value->app_id);
232 g_hash_table_destroy(app_value->processes);
233 app_value->processes = NULL;
238 static void __check_rstn_limit_exceeded(gpointer data,
241 stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
242 int32_t *limit_exceeded = (int32_t *)user_data;
244 if (rstn_data->limit_exceeded != 0)
245 *limit_exceeded = rstn_data->limit_exceeded;
248 static void __app_update_counter(classid_bytes_context_s *context,
251 stc_app_value_s *lookup_app;
252 stc_rstn_value_s *lookup_rstn;
253 GHashTable *apps = stc_monitor_get_system_apps();
254 GHashTable *rstns = stc_monitor_get_system_rstns();
259 lookup_app = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
261 stc_monitor_app_update_counter(lookup_app, context);
266 lookup_rstn = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
268 int32_t limit_exceeded = 0;
269 g_slist_foreach(lookup_rstn->rules,
270 __check_rstn_limit_exceeded, &limit_exceeded);
272 if (limit_exceeded != 0)
277 void stc_monitor_app_update_counter(stc_app_value_s *value,
278 classid_bytes_context_s *context)
280 switch (context->counter->iotype) {
281 case NFACCT_COUNTER_IN:
282 value->data_usage.in_bytes += context->bytes;
283 value->counter.in_bytes = context->bytes;
284 stc_monitor_set_apps_updated(TRUE);
287 case NFACCT_COUNTER_OUT:
288 value->data_usage.out_bytes += context->bytes;
289 value->counter.out_bytes = context->bytes;
290 stc_monitor_set_apps_updated(TRUE);
294 STC_LOGE("Unknown iotype");
298 void stc_monitor_app_update_iface_counter(classid_bytes_context_s *context)
300 switch (context->counter->iftype) {
301 case STC_IFACE_DATACALL:
302 __app_update_counter(context, STC_TOTAL_DATACALL_CLASSID);
305 __app_update_counter(context, STC_TOTAL_WIFI_CLASSID);
306 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
308 case STC_IFACE_BLUETOOTH:
309 __app_update_counter(context, STC_TOTAL_BLUETOOTH_CLASSID);
310 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
313 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
316 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
323 gboolean stc_monitor_app_flush_stats_to_db(gpointer user_data)
325 time_t current_time = 0;
326 stc_s *stc = stc_get_manager();
327 GHashTable *apps = stc_monitor_get_system_apps();
328 gboolean apps_updated = stc_monitor_get_apps_updated();
330 if (stc && stc->carg)
331 current_time = stc->carg->last_run_time;
333 if (apps_updated == FALSE)
334 return G_SOURCE_REMOVE;
336 stc_monitor_set_apps_updated(FALSE);
339 g_hash_table_foreach(apps,
340 __app_update_statistics,
343 STC_LOGI("Flushed app stats to database");
344 return G_SOURCE_REMOVE;
347 API stc_error_e stc_monitor_app_add(uint32_t classid,
350 const stc_app_value_s value)
352 stc_app_value_s *app_value;
353 stc_app_value_s *lookup_value;
355 GHashTable *apps = stc_monitor_get_system_apps();
356 GSList *conn_list = stc_get_connection_list();
359 return STC_ERROR_NO_DATA;
361 if (classid == STC_UNKNOWN_CLASSID)
362 classid = get_classid_by_app_id(app_id, TRUE);
364 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
367 STC_LOGE("Already exists [\033[1;36m%d\033[0;m:"
368 "\033[0;32m%s\033[0;m]", classid, app_id);
369 return STC_ERROR_NONE;
372 app_value = MALLOC0(stc_app_value_s, 1);
375 STC_LOGE("Value allocation failed");
376 return STC_ERROR_OUT_OF_MEMORY;
379 /* create cgroup and update classid */
380 app_value->classid = classid;
382 app_value->app_id = g_strdup(app_id);
383 app_value->pkg_id = g_strdup(pkg_id);
385 app_value->type = value.type;
386 app_value->state = value.state;
387 app_value->data_usage.in_bytes = value.data_usage.in_bytes;
388 app_value->data_usage.out_bytes = value.data_usage.out_bytes;
389 g_strlcpy(app_value->mac, value.mac, MAC_ADDRESS_LEN);
391 app_value->processes = g_hash_table_new_full(g_direct_hash,
392 g_direct_equal, NULL, NULL);
394 /* update classid for tethering station based on its mac address */
395 if (g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX) &&
396 classid != STC_TETHERING_APP_CLASSID)
397 stc_plugin_tether_set_station_classid(app_value->mac, classid);
399 g_hash_table_insert(apps, GUINT_TO_POINTER(classid), app_value);
401 for (; conn_list != NULL; conn_list = conn_list->next) {
402 stc_connection_s *conn = conn_list->data;
403 /* add nfacct rule for this classid */
404 stc_monitor_app_add_monitor(GUINT_TO_POINTER(classid),
407 if (app_value->state == STC_APP_STATE_FOREGROUND)
408 stc_monitor_app_add_accept(GUINT_TO_POINTER(classid),
412 stc_monitor_rstn_add_for_app(classid);
415 __print_app(GUINT_TO_POINTER(classid), app_value, NULL);
416 STC_LOGD("\033[1;32mApplication added\033[0;m "
417 "[\033[1;36m%d\033[0;m]", classid);
420 return STC_ERROR_NONE;
423 void stc_monitor_app_add_by_iface(const char *ifname)
425 stc_app_value_s app_value;
430 memset(&app_value, 0, sizeof(stc_app_value_s));
432 app_value.type = STC_APP_TYPE_NONE;
433 app_value.processes = NULL;
434 app_value.counter.in_bytes = 0;
435 app_value.counter.out_bytes = 0;
437 stc_monitor_app_add(STC_UNKNOWN_CLASSID, ifname, ifname, app_value);
440 void stc_monitor_app_add_monitor(gpointer key,
441 gpointer value, gpointer data)
443 stc_app_value_s *app_value = (stc_app_value_s *)value;
444 stc_connection_s *connection = (stc_connection_s *)data;
445 stc_s *stc = stc_get_manager();
447 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
448 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
449 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
452 if (stc && connection && connection->ifname) {
453 struct nfacct_rule counter;
456 stc->carg = MALLOC0(counter_arg_s, 1);
457 if (stc->carg == NULL)
460 stc->carg->sock = stc_monitor_get_contr_sock();
463 memset(&counter, 0, sizeof(struct nfacct_rule));
465 counter.carg = stc->carg;
466 counter.classid = app_value->classid;
467 counter.app_state = app_value->state;
468 counter.intend = NFACCT_COUNTER;
470 if (connection->tether_state == TRUE &&
471 connection->tether_iface.ifname != NULL &&
472 app_value->classid == STC_TETHERING_APP_CLASSID) {
473 counter.iftype = connection->tether_iface.type;
474 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
476 counter.iftype = connection->type;
477 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
480 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
481 app_value->classid != STC_TETHERING_APP_CLASSID) {
482 __add_app_monitor_for_tethering(key, value, data);
483 } else if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
484 stc_monitor_ipt_add_in(&counter);
485 stc_monitor_ipt_add_out(&counter);
486 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
487 stc_monitor_ip6t_add_in(&counter);
488 stc_monitor_ip6t_add_out(&counter);
490 stc_monitor_ipt_add_in(&counter);
491 stc_monitor_ipt_add_out(&counter);
492 stc_monitor_ip6t_add_in(&counter);
493 stc_monitor_ip6t_add_out(&counter);
498 void stc_monitor_app_add_by_connection(stc_connection_s *conn)
500 GHashTable *apps = stc_monitor_get_system_apps();
505 g_hash_table_foreach(apps, stc_monitor_app_add_monitor, conn);
506 g_hash_table_foreach(apps, stc_monitor_app_add_accept, conn);
509 void stc_monitor_app_add_accept(gpointer key,
510 gpointer value, gpointer data)
512 stc_app_value_s *app_value = (stc_app_value_s *)value;
513 stc_connection_s *connection = (stc_connection_s *)data;
514 stc_s *stc = stc_get_manager();
516 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
517 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
518 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
521 if (app_value->state != STC_APP_STATE_FOREGROUND)
524 if (stc && connection && connection->ifname) {
525 struct nfacct_rule counter;
528 stc->carg = MALLOC0(counter_arg_s, 1);
529 if (stc->carg == NULL)
532 stc->carg->sock = stc_monitor_get_contr_sock();
535 memset(&counter, 0, sizeof(struct nfacct_rule));
537 counter.carg = stc->carg;
538 counter.classid = app_value->classid;
539 counter.app_state = app_value->state;
540 counter.intend = NFACCT_ALLOW;
542 counter.iftype = connection->type;
543 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
545 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
546 stc_monitor_ipt_add_in(&counter);
547 stc_monitor_ipt_add_out(&counter);
548 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
549 stc_monitor_ip6t_add_in(&counter);
550 stc_monitor_ip6t_add_out(&counter);
552 stc_monitor_ipt_add_in(&counter);
553 stc_monitor_ipt_add_out(&counter);
554 stc_monitor_ip6t_add_in(&counter);
555 stc_monitor_ip6t_add_out(&counter);
560 API stc_error_e stc_monitor_app_remove(uint32_t classid, const char *app_id)
562 stc_app_value_s *app_lookup;
563 GHashTable *apps = stc_monitor_get_system_apps();
564 GSList *conn_list = stc_get_connection_list();
567 return STC_ERROR_NO_DATA;
569 classid = get_classid_by_app_id(app_id, FALSE);
571 app_lookup = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
574 STC_LOGD("Application not found [\033[1;36m%d\033[0;m]", classid);
575 return STC_ERROR_FAIL;
578 for (; conn_list != NULL; conn_list = conn_list->next) {
579 stc_connection_s *conn = conn_list->data;
580 /* remove nfacct rule for this classid */
581 stc_monitor_app_remove_monitor(GUINT_TO_POINTER(classid),
584 if (app_lookup->state == STC_APP_STATE_FOREGROUND)
585 stc_monitor_app_remove_accept(GUINT_TO_POINTER(classid),
589 /* remove ristrictions if any */
590 stc_monitor_rstn_remove_for_app(classid);
593 __print_app(GUINT_TO_POINTER(classid), app_lookup, NULL);
595 /* remove app_key from the stc-manager */
596 g_hash_table_remove(apps, GUINT_TO_POINTER(classid));
598 return STC_ERROR_NONE;
601 void stc_monitor_app_remove_monitor(gpointer key,
602 gpointer value, gpointer data)
604 stc_app_value_s *app_value = (stc_app_value_s *)value;
605 stc_connection_s *connection = (stc_connection_s *)data;
606 stc_s *stc = stc_get_manager();
608 if (stc && connection && connection->ifname) {
609 struct nfacct_rule counter;
612 stc->carg = MALLOC0(counter_arg_s, 1);
613 if (stc->carg == NULL)
616 stc->carg->sock = stc_monitor_get_contr_sock();
619 memset(&counter, 0, sizeof(struct nfacct_rule));
621 counter.carg = stc->carg;
622 counter.classid = app_value->classid;
623 counter.app_state = app_value->state;
624 counter.intend = NFACCT_COUNTER;
626 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
627 app_value->classid != STC_TETHERING_APP_CLASSID) {
628 __remove_app_monitor_for_tethering(key, value, data);
630 } else if (connection->tether_state == FALSE &&
631 connection->tether_iface.ifname != NULL &&
632 app_value->classid == STC_TETHERING_APP_CLASSID) {
633 counter.iftype = connection->tether_iface.type;
634 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
636 counter.iftype = connection->type;
637 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
640 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
641 stc_monitor_ipt_del_in(&counter);
642 stc_monitor_ipt_del_out(&counter);
643 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
644 stc_monitor_ip6t_del_in(&counter);
645 stc_monitor_ip6t_del_out(&counter);
647 stc_monitor_ipt_del_in(&counter);
648 stc_monitor_ipt_del_out(&counter);
649 stc_monitor_ip6t_del_in(&counter);
650 stc_monitor_ip6t_del_out(&counter);
657 void stc_monitor_app_remove_by_connection(stc_connection_s *conn)
659 GHashTable *apps = stc_monitor_get_system_apps();
664 g_hash_table_foreach(apps, stc_monitor_app_remove_monitor, conn);
665 g_hash_table_foreach(apps, stc_monitor_app_remove_accept, conn);
668 void stc_monitor_app_remove_accept(gpointer key,
669 gpointer value, gpointer data)
671 stc_app_value_s *app_value = (stc_app_value_s *)value;
672 stc_connection_s *connection = (stc_connection_s *)data;
673 stc_s *stc = stc_get_manager();
675 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
676 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
677 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
680 if (app_value->state != STC_APP_STATE_FOREGROUND)
683 if (stc && connection && connection->ifname) {
684 struct nfacct_rule counter;
687 stc->carg = MALLOC0(counter_arg_s, 1);
688 if (stc->carg == NULL)
691 stc->carg->sock = stc_monitor_get_contr_sock();
694 memset(&counter, 0, sizeof(struct nfacct_rule));
696 counter.carg = stc->carg;
697 counter.classid = app_value->classid;
698 counter.app_state = app_value->state;
699 counter.intend = NFACCT_ALLOW;
701 counter.iftype = connection->type;
702 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
704 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
705 stc_monitor_ipt_del_in(&counter);
706 stc_monitor_ipt_del_out(&counter);
707 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
708 stc_monitor_ip6t_del_in(&counter);
709 stc_monitor_ip6t_del_out(&counter);
711 stc_monitor_ipt_del_in(&counter);
712 stc_monitor_ipt_del_out(&counter);
713 stc_monitor_ip6t_del_in(&counter);
714 stc_monitor_ip6t_del_out(&counter);
721 API gboolean stc_monitor_app_lookup(uint32_t classid)
723 stc_app_value_s *lookup_value;
725 GHashTable *apps = stc_monitor_get_system_apps();
730 if (classid == STC_UNKNOWN_CLASSID)
733 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
740 GHashTable *stc_monitor_apps_init(void)
742 return g_hash_table_new_full(g_direct_hash, g_direct_equal,
743 NULL, __app_value_destroy);