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));
59 /* Do not update statistics for Tethering
60 * if tethering is in-active found */
61 if (conn && conn->tether_state == FALSE &&
62 !strcmp(app_value->app_id, STC_TOTAL_TETHERING))
65 /* Do not update statistics for Wi-Fi
66 * if tethering is active on wlan0 iface */
67 if (conn && conn->tether_state &&
68 conn->tether_iface.type == STC_IFACE_WIFI &&
69 !strcmp(app_value->app_id, STC_TOTAL_WIFI))
72 stat_key.classid = app_value->classid;
74 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
75 conn->tether_state == TRUE)
76 stat_key.iftype = conn->tether_iface.type;
77 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
78 stat_key.iftype = conn->tether_iface.type;
80 stat_key.iftype = conn->type;
82 if (STC_IFACE_DATACALL == stat_key.iftype)
83 stat_key.subscriber_id = g_strdup(conn->subscriber_id);
85 stat_key.subscriber_id = g_strdup(SUBSCRIBERID_NONE);
87 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
88 conn->tether_state == TRUE)
89 g_strlcpy(stat_key.ifname, conn->tether_iface.ifname,
91 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
92 g_strlcpy(stat_key.ifname, conn->tether_iface.ifname,
95 g_strlcpy(stat_key.ifname, conn->ifname,
98 stat.app_id = g_strdup(app_value->app_id);
99 stat.snd_count = app_value->counter.out_bytes;
100 stat.rcv_count = app_value->counter.in_bytes;
101 stat.is_roaming = conn->roaming;
103 if (strstr(stat.app_id, "_BACKGROUND")) {
104 stat.ground = STC_APP_STATE_BACKGROUND;
106 if (strstr(stat.app_id, "TOTAL_"))
107 stat.ground = STC_APP_STATE_UNKNOWN;
109 stat.ground = STC_APP_STATE_FOREGROUND;
112 table_statistics_insert(&stat_key, &stat, *touch_time);
114 app_value->counter.out_bytes = 0;
115 app_value->counter.in_bytes = 0;
118 FREE(stat_key.subscriber_id);
124 static gboolean __add_app_monitor_for_tethering(gpointer key,
125 gpointer value, gpointer data)
127 stc_app_value_s *app_value = (stc_app_value_s *)value;
128 stc_connection_s *connection = (stc_connection_s *)data;
129 stc_s *stc = stc_get_manager();
130 struct nfacct_rule counter;
134 STC_LOGI("Add appid(%s) classid(%d)", app_value->app_id,
137 if (stc == NULL || connection == NULL)
141 stc->carg = MALLOC0(counter_arg_s, 1);
142 if (stc->carg == NULL)
145 stc->carg->sock = stc_monitor_get_contr_sock();
148 memset(&counter, 0, sizeof(struct nfacct_rule));
150 counter.carg = stc->carg;
151 counter.classid = app_value->classid;
152 counter.intend = NFACCT_TETH_COUNTER;
154 if (connection->tether_state != TRUE ||
155 connection->tether_iface.ifname == NULL)
158 counter.iftype = connection->tether_iface.type;
159 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
161 /* get the ip address of the station based on its mac address */
162 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
163 if (ret != STC_ERROR_NONE)
166 /* tethering iptables rule */
167 stc_monitor_tether_add_in(&counter, ipaddr);
168 stc_monitor_tether_add_out(&counter, ipaddr);
174 static gboolean __remove_app_monitor_for_tethering(gpointer key,
175 gpointer value, gpointer data)
177 stc_app_value_s *app_value = (stc_app_value_s *)value;
178 stc_connection_s *connection = (stc_connection_s *)data;
179 stc_s *stc = stc_get_manager();
180 struct nfacct_rule counter;
184 STC_LOGI("Remove appid(%s) classid(%d)", app_value->app_id,
187 if (stc == NULL || connection == NULL)
191 stc->carg = MALLOC0(counter_arg_s, 1);
192 if (stc->carg == NULL)
195 stc->carg->sock = stc_monitor_get_contr_sock();
198 memset(&counter, 0, sizeof(struct nfacct_rule));
200 counter.carg = stc->carg;
201 counter.classid = app_value->classid;
202 counter.intend = NFACCT_TETH_COUNTER;
204 if (connection->tether_state != TRUE ||
205 connection->tether_iface.ifname == NULL)
208 counter.iftype = connection->tether_iface.type;
209 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
211 /* get the ip address of the station based on its mac address */
212 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
213 if (ret != STC_ERROR_NONE)
216 stc_monitor_tether_del_in(&counter, ipaddr);
217 stc_monitor_tether_del_out(&counter, ipaddr);
223 static void __app_value_destroy(gpointer data)
225 stc_app_value_s *app_value = (stc_app_value_s *)data;
227 FREE(app_value->pkg_id);
228 FREE(app_value->app_id);
229 g_hash_table_destroy(app_value->processes);
230 app_value->processes = NULL;
235 static void __check_rstn_limit_exceeded(gpointer data,
238 stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
239 int32_t *limit_exceeded = (int32_t *)user_data;
241 if (rstn_data->limit_exceeded != 0)
242 *limit_exceeded = rstn_data->limit_exceeded;
245 static void __app_update_counter(classid_bytes_context_s *context,
248 stc_app_value_s *lookup_app;
249 stc_rstn_value_s *lookup_rstn;
250 GHashTable *apps = stc_monitor_get_system_apps();
251 GHashTable *rstns = stc_monitor_get_system_rstns();
256 lookup_app = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
258 stc_monitor_app_update_counter(lookup_app, context);
263 lookup_rstn = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
265 int32_t limit_exceeded = 0;
266 g_slist_foreach(lookup_rstn->rules,
267 __check_rstn_limit_exceeded, &limit_exceeded);
269 if (limit_exceeded != 0)
274 void stc_monitor_app_update_counter(stc_app_value_s *value,
275 classid_bytes_context_s *context)
277 switch (context->counter->iotype) {
278 case NFACCT_COUNTER_IN:
279 value->data_usage.in_bytes += context->bytes;
280 value->counter.in_bytes = context->bytes;
281 stc_monitor_set_apps_updated(TRUE);
284 case NFACCT_COUNTER_OUT:
285 value->data_usage.out_bytes += context->bytes;
286 value->counter.out_bytes = context->bytes;
287 stc_monitor_set_apps_updated(TRUE);
291 STC_LOGE("Unknown iotype");
295 void stc_monitor_app_update_iface_counter(classid_bytes_context_s *context)
297 switch (context->counter->iftype) {
298 case STC_IFACE_DATACALL:
299 __app_update_counter(context, STC_TOTAL_DATACALL_CLASSID);
302 __app_update_counter(context, STC_TOTAL_WIFI_CLASSID);
303 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
305 case STC_IFACE_BLUETOOTH:
306 __app_update_counter(context, STC_TOTAL_BLUETOOTH_CLASSID);
307 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
310 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
313 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
320 gboolean stc_monitor_app_flush_stats_to_db(gpointer user_data)
322 time_t current_time = 0;
323 stc_s *stc = stc_get_manager();
324 GHashTable *apps = stc_monitor_get_system_apps();
325 gboolean apps_updated = stc_monitor_get_apps_updated();
327 if (stc && stc->carg)
328 current_time = stc->carg->last_run_time;
330 if (apps_updated == FALSE)
331 return G_SOURCE_REMOVE;
333 stc_monitor_set_apps_updated(FALSE);
336 g_hash_table_foreach(apps,
337 __app_update_statistics,
340 STC_LOGI("Flushed app stats to database");
341 return G_SOURCE_REMOVE;
344 API stc_error_e stc_monitor_app_add(uint32_t classid,
347 const stc_app_value_s value)
349 stc_app_value_s *app_value;
350 stc_app_value_s *lookup_value;
352 GHashTable *apps = stc_monitor_get_system_apps();
353 GSList *conn_list = stc_get_connection_list();
356 return STC_ERROR_NO_DATA;
358 if (classid == STC_UNKNOWN_CLASSID)
359 classid = get_classid_by_app_id(app_id, TRUE);
361 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
364 STC_LOGE("Already exists [\033[1;36m%d\033[0;m:"
365 "\033[0;32m%s\033[0;m]", classid, app_id);
366 return STC_ERROR_NONE;
369 app_value = MALLOC0(stc_app_value_s, 1);
372 STC_LOGE("Value allocation failed");
373 return STC_ERROR_OUT_OF_MEMORY;
376 /* create cgroup and update classid */
377 app_value->classid = classid;
379 app_value->app_id = g_strdup(app_id);
380 app_value->pkg_id = g_strdup(pkg_id);
382 app_value->type = value.type;
383 app_value->state = value.state;
384 app_value->data_usage.in_bytes = value.data_usage.in_bytes;
385 app_value->data_usage.out_bytes = value.data_usage.out_bytes;
386 g_strlcpy(app_value->mac, value.mac, MAC_ADDRESS_LEN);
388 app_value->processes = g_hash_table_new_full(g_direct_hash,
389 g_direct_equal, NULL, NULL);
391 /* update classid for tethering station based on its mac address */
392 if (g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX) &&
393 classid != STC_TETHERING_APP_CLASSID)
394 stc_plugin_tether_set_station_classid(app_value->mac, classid);
396 g_hash_table_insert(apps, GUINT_TO_POINTER(classid), app_value);
398 for (; conn_list != NULL; conn_list = conn_list->next) {
399 stc_connection_s *conn = conn_list->data;
400 /* add nfacct rule for this classid */
401 stc_monitor_app_add_monitor(GUINT_TO_POINTER(classid),
404 if (app_value->state == STC_APP_STATE_FOREGROUND)
405 stc_monitor_app_add_accept(GUINT_TO_POINTER(classid),
409 stc_monitor_rstn_add_for_app(classid);
412 __print_app(GUINT_TO_POINTER(classid), app_value, NULL);
413 STC_LOGD("\033[1;32mApplication added\033[0;m "
414 "[\033[1;36m%d\033[0;m]", classid);
417 return STC_ERROR_NONE;
420 void stc_monitor_app_add_by_iface(const char *ifname)
422 stc_app_value_s app_value;
427 memset(&app_value, 0, sizeof(stc_app_value_s));
429 app_value.type = STC_APP_TYPE_NONE;
430 app_value.processes = NULL;
431 app_value.counter.in_bytes = 0;
432 app_value.counter.out_bytes = 0;
434 stc_monitor_app_add(STC_UNKNOWN_CLASSID, ifname, ifname, app_value);
437 void stc_monitor_app_add_monitor(gpointer key,
438 gpointer value, gpointer data)
440 stc_app_value_s *app_value = (stc_app_value_s *)value;
441 stc_connection_s *connection = (stc_connection_s *)data;
442 stc_s *stc = stc_get_manager();
444 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
445 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
446 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
449 if (stc && connection && connection->ifname) {
450 struct nfacct_rule counter;
453 stc->carg = MALLOC0(counter_arg_s, 1);
454 if (stc->carg == NULL)
457 stc->carg->sock = stc_monitor_get_contr_sock();
460 memset(&counter, 0, sizeof(struct nfacct_rule));
462 counter.carg = stc->carg;
463 counter.classid = app_value->classid;
464 counter.app_state = app_value->state;
465 counter.intend = NFACCT_COUNTER;
467 if (connection->tether_state == TRUE &&
468 connection->tether_iface.ifname != NULL &&
469 app_value->classid == STC_TETHERING_APP_CLASSID) {
470 counter.iftype = connection->tether_iface.type;
471 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
473 counter.iftype = connection->type;
474 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
477 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
478 app_value->classid != STC_TETHERING_APP_CLASSID) {
479 __add_app_monitor_for_tethering(key, value, data);
480 } else if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
481 stc_monitor_ipt_add_in(&counter);
482 stc_monitor_ipt_add_out(&counter);
483 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
484 stc_monitor_ip6t_add_in(&counter);
485 stc_monitor_ip6t_add_out(&counter);
487 stc_monitor_ipt_add_in(&counter);
488 stc_monitor_ipt_add_out(&counter);
489 stc_monitor_ip6t_add_in(&counter);
490 stc_monitor_ip6t_add_out(&counter);
495 void stc_monitor_app_add_by_connection(stc_connection_s *conn)
497 GHashTable *apps = stc_monitor_get_system_apps();
502 g_hash_table_foreach(apps, stc_monitor_app_add_monitor, conn);
503 g_hash_table_foreach(apps, stc_monitor_app_add_accept, conn);
506 void stc_monitor_app_add_accept(gpointer key,
507 gpointer value, gpointer data)
509 stc_app_value_s *app_value = (stc_app_value_s *)value;
510 stc_connection_s *connection = (stc_connection_s *)data;
511 stc_s *stc = stc_get_manager();
513 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
514 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
515 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
518 if (app_value->state != STC_APP_STATE_FOREGROUND)
521 if (stc && connection && connection->ifname) {
522 struct nfacct_rule counter;
525 stc->carg = MALLOC0(counter_arg_s, 1);
526 if (stc->carg == NULL)
529 stc->carg->sock = stc_monitor_get_contr_sock();
532 memset(&counter, 0, sizeof(struct nfacct_rule));
534 counter.carg = stc->carg;
535 counter.classid = app_value->classid;
536 counter.app_state = app_value->state;
537 counter.intend = NFACCT_ALLOW;
539 counter.iftype = connection->type;
540 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
542 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
543 stc_monitor_ipt_add_in(&counter);
544 stc_monitor_ipt_add_out(&counter);
545 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
546 stc_monitor_ip6t_add_in(&counter);
547 stc_monitor_ip6t_add_out(&counter);
549 stc_monitor_ipt_add_in(&counter);
550 stc_monitor_ipt_add_out(&counter);
551 stc_monitor_ip6t_add_in(&counter);
552 stc_monitor_ip6t_add_out(&counter);
557 API stc_error_e stc_monitor_app_remove(uint32_t classid, const char *app_id)
559 stc_app_value_s *app_lookup;
560 GHashTable *apps = stc_monitor_get_system_apps();
561 GSList *conn_list = stc_get_connection_list();
564 return STC_ERROR_NO_DATA;
566 classid = get_classid_by_app_id(app_id, FALSE);
568 app_lookup = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
571 STC_LOGD("Application not found [\033[1;36m%d\033[0;m]", classid);
572 return STC_ERROR_FAIL;
575 for (; conn_list != NULL; conn_list = conn_list->next) {
576 stc_connection_s *conn = conn_list->data;
577 /* remove nfacct rule for this classid */
578 stc_monitor_app_remove_monitor(GUINT_TO_POINTER(classid),
581 if (app_lookup->state == STC_APP_STATE_FOREGROUND)
582 stc_monitor_app_remove_accept(GUINT_TO_POINTER(classid),
586 /* remove ristrictions if any */
587 stc_monitor_rstn_remove_for_app(classid);
590 __print_app(GUINT_TO_POINTER(classid), app_lookup, NULL);
592 /* remove app_key from the stc-manager */
593 g_hash_table_remove(apps, GUINT_TO_POINTER(classid));
595 return STC_ERROR_NONE;
598 void stc_monitor_app_remove_monitor(gpointer key,
599 gpointer value, gpointer data)
601 stc_app_value_s *app_value = (stc_app_value_s *)value;
602 stc_connection_s *connection = (stc_connection_s *)data;
603 stc_s *stc = stc_get_manager();
605 if (stc && connection && connection->ifname) {
606 struct nfacct_rule counter;
609 stc->carg = MALLOC0(counter_arg_s, 1);
610 if (stc->carg == NULL)
613 stc->carg->sock = stc_monitor_get_contr_sock();
616 memset(&counter, 0, sizeof(struct nfacct_rule));
618 counter.carg = stc->carg;
619 counter.classid = app_value->classid;
620 counter.app_state = app_value->state;
621 counter.intend = NFACCT_COUNTER;
623 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
624 app_value->classid != STC_TETHERING_APP_CLASSID) {
625 __remove_app_monitor_for_tethering(key, value, data);
627 } else if (connection->tether_state == FALSE &&
628 connection->tether_iface.ifname != NULL &&
629 app_value->classid == STC_TETHERING_APP_CLASSID) {
630 counter.iftype = connection->tether_iface.type;
631 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
633 counter.iftype = connection->type;
634 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
637 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
638 stc_monitor_ipt_del_in(&counter);
639 stc_monitor_ipt_del_out(&counter);
640 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
641 stc_monitor_ip6t_del_in(&counter);
642 stc_monitor_ip6t_del_out(&counter);
644 stc_monitor_ipt_del_in(&counter);
645 stc_monitor_ipt_del_out(&counter);
646 stc_monitor_ip6t_del_in(&counter);
647 stc_monitor_ip6t_del_out(&counter);
654 void stc_monitor_app_remove_by_connection(stc_connection_s *conn)
656 GHashTable *apps = stc_monitor_get_system_apps();
661 g_hash_table_foreach(apps, stc_monitor_app_remove_monitor, conn);
662 g_hash_table_foreach(apps, stc_monitor_app_remove_accept, conn);
665 void stc_monitor_app_remove_accept(gpointer key,
666 gpointer value, gpointer data)
668 stc_app_value_s *app_value = (stc_app_value_s *)value;
669 stc_connection_s *connection = (stc_connection_s *)data;
670 stc_s *stc = stc_get_manager();
672 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
673 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
674 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
677 if (app_value->state != STC_APP_STATE_FOREGROUND)
680 if (stc && connection && connection->ifname) {
681 struct nfacct_rule counter;
684 stc->carg = MALLOC0(counter_arg_s, 1);
685 if (stc->carg == NULL)
688 stc->carg->sock = stc_monitor_get_contr_sock();
691 memset(&counter, 0, sizeof(struct nfacct_rule));
693 counter.carg = stc->carg;
694 counter.classid = app_value->classid;
695 counter.app_state = app_value->state;
696 counter.intend = NFACCT_ALLOW;
698 counter.iftype = connection->type;
699 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
701 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
702 stc_monitor_ipt_del_in(&counter);
703 stc_monitor_ipt_del_out(&counter);
704 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
705 stc_monitor_ip6t_del_in(&counter);
706 stc_monitor_ip6t_del_out(&counter);
708 stc_monitor_ipt_del_in(&counter);
709 stc_monitor_ipt_del_out(&counter);
710 stc_monitor_ip6t_del_in(&counter);
711 stc_monitor_ip6t_del_out(&counter);
718 API gboolean stc_monitor_app_lookup(uint32_t classid)
720 stc_app_value_s *lookup_value;
722 GHashTable *apps = stc_monitor_get_system_apps();
727 if (classid == STC_UNKNOWN_CLASSID)
730 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
737 GHashTable *stc_monitor_apps_init(void)
739 return g_hash_table_new_full(g_direct_hash, g_direct_equal,
740 NULL, __app_value_destroy);