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 stc_db_classid_iftype_key stat_key;
50 stc_db_app_stats stat;
51 default_connection_s *default_connection = stc_get_default_connection();
53 memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key));
54 memset(&stat, 0 , sizeof(stc_db_app_stats));
56 /* Do not update statistics for Tethering
57 * if tethering is in-active found */
58 if (default_connection &&
59 default_connection->tether_state == FALSE &&
60 !strcmp(app_value->app_id, STC_TOTAL_TETHERING))
63 /* Do not update statistics for Wi-Fi
64 * if tethering is active on wlan0 iface */
65 if (default_connection && default_connection->tether_state &&
66 default_connection->tether_iface.type == STC_IFACE_WIFI &&
67 !strcmp(app_value->app_id, STC_TOTAL_WIFI))
70 stat_key.classid = app_value->classid;
72 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
73 default_connection->tether_state == TRUE)
74 stat_key.iftype = default_connection->tether_iface.type;
75 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
76 stat_key.iftype = default_connection->tether_iface.type;
78 stat_key.iftype = default_connection->type;
80 if (STC_IFACE_DATACALL == stat_key.iftype)
81 stat_key.subscriber_id = g_strdup(default_connection->subscriber_id);
83 stat_key.subscriber_id = g_strdup(SUBSCRIBERID_NONE);
85 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
86 default_connection->tether_state == TRUE)
87 g_strlcpy(stat_key.ifname, default_connection->tether_iface.ifname,
89 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
90 g_strlcpy(stat_key.ifname, default_connection->tether_iface.ifname,
93 g_strlcpy(stat_key.ifname, default_connection->ifname,
96 stat.app_id = g_strdup(app_value->app_id);
97 stat.snd_count = app_value->counter.out_bytes;
98 stat.rcv_count = app_value->counter.in_bytes;
99 stat.is_roaming = default_connection->roaming;
101 if (strstr(stat.app_id, "_BACKGROUND")) {
102 stat.ground = STC_APP_STATE_BACKGROUND;
104 if (strstr(stat.app_id, "TOTAL_"))
105 stat.ground = STC_APP_STATE_UNKNOWN;
107 stat.ground = STC_APP_STATE_FOREGROUND;
110 table_statistics_insert(&stat_key, &stat, *touch_time);
112 app_value->counter.out_bytes = 0;
113 app_value->counter.in_bytes = 0;
116 FREE(stat_key.subscriber_id);
121 static gboolean __add_app_monitor_for_tethering(gpointer key,
122 gpointer value, gpointer data)
124 stc_app_value_s *app_value = (stc_app_value_s *)value;
125 default_connection_s *connection = (default_connection_s *)data;
126 stc_s *stc = stc_get_manager();
127 struct nfacct_rule counter;
131 STC_LOGI("Add appid(%s) classid(%d)", app_value->app_id,
134 if (stc == NULL || connection == NULL)
138 stc->carg = MALLOC0(counter_arg_s, 1);
139 if (stc->carg == NULL)
142 stc->carg->sock = stc_monitor_get_contr_sock();
145 memset(&counter, 0, sizeof(struct nfacct_rule));
147 counter.carg = stc->carg;
148 counter.classid = app_value->classid;
149 counter.intend = NFACCT_TETH_COUNTER;
151 if (connection->tether_state != TRUE ||
152 connection->tether_iface.ifname == NULL)
155 counter.iftype = connection->tether_iface.type;
156 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
158 /* get the ip address of the station based on its mac address */
159 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
160 if (ret != STC_ERROR_NONE)
163 /* tethering iptables rule */
164 stc_monitor_tether_add_in(&counter, ipaddr);
165 stc_monitor_tether_add_out(&counter, ipaddr);
171 static gboolean __remove_app_monitor_for_tethering(gpointer key,
172 gpointer value, gpointer data)
174 stc_app_value_s *app_value = (stc_app_value_s *)value;
175 default_connection_s *connection = (default_connection_s *)data;
176 stc_s *stc = stc_get_manager();
177 struct nfacct_rule counter;
181 STC_LOGI("Remove appid(%s) classid(%d)", app_value->app_id,
184 if (stc == NULL || connection == NULL)
188 stc->carg = MALLOC0(counter_arg_s, 1);
189 if (stc->carg == NULL)
192 stc->carg->sock = stc_monitor_get_contr_sock();
195 memset(&counter, 0, sizeof(struct nfacct_rule));
197 counter.carg = stc->carg;
198 counter.classid = app_value->classid;
199 counter.intend = NFACCT_TETH_COUNTER;
201 if (connection->tether_state != TRUE ||
202 connection->tether_iface.ifname == NULL)
205 counter.iftype = connection->tether_iface.type;
206 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
208 /* get the ip address of the station based on its mac address */
209 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
210 if (ret != STC_ERROR_NONE)
213 stc_monitor_tether_del_in(&counter, ipaddr);
214 stc_monitor_tether_del_out(&counter, ipaddr);
220 static void __app_value_destroy(gpointer data)
222 stc_app_value_s *app_value = (stc_app_value_s *)data;
224 FREE(app_value->pkg_id);
225 FREE(app_value->app_id);
226 g_hash_table_destroy(app_value->processes);
227 app_value->processes = NULL;
232 static void __check_rstn_limit_exceeded(gpointer data,
235 stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
236 int32_t *limit_exceeded = (int32_t *)user_data;
238 if (rstn_data->limit_exceeded != 0)
239 *limit_exceeded = rstn_data->limit_exceeded;
242 static void __app_update_counter(classid_bytes_context_s *context,
245 stc_app_value_s *lookup_app;
246 stc_rstn_value_s *lookup_rstn;
247 GHashTable *apps = stc_monitor_get_system_apps();
248 GHashTable *rstns = stc_monitor_get_system_rstns();
253 lookup_app = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
255 stc_monitor_app_update_counter(lookup_app, context);
260 lookup_rstn = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
262 int32_t limit_exceeded = 0;
263 g_slist_foreach(lookup_rstn->rules,
264 __check_rstn_limit_exceeded, &limit_exceeded);
266 if (limit_exceeded != 0)
271 void stc_monitor_app_update_counter(stc_app_value_s *value,
272 classid_bytes_context_s *context)
274 switch (context->counter->iotype) {
275 case NFACCT_COUNTER_IN:
276 value->data_usage.in_bytes += context->bytes;
277 value->counter.in_bytes = context->bytes;
278 stc_monitor_set_apps_updated(TRUE);
281 case NFACCT_COUNTER_OUT:
282 value->data_usage.out_bytes += context->bytes;
283 value->counter.out_bytes = context->bytes;
284 stc_monitor_set_apps_updated(TRUE);
288 STC_LOGE("Unknown iotype");
292 void stc_monitor_app_update_iface_counter(classid_bytes_context_s *context)
294 switch (context->counter->iftype) {
295 case STC_IFACE_DATACALL:
296 __app_update_counter(context, STC_TOTAL_DATACALL_CLASSID);
299 __app_update_counter(context, STC_TOTAL_WIFI_CLASSID);
300 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
302 case STC_IFACE_BLUETOOTH:
303 __app_update_counter(context, STC_TOTAL_BLUETOOTH_CLASSID);
304 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
307 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
310 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
317 gboolean stc_monitor_app_flush_stats_to_db(gpointer user_data)
319 time_t current_time = 0;
320 stc_s *stc = stc_get_manager();
321 GHashTable *apps = stc_monitor_get_system_apps();
322 gboolean apps_updated = stc_monitor_get_apps_updated();
324 if (stc && stc->carg)
325 current_time = stc->carg->last_run_time;
327 if (apps_updated == FALSE)
328 return G_SOURCE_REMOVE;
330 stc_monitor_set_apps_updated(FALSE);
333 g_hash_table_foreach(apps,
334 __app_update_statistics,
337 STC_LOGI("Flushed app stats to database");
338 return G_SOURCE_REMOVE;
341 API stc_error_e stc_monitor_app_add(uint32_t classid,
344 const stc_app_value_s value)
346 stc_app_value_s *app_value;
347 stc_app_value_s *lookup_value;
349 GHashTable *apps = stc_monitor_get_system_apps();
352 return STC_ERROR_NO_DATA;
354 if (classid == STC_UNKNOWN_CLASSID)
355 classid = get_classid_by_app_id(app_id, TRUE);
357 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
360 STC_LOGE("Already exists [\033[1;36m%d\033[0;m:"
361 "\033[0;32m%s\033[0;m]", classid, app_id);
362 return STC_ERROR_NONE;
365 app_value = MALLOC0(stc_app_value_s, 1);
368 STC_LOGE("Value allocation failed");
369 return STC_ERROR_OUT_OF_MEMORY;
372 /* create cgroup and update classid */
373 app_value->classid = classid;
375 app_value->app_id = g_strdup(app_id);
376 app_value->pkg_id = g_strdup(pkg_id);
378 app_value->type = value.type;
379 app_value->state = value.state;
380 app_value->data_usage.in_bytes = value.data_usage.in_bytes;
381 app_value->data_usage.out_bytes = value.data_usage.out_bytes;
382 g_strlcpy(app_value->mac, value.mac, MAC_ADDRESS_LEN);
384 app_value->processes = g_hash_table_new_full(g_direct_hash,
385 g_direct_equal, NULL, NULL);
387 /* update classid for tethering station based on its mac address */
388 if (g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX) &&
389 classid != STC_TETHERING_APP_CLASSID)
390 stc_plugin_tether_set_station_classid(app_value->mac, classid);
392 g_hash_table_insert(apps, GUINT_TO_POINTER(classid), app_value);
394 /* add nfacct rule for this classid */
395 stc_monitor_app_add_monitor(GUINT_TO_POINTER(classid),
396 app_value, stc_get_default_connection());
398 if (app_value->state == STC_APP_STATE_FOREGROUND)
399 stc_monitor_app_add_accept(GUINT_TO_POINTER(classid),
400 app_value, stc_get_default_connection());
402 stc_monitor_rstn_add_for_app(classid);
405 __print_app(GUINT_TO_POINTER(classid), app_value, NULL);
406 STC_LOGD("\033[1;32mApplication added\033[0;m "
407 "[\033[1;36m%d\033[0;m]", classid);
410 return STC_ERROR_NONE;
413 void stc_monitor_app_add_by_iface(const char *ifname)
415 stc_app_value_s app_value;
420 memset(&app_value, 0, sizeof(stc_app_value_s));
422 app_value.type = STC_APP_TYPE_NONE;
423 app_value.processes = NULL;
424 app_value.counter.in_bytes = 0;
425 app_value.counter.out_bytes = 0;
427 stc_monitor_app_add(STC_UNKNOWN_CLASSID, ifname, ifname, app_value);
430 void stc_monitor_app_add_monitor(gpointer key,
431 gpointer value, gpointer data)
433 stc_app_value_s *app_value = (stc_app_value_s *)value;
434 default_connection_s *connection = (default_connection_s *)data;
435 stc_s *stc = stc_get_manager();
437 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
438 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
439 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
442 if (stc && connection && connection->ifname) {
443 struct nfacct_rule counter;
446 stc->carg = MALLOC0(counter_arg_s, 1);
447 if (stc->carg == NULL)
450 stc->carg->sock = stc_monitor_get_contr_sock();
453 memset(&counter, 0, sizeof(struct nfacct_rule));
455 counter.carg = stc->carg;
456 counter.classid = app_value->classid;
457 counter.app_state = app_value->state;
458 counter.intend = NFACCT_COUNTER;
460 if (connection->tether_state == TRUE &&
461 connection->tether_iface.ifname != NULL &&
462 app_value->classid == STC_TETHERING_APP_CLASSID) {
463 counter.iftype = connection->tether_iface.type;
464 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
466 counter.iftype = connection->type;
467 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
470 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
471 app_value->classid != STC_TETHERING_APP_CLASSID) {
472 __add_app_monitor_for_tethering(key, value, data);
473 } else if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
474 stc_monitor_ipt_add_in(&counter);
475 stc_monitor_ipt_add_out(&counter);
476 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
477 stc_monitor_ip6t_add_in(&counter);
478 stc_monitor_ip6t_add_out(&counter);
480 stc_monitor_ipt_add_in(&counter);
481 stc_monitor_ipt_add_out(&counter);
482 stc_monitor_ip6t_add_in(&counter);
483 stc_monitor_ip6t_add_out(&counter);
488 void stc_monitor_app_add_by_connection(default_connection_s *conn)
490 GHashTable *apps = stc_monitor_get_system_apps();
495 g_hash_table_foreach(apps, stc_monitor_app_add_monitor, conn);
498 void stc_monitor_app_add_accept(gpointer key,
499 gpointer value, gpointer data)
501 stc_app_value_s *app_value = (stc_app_value_s *)value;
502 default_connection_s *connection = (default_connection_s *)data;
503 stc_s *stc = stc_get_manager();
505 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
506 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
507 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
510 if (stc && connection && connection->ifname) {
511 struct nfacct_rule counter;
514 stc->carg = MALLOC0(counter_arg_s, 1);
515 if (stc->carg == NULL)
518 stc->carg->sock = stc_monitor_get_contr_sock();
521 memset(&counter, 0, sizeof(struct nfacct_rule));
523 counter.carg = stc->carg;
524 counter.classid = app_value->classid;
525 counter.app_state = app_value->state;
526 counter.intend = NFACCT_ALLOW;
528 counter.iftype = connection->type;
529 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
531 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
532 stc_monitor_ipt_add_in(&counter);
533 stc_monitor_ipt_add_out(&counter);
534 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
535 stc_monitor_ip6t_add_in(&counter);
536 stc_monitor_ip6t_add_out(&counter);
538 stc_monitor_ipt_add_in(&counter);
539 stc_monitor_ipt_add_out(&counter);
540 stc_monitor_ip6t_add_in(&counter);
541 stc_monitor_ip6t_add_out(&counter);
546 API stc_error_e stc_monitor_app_remove(uint32_t classid, const char *app_id)
548 stc_app_value_s *app_lookup;
549 GHashTable *apps = stc_monitor_get_system_apps();
552 return STC_ERROR_NO_DATA;
554 classid = get_classid_by_app_id(app_id, FALSE);
556 app_lookup = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
559 STC_LOGD("Application not found [\033[1;36m%d\033[0;m]", classid);
560 return STC_ERROR_FAIL;
563 /* remove nfacct rule for this classid */
564 stc_monitor_app_remove_monitor(GUINT_TO_POINTER(classid),
565 app_lookup, stc_get_default_connection());
567 /* remove ristrictions if any */
568 stc_monitor_rstn_remove_for_app(classid);
571 __print_app(GUINT_TO_POINTER(classid), app_lookup, NULL);
573 /* remove app_key from the stc-manager */
574 g_hash_table_remove(apps, GUINT_TO_POINTER(classid));
576 return STC_ERROR_NONE;
579 void stc_monitor_app_remove_monitor(gpointer key,
580 gpointer value, gpointer data)
582 stc_app_value_s *app_value = (stc_app_value_s *)value;
583 default_connection_s *connection = (default_connection_s *)data;
584 stc_s *stc = stc_get_manager();
586 if (stc && connection && connection->ifname) {
587 struct nfacct_rule counter;
590 stc->carg = MALLOC0(counter_arg_s, 1);
591 if (stc->carg == NULL)
594 stc->carg->sock = stc_monitor_get_contr_sock();
597 memset(&counter, 0, sizeof(struct nfacct_rule));
599 counter.carg = stc->carg;
600 counter.classid = app_value->classid;
601 counter.app_state = app_value->state;
602 counter.intend = NFACCT_COUNTER;
604 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
605 app_value->classid != STC_TETHERING_APP_CLASSID) {
606 __remove_app_monitor_for_tethering(key, value, data);
608 } else if (connection->tether_state == FALSE &&
609 connection->tether_iface.ifname != NULL &&
610 app_value->classid == STC_TETHERING_APP_CLASSID) {
611 counter.iftype = connection->tether_iface.type;
612 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
614 counter.iftype = connection->type;
615 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
618 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
619 stc_monitor_ipt_del_in(&counter);
620 stc_monitor_ipt_del_out(&counter);
621 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
622 stc_monitor_ip6t_del_in(&counter);
623 stc_monitor_ip6t_del_out(&counter);
625 stc_monitor_ipt_del_in(&counter);
626 stc_monitor_ipt_del_out(&counter);
627 stc_monitor_ip6t_del_in(&counter);
628 stc_monitor_ip6t_del_out(&counter);
635 void stc_monitor_app_remove_by_connection(default_connection_s *conn)
637 GHashTable *apps = stc_monitor_get_system_apps();
642 g_hash_table_foreach(apps, stc_monitor_app_remove_monitor, conn);
645 void stc_monitor_app_remove_accept(gpointer key,
646 gpointer value, gpointer data)
648 stc_app_value_s *app_value = (stc_app_value_s *)value;
649 default_connection_s *connection = (default_connection_s *)data;
650 stc_s *stc = stc_get_manager();
652 if (stc && connection && connection->ifname) {
653 struct nfacct_rule counter;
656 stc->carg = MALLOC0(counter_arg_s, 1);
657 if (stc->carg == NULL)
660 stc->carg->sock = stc_monitor_get_contr_sock();
663 memset(&counter, 0, sizeof(struct nfacct_rule));
665 counter.carg = stc->carg;
666 counter.classid = app_value->classid;
667 counter.app_state = app_value->state;
668 counter.intend = NFACCT_ALLOW;
670 counter.iftype = connection->type;
671 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
673 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
674 stc_monitor_ipt_del_in(&counter);
675 stc_monitor_ipt_del_out(&counter);
676 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
677 stc_monitor_ip6t_del_in(&counter);
678 stc_monitor_ip6t_del_out(&counter);
680 stc_monitor_ipt_del_in(&counter);
681 stc_monitor_ipt_del_out(&counter);
682 stc_monitor_ip6t_del_in(&counter);
683 stc_monitor_ip6t_del_out(&counter);
690 API gboolean stc_monitor_app_lookup(uint32_t classid)
692 stc_app_value_s *lookup_value;
694 GHashTable *apps = stc_monitor_get_system_apps();
699 if (classid == STC_UNKNOWN_CLASSID)
702 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
709 GHashTable *stc_monitor_apps_init(void)
711 return g_hash_table_new_full(g_direct_hash, g_direct_equal,
712 NULL, __app_value_destroy);