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-plugin-monitor.h"
21 #include "stc-plugin-monitor-app.h"
22 #include "stc-plugin-monitor-rstn.h"
23 #include "stc-plugin-monitor-proc.h"
24 #include "stc-plugin-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 API stc_error_e stc_plugin_monitor_app_add(uint32_t classid,
280 const stc_app_value_s value)
282 stc_app_value_s *app_value;
283 stc_app_value_s *lookup_value;
285 GHashTable *apps = stc_monitor_get_system_apps();
286 GSList *conn_list = stc_get_connection_list();
289 return STC_ERROR_NO_DATA;
291 if (classid == STC_UNKNOWN_CLASSID)
292 classid = get_classid_by_app_id(app_id, TRUE);
294 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
297 STC_LOGE("Already exists [\033[1;36m%d\033[0;m:"
298 "\033[0;32m%s\033[0;m]", classid, app_id);
299 return STC_ERROR_NONE;
302 app_value = MALLOC0(stc_app_value_s, 1);
305 STC_LOGE("Value allocation failed");
306 return STC_ERROR_OUT_OF_MEMORY;
309 /* create cgroup and update classid */
310 app_value->classid = classid;
312 app_value->app_id = g_strdup(app_id);
313 app_value->pkg_id = g_strdup(pkg_id);
315 app_value->type = value.type;
316 app_value->state = value.state;
317 app_value->data_usage.in_bytes = value.data_usage.in_bytes;
318 app_value->data_usage.out_bytes = value.data_usage.out_bytes;
319 g_strlcpy(app_value->mac, value.mac, MAC_ADDRESS_LEN);
321 app_value->processes = g_hash_table_new_full(g_direct_hash,
322 g_direct_equal, NULL, NULL);
324 /* update classid for tethering station based on its mac address */
325 if (g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX) &&
326 classid != STC_TETHERING_APP_CLASSID)
327 stc_plugin_tether_set_station_classid(app_value->mac, classid);
329 g_hash_table_insert(apps, GUINT_TO_POINTER(classid), app_value);
331 for (; conn_list != NULL; conn_list = conn_list->next) {
332 stc_connection_s *conn = conn_list->data;
333 /* add nfacct rule for this classid */
334 stc_monitor_app_add_monitor(GUINT_TO_POINTER(classid),
337 if (app_value->state == STC_APP_STATE_FOREGROUND)
338 stc_monitor_app_add_accept(GUINT_TO_POINTER(classid),
342 stc_monitor_rstn_add_for_app(classid);
345 __print_app(GUINT_TO_POINTER(classid), app_value, NULL);
346 STC_LOGD("\033[1;32mApplication added\033[0;m "
347 "[\033[1;36m%d\033[0;m]", classid);
350 return STC_ERROR_NONE;
353 API stc_error_e stc_plugin_monitor_app_remove(uint32_t classid,
356 stc_app_value_s *app_lookup;
357 GHashTable *apps = stc_monitor_get_system_apps();
358 GSList *conn_list = stc_get_connection_list();
361 return STC_ERROR_NO_DATA;
363 classid = get_classid_by_app_id(app_id, FALSE);
365 app_lookup = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
368 STC_LOGD("Application not found [\033[1;36m%d\033[0;m]", classid);
369 return STC_ERROR_FAIL;
372 for (; conn_list != NULL; conn_list = conn_list->next) {
373 stc_connection_s *conn = conn_list->data;
374 /* remove nfacct rule for this classid */
375 stc_monitor_app_remove_monitor(GUINT_TO_POINTER(classid),
378 if (app_lookup->state == STC_APP_STATE_FOREGROUND)
379 stc_monitor_app_remove_accept(GUINT_TO_POINTER(classid),
383 /* remove ristrictions if any */
384 stc_monitor_rstn_remove_for_app(classid);
387 __print_app(GUINT_TO_POINTER(classid), app_lookup, NULL);
389 /* remove app_key from the stc-manager */
390 g_hash_table_remove(apps, GUINT_TO_POINTER(classid));
392 return STC_ERROR_NONE;
395 API gboolean stc_plugin_monitor_app_lookup(uint32_t classid)
397 stc_app_value_s *lookup_value;
399 GHashTable *apps = stc_monitor_get_system_apps();
404 if (classid == STC_UNKNOWN_CLASSID)
407 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
414 void stc_monitor_app_update_counter(stc_app_value_s *value,
415 classid_bytes_context_s *context)
417 switch (context->counter->iotype) {
418 case NFACCT_COUNTER_IN:
419 value->data_usage.in_bytes += context->bytes;
420 value->counter.in_bytes = context->bytes;
421 stc_monitor_set_apps_updated(TRUE);
424 case NFACCT_COUNTER_OUT:
425 value->data_usage.out_bytes += context->bytes;
426 value->counter.out_bytes = context->bytes;
427 stc_monitor_set_apps_updated(TRUE);
431 STC_LOGE("Unknown iotype");
435 void stc_monitor_app_update_iface_counter(classid_bytes_context_s *context)
437 switch (context->counter->iftype) {
438 case STC_IFACE_DATACALL:
439 __app_update_counter(context, STC_TOTAL_DATACALL_CLASSID);
442 __app_update_counter(context, STC_TOTAL_WIFI_CLASSID);
443 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
445 case STC_IFACE_BLUETOOTH:
446 __app_update_counter(context, STC_TOTAL_BLUETOOTH_CLASSID);
447 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
450 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
453 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
460 gboolean stc_monitor_app_flush_stats_to_db(gpointer user_data)
462 time_t current_time = 0;
463 stc_s *stc = stc_get_manager();
464 GHashTable *apps = stc_monitor_get_system_apps();
465 gboolean apps_updated = stc_monitor_get_apps_updated();
467 if (stc && stc->carg)
468 current_time = stc->carg->last_run_time;
470 if (apps_updated == FALSE)
471 return G_SOURCE_REMOVE;
473 stc_monitor_set_apps_updated(FALSE);
476 g_hash_table_foreach(apps,
477 __app_update_statistics,
480 STC_LOGI("Flushed app stats to database");
481 return G_SOURCE_REMOVE;
484 void stc_monitor_app_add_by_iface(const char *ifname)
486 stc_app_value_s app_value;
491 memset(&app_value, 0, sizeof(stc_app_value_s));
493 app_value.type = STC_APP_TYPE_NONE;
494 app_value.processes = NULL;
495 app_value.counter.in_bytes = 0;
496 app_value.counter.out_bytes = 0;
498 stc_plugin_monitor_app_add(STC_UNKNOWN_CLASSID, ifname, ifname, app_value);
501 void stc_monitor_app_add_monitor(gpointer key,
502 gpointer value, gpointer data)
504 stc_app_value_s *app_value = (stc_app_value_s *)value;
505 stc_connection_s *connection = (stc_connection_s *)data;
506 stc_s *stc = stc_get_manager();
508 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
509 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
510 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
513 if (stc && connection && connection->ifname) {
514 struct nfacct_rule counter;
517 stc->carg = MALLOC0(counter_arg_s, 1);
518 if (stc->carg == NULL)
521 stc->carg->sock = stc_monitor_get_contr_sock();
524 memset(&counter, 0, sizeof(struct nfacct_rule));
526 counter.carg = stc->carg;
527 counter.classid = app_value->classid;
528 counter.app_state = app_value->state;
529 counter.intend = NFACCT_COUNTER;
531 if (connection->tether_state == TRUE &&
532 connection->tether_iface.ifname != NULL &&
533 app_value->classid == STC_TETHERING_APP_CLASSID) {
534 counter.iftype = connection->tether_iface.type;
535 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
537 counter.iftype = connection->type;
538 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
541 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
542 app_value->classid != STC_TETHERING_APP_CLASSID) {
543 __add_app_monitor_for_tethering(key, value, data);
544 } else if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
545 stc_monitor_ipt_add_in(&counter);
546 stc_monitor_ipt_add_out(&counter);
547 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
548 stc_monitor_ip6t_add_in(&counter);
549 stc_monitor_ip6t_add_out(&counter);
551 stc_monitor_ipt_add_in(&counter);
552 stc_monitor_ipt_add_out(&counter);
553 stc_monitor_ip6t_add_in(&counter);
554 stc_monitor_ip6t_add_out(&counter);
559 void stc_monitor_app_add_by_connection(stc_connection_s *conn)
561 GHashTable *apps = stc_monitor_get_system_apps();
566 g_hash_table_foreach(apps, stc_monitor_app_add_monitor, conn);
567 g_hash_table_foreach(apps, stc_monitor_app_add_accept, conn);
570 void stc_monitor_app_add_accept(gpointer key,
571 gpointer value, gpointer data)
573 stc_app_value_s *app_value = (stc_app_value_s *)value;
574 stc_connection_s *connection = (stc_connection_s *)data;
575 stc_s *stc = stc_get_manager();
577 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
578 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
579 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
582 if (app_value->state != STC_APP_STATE_FOREGROUND)
585 if (stc && connection && connection->ifname) {
586 struct nfacct_rule counter;
589 stc->carg = MALLOC0(counter_arg_s, 1);
590 if (stc->carg == NULL)
593 stc->carg->sock = stc_monitor_get_contr_sock();
596 memset(&counter, 0, sizeof(struct nfacct_rule));
598 counter.carg = stc->carg;
599 counter.classid = app_value->classid;
600 counter.app_state = app_value->state;
601 counter.intend = NFACCT_ALLOW;
603 counter.iftype = connection->type;
604 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
606 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
607 stc_monitor_ipt_add_in(&counter);
608 stc_monitor_ipt_add_out(&counter);
609 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
610 stc_monitor_ip6t_add_in(&counter);
611 stc_monitor_ip6t_add_out(&counter);
613 stc_monitor_ipt_add_in(&counter);
614 stc_monitor_ipt_add_out(&counter);
615 stc_monitor_ip6t_add_in(&counter);
616 stc_monitor_ip6t_add_out(&counter);
621 void stc_monitor_app_remove_monitor(gpointer key,
622 gpointer value, gpointer data)
624 stc_app_value_s *app_value = (stc_app_value_s *)value;
625 stc_connection_s *connection = (stc_connection_s *)data;
626 stc_s *stc = stc_get_manager();
628 if (stc && connection && connection->ifname) {
629 struct nfacct_rule counter;
632 stc->carg = MALLOC0(counter_arg_s, 1);
633 if (stc->carg == NULL)
636 stc->carg->sock = stc_monitor_get_contr_sock();
639 memset(&counter, 0, sizeof(struct nfacct_rule));
641 counter.carg = stc->carg;
642 counter.classid = app_value->classid;
643 counter.app_state = app_value->state;
644 counter.intend = NFACCT_COUNTER;
646 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
647 app_value->classid != STC_TETHERING_APP_CLASSID) {
648 __remove_app_monitor_for_tethering(key, value, data);
650 } else if (connection->tether_state == FALSE &&
651 connection->tether_iface.ifname != NULL &&
652 app_value->classid == STC_TETHERING_APP_CLASSID) {
653 counter.iftype = connection->tether_iface.type;
654 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
656 counter.iftype = connection->type;
657 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
660 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
661 stc_monitor_ipt_del_in(&counter);
662 stc_monitor_ipt_del_out(&counter);
663 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
664 stc_monitor_ip6t_del_in(&counter);
665 stc_monitor_ip6t_del_out(&counter);
667 stc_monitor_ipt_del_in(&counter);
668 stc_monitor_ipt_del_out(&counter);
669 stc_monitor_ip6t_del_in(&counter);
670 stc_monitor_ip6t_del_out(&counter);
677 void stc_monitor_app_remove_by_connection(stc_connection_s *conn)
679 GHashTable *apps = stc_monitor_get_system_apps();
684 g_hash_table_foreach(apps, stc_monitor_app_remove_monitor, conn);
685 g_hash_table_foreach(apps, stc_monitor_app_remove_accept, conn);
688 void stc_monitor_app_remove_accept(gpointer key,
689 gpointer value, gpointer data)
691 stc_app_value_s *app_value = (stc_app_value_s *)value;
692 stc_connection_s *connection = (stc_connection_s *)data;
693 stc_s *stc = stc_get_manager();
695 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
696 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
697 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
700 if (app_value->state != STC_APP_STATE_FOREGROUND)
703 if (stc && connection && connection->ifname) {
704 struct nfacct_rule counter;
707 stc->carg = MALLOC0(counter_arg_s, 1);
708 if (stc->carg == NULL)
711 stc->carg->sock = stc_monitor_get_contr_sock();
714 memset(&counter, 0, sizeof(struct nfacct_rule));
716 counter.carg = stc->carg;
717 counter.classid = app_value->classid;
718 counter.app_state = app_value->state;
719 counter.intend = NFACCT_ALLOW;
721 counter.iftype = connection->type;
722 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
724 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
725 stc_monitor_ipt_del_in(&counter);
726 stc_monitor_ipt_del_out(&counter);
727 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
728 stc_monitor_ip6t_del_in(&counter);
729 stc_monitor_ip6t_del_out(&counter);
731 stc_monitor_ipt_del_in(&counter);
732 stc_monitor_ipt_del_out(&counter);
733 stc_monitor_ip6t_del_in(&counter);
734 stc_monitor_ip6t_del_out(&counter);
741 GHashTable *stc_monitor_apps_init(void)
743 return g_hash_table_new_full(g_direct_hash, g_direct_equal,
744 NULL, __app_value_destroy);