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.
17 #include <linux/netlink.h>
19 #include <vconf-keys.h>
21 #include "stc-default-connection.h"
22 #include "helper-nl.h"
23 #include "helper-nfacct-rule.h"
24 #include "helper-net-cls.h"
25 #include "helper-cgroup.h"
26 #include "helper-iptables.h"
28 #include "table-statistics.h"
29 #include "table-counters.h"
30 #include "stc-monitor.h"
31 #include "stc-manager-plugin-appstatus.h"
32 #include "stc-manager-plugin-exception.h"
34 #define MAX_INT_LENGTH 128
35 #define VCONFKEY_STC_BACKGROUND_STATE "db/stc/background_state"
38 stc_app_key_s *app_key;
39 stc_process_key_s *proc_key;
40 gboolean entry_removed;
41 } remove_pid_context_s;
44 struct nfacct_rule *counter;
46 gboolean data_limit_reached;
47 } classid_bytes_context_s;
49 static stc_system_s *g_system = NULL;
51 static nfacct_rule_jump __get_jump_by_intend(struct nfacct_rule *counter)
53 if (counter->intend == NFACCT_WARN)
54 return NFACCT_JUMP_ACCEPT;
55 else if (counter->intend == NFACCT_BLOCK)
56 return NFACCT_JUMP_REJECT;
57 else if (counter->intend == NFACCT_ALLOW)
58 return NFACCT_JUMP_ACCEPT;
60 return NFACCT_JUMP_UNKNOWN;
63 static stc_error_e __add_iptables_in(struct nfacct_rule *counter)
66 return STC_ERROR_INVALID_PARAMETER;
68 counter->action = NFACCT_ACTION_INSERT;
69 counter->iotype = NFACCT_COUNTER_IN;
70 counter->jump = __get_jump_by_intend(counter);
71 counter->iptype = NFACCT_TYPE_IPV4;
72 counter->send_limit = 0;
73 counter->rcv_limit = 0;
75 return produce_net_rule(counter);
78 static stc_error_e __add_iptables_out(struct nfacct_rule *counter)
81 return STC_ERROR_INVALID_PARAMETER;
83 counter->action = NFACCT_ACTION_INSERT;
84 counter->iotype = NFACCT_COUNTER_OUT;
85 counter->jump = __get_jump_by_intend(counter);
86 counter->iptype = NFACCT_TYPE_IPV4;
87 counter->send_limit = 0;
88 counter->rcv_limit = 0;
90 return produce_net_rule(counter);
93 static stc_error_e __del_iptables_in(struct nfacct_rule *counter)
96 return STC_ERROR_INVALID_PARAMETER;
98 counter->action = NFACCT_ACTION_DELETE;
99 counter->iotype = NFACCT_COUNTER_IN;
100 counter->jump = __get_jump_by_intend(counter);
101 counter->iptype = NFACCT_TYPE_IPV4;
102 counter->send_limit = 0;
103 counter->rcv_limit = 0;
105 return produce_net_rule(counter);
108 static stc_error_e __del_iptables_out(struct nfacct_rule *counter)
111 return STC_ERROR_INVALID_PARAMETER;
113 counter->action = NFACCT_ACTION_DELETE;
114 counter->iotype = NFACCT_COUNTER_OUT;
115 counter->jump = __get_jump_by_intend(counter);
116 counter->iptype = NFACCT_TYPE_IPV4;
117 counter->send_limit = 0;
118 counter->rcv_limit = 0;
120 return produce_net_rule(counter);
123 static stc_error_e __add_ip6tables_in(struct nfacct_rule *counter)
126 return STC_ERROR_INVALID_PARAMETER;
128 counter->action = NFACCT_ACTION_INSERT;
129 counter->iotype = NFACCT_COUNTER_IN;
130 counter->jump = __get_jump_by_intend(counter);
131 counter->iptype = NFACCT_TYPE_IPV6;
132 counter->send_limit = 0;
133 counter->rcv_limit = 0;
135 return produce_net_rule(counter);
138 static stc_error_e __add_ip6tables_out(struct nfacct_rule *counter)
141 return STC_ERROR_INVALID_PARAMETER;
143 counter->action = NFACCT_ACTION_INSERT;
144 counter->iotype = NFACCT_COUNTER_OUT;
145 counter->jump = __get_jump_by_intend(counter);
146 counter->iptype = NFACCT_TYPE_IPV6;
147 counter->send_limit = 0;
148 counter->rcv_limit = 0;
150 return produce_net_rule(counter);
153 static stc_error_e __del_ip6tables_in(struct nfacct_rule *counter)
156 return STC_ERROR_INVALID_PARAMETER;
158 counter->action = NFACCT_ACTION_DELETE;
159 counter->iotype = NFACCT_COUNTER_IN;
160 counter->jump = __get_jump_by_intend(counter);
161 counter->iptype = NFACCT_TYPE_IPV6;
162 counter->send_limit = 0;
163 counter->rcv_limit = 0;
165 return produce_net_rule(counter);
168 static stc_error_e __del_ip6tables_out(struct nfacct_rule *counter)
171 return STC_ERROR_INVALID_PARAMETER;
173 counter->action = NFACCT_ACTION_DELETE;
174 counter->iotype = NFACCT_COUNTER_OUT;
175 counter->jump = __get_jump_by_intend(counter);
176 counter->iptype = NFACCT_TYPE_IPV6;
177 counter->send_limit = 0;
178 counter->rcv_limit = 0;
180 return produce_net_rule(counter);
183 static int __processes_tree_key_compare(gconstpointer a, gconstpointer b,
184 gpointer UNUSED user_data)
186 stc_process_key_s *key_a = (stc_process_key_s *)a;
187 stc_process_key_s *key_b = (stc_process_key_s *)b;
189 return key_a->pid - key_b->pid;
192 static void __processes_tree_value_free(gpointer data)
194 stc_process_value_s *value = (stc_process_value_s *)data;
199 static void __processes_tree_key_free(gpointer data)
201 stc_process_key_s *key = (stc_process_key_s *)data;
206 static int __apps_tree_key_compare(gconstpointer a, gconstpointer b,
207 gpointer UNUSED user_data)
209 stc_app_key_s *key_a = (stc_app_key_s *)a;
210 stc_app_key_s *key_b = (stc_app_key_s *)b;
213 ret = g_strcmp0(key_a->pkg_id, key_b->pkg_id);
217 return g_strcmp0(key_a->app_id, key_b->app_id);
220 static void __apps_tree_value_free(gpointer data)
222 stc_app_value_s *value = (stc_app_value_s *)data;
224 g_tree_destroy(value->processes);
225 value->processes = NULL;
230 static void __apps_tree_key_free(gpointer data)
232 stc_app_key_s *key = (stc_app_key_s *)data;
239 static int __rstns_tree_key_compare(gconstpointer a, gconstpointer b,
240 gpointer UNUSED user_data)
242 stc_rstn_key_s *key_a = (stc_rstn_key_s *)a;
243 stc_rstn_key_s *key_b = (stc_rstn_key_s *)b;
246 ret = g_strcmp0(key_a->app_id, key_b->app_id);
250 ret = g_strcmp0(key_a->ifname, key_b->ifname);
254 ret = g_strcmp0(key_a->subscriber_id, key_b->subscriber_id);
258 ret = key_a->iftype - key_b->iftype;
262 ret = key_a->roaming - key_b->roaming;
269 static void __rstns_tree_value_free(gpointer data)
271 stc_rstn_value_s *value = (stc_rstn_value_s *)data;
276 static void __rstns_tree_key_free(gpointer data)
278 stc_rstn_key_s *key = (stc_rstn_key_s *)data;
282 FREE(key->subscriber_id);
287 static gboolean __processes_tree_foreach_print(gpointer key, gpointer value,
290 stc_process_key_s *proc_key = (stc_process_key_s *)key;
291 stc_process_value_s *proc_value = (stc_process_value_s *)value;
293 STC_LOGD("Process entry => PID [\033[1;33m%d\033[0;m], Ground state [%d]",
294 proc_key->pid, proc_value->ground);
298 static void __processes_tree_printall(GTree *processes)
300 g_tree_foreach(processes, __processes_tree_foreach_print, NULL);
303 static gboolean __apps_tree_foreach_print(gpointer key, gpointer value,
306 stc_app_key_s *app_key = (stc_app_key_s *)key;
307 stc_app_value_s *app_value = (stc_app_value_s *)value;
309 STC_LOGD("Application info => Pkg ID [\033[0;34m%s\033[0;m], "
310 "App ID [\033[0;32m%s\033[0;m], Type [%d], classid [%d],"
311 " counter [ in (%lld), out (%lld)]",
312 app_key->pkg_id, app_key->app_id,
313 app_value->type, app_value->classid,
314 app_value->data_usage.in_bytes, app_value->data_usage.out_bytes);
316 __processes_tree_printall(app_value->processes);
320 static void __apps_tree_printall(void)
322 g_tree_foreach(g_system->apps, __apps_tree_foreach_print, NULL);
326 static gboolean __apps_tree_foreach_remove_pid(gpointer key, gpointer value,
329 remove_pid_context_s *context = (remove_pid_context_s *)data;
330 stc_app_value_s *app_value = (stc_app_value_s *)value;
332 if (!g_tree_remove(app_value->processes, context->proc_key)) {
334 STC_LOGD("key not found"); //LCOV_EXCL_LINE
338 context->entry_removed = TRUE;
339 context->app_key = (stc_app_key_s *)key;
344 static stc_app_value_s * __application_lookup(GTree *apps,
345 const stc_app_key_s *key)
347 stc_app_value_s *lookup;
349 ret_value_msg_if(apps == NULL, NULL, "apps is null!");
351 lookup = g_tree_lookup(apps, key);
356 static stc_process_value_s * __process_lookup(GTree *processes,
357 const stc_process_key_s *key)
359 stc_process_value_s *lookup;
361 ret_value_msg_if(processes == NULL, NULL, "processes is null!");
363 lookup = g_tree_lookup(processes, key);
369 static gboolean __processes_tree_check_empty(gpointer key, gpointer value,
372 guint *pid_count = (guint *)data;
378 static gboolean __add_application_monitor(gpointer key, gpointer value,
381 stc_app_value_s *app_value = (stc_app_value_s *)value;
382 default_connection_s *connection = (default_connection_s *)data;
383 stc_s *stc = stc_get_manager();
385 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
386 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
387 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
390 if (stc && connection && connection->ifname) {
391 struct nfacct_rule counter;
394 stc->carg = MALLOC0(counter_arg_s, 1); //LCOV_EXCL_LINE
395 if (stc->carg == NULL) //LCOV_EXCL_LINE
396 return FALSE; //LCOV_EXCL_LINE
398 stc->carg->sock = stc_monitor_get_counter_socket(); //LCOV_EXCL_LINE
401 memset(&counter, 0, sizeof(struct nfacct_rule));
403 counter.carg = stc->carg;
404 counter.classid = app_value->classid;
405 counter.intend = NFACCT_COUNTER;
406 counter.iftype = connection->type;
407 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
409 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
410 __add_iptables_in(&counter);
411 __add_iptables_out(&counter);
412 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
413 __add_ip6tables_in(&counter);
414 __add_ip6tables_out(&counter);
416 __add_iptables_in(&counter);
417 __add_iptables_out(&counter);
418 __add_ip6tables_in(&counter);
419 __add_ip6tables_out(&counter);
426 static gboolean __remove_application_monitor(gpointer key, gpointer value,
429 stc_app_value_s *app_value = (stc_app_value_s *)value;
430 default_connection_s *connection = (default_connection_s *)data;
431 stc_s *stc = stc_get_manager();
433 if (stc && connection && connection->ifname) {
434 struct nfacct_rule counter;
437 stc->carg = MALLOC0(counter_arg_s, 1); //LCOV_EXCL_LINE
438 if (stc->carg == NULL) //LCOV_EXCL_LINE
439 return FALSE; //LCOV_EXCL_LINE
441 stc->carg->sock = stc_monitor_get_counter_socket(); //LCOV_EXCL_LINE
444 memset(&counter, 0, sizeof(struct nfacct_rule));
446 counter.carg = stc->carg;
447 counter.classid = app_value->classid;
448 counter.intend = NFACCT_COUNTER;
449 counter.iftype = connection->type;
450 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
452 __del_iptables_in(&counter);
453 __del_iptables_out(&counter);
454 __del_ip6tables_in(&counter);
455 __del_ip6tables_out(&counter);
461 static void __print_rstn(stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value)
463 STC_LOGI("rstn info => rstn_id [%llu], "
464 "app_id [%s], classid [%lu], ifname [%s], "
465 "iftype [%d], rst_state [%d], rst_type [%d], "
466 "limit [ (%lld) bytes], "
467 "warn_limit [ (%lld) bytes], "
468 "counter [ (%lld) bytes], "
469 "roaming [%d], subscriber_id [%s]",
470 rstn_value->restriction_id,
471 rstn_key->app_id, rstn_value->classid , rstn_key->ifname,
472 rstn_key->iftype, rstn_value->rst_state, rstn_value->rst_type,
473 rstn_value->data_limit,
474 rstn_value->data_warn_limit,
475 rstn_value->data_counter,
476 rstn_key->roaming, rstn_key->subscriber_id);
479 static void __add_iptables_rule(int64_t classid, nfacct_rule_intend intend,
480 stc_iface_type_e iftype)
482 char *default_ifname = stc_default_connection_get_ifname();
483 struct nfacct_rule counter;
484 stc_s *stc = stc_get_manager();
486 g_free(default_ifname); //LCOV_EXCL_LINE
487 return; //LCOV_EXCL_LINE
491 stc->carg = MALLOC0(counter_arg_s, 1); //LCOV_EXCL_LINE
492 if (stc->carg == NULL) { //LCOV_EXCL_LINE
493 g_free(default_ifname); //LCOV_EXCL_LINE
494 return; //LCOV_EXCL_LINE
497 stc->carg->sock = stc_monitor_get_counter_socket(); //LCOV_EXCL_LINE
500 counter.carg = stc->carg;
501 counter.classid = classid;
502 counter.intend = intend;
503 counter.iftype = iftype;
504 g_strlcpy(counter.ifname, default_ifname, MAX_IFACE_LENGTH);
505 g_free(default_ifname);
508 __add_iptables_in(&counter);
509 __add_iptables_out(&counter);
512 __add_ip6tables_in(&counter);
513 __add_ip6tables_out(&counter);
516 static void __del_iptables_rule(int64_t classid, nfacct_rule_intend intend,
517 stc_iface_type_e iftype)
519 char *default_ifname = stc_default_connection_get_ifname();
520 struct nfacct_rule counter;
521 stc_s *stc = stc_get_manager();
523 g_free(default_ifname); //LCOV_EXCL_LINE
524 return; //LCOV_EXCL_LINE
528 stc->carg = MALLOC0(counter_arg_s, 1); //LCOV_EXCL_LINE
529 if (stc->carg == NULL) { //LCOV_EXCL_LINE
530 g_free(default_ifname); //LCOV_EXCL_LINE
531 return; //LCOV_EXCL_LINE
534 stc->carg->sock = stc_monitor_get_counter_socket(); //LCOV_EXCL_LINE
537 counter.carg = stc->carg;
538 counter.classid = classid;
539 counter.intend = intend;
540 counter.iftype = iftype;
541 g_strlcpy(counter.ifname, default_ifname, MAX_IFACE_LENGTH);
542 g_free(default_ifname);
545 __del_iptables_in(&counter);
546 __del_iptables_out(&counter);
549 __del_ip6tables_in(&counter);
550 __del_ip6tables_out(&counter);
553 static void __process_restriction(enum traffic_restriction_type rst_type,
554 stc_rstn_key_s *rstn_key,
555 stc_rstn_value_s *rstn_value, void *data)
557 int64_t effective_data_limit, effective_data_warn_limit;
558 default_connection_s *old_connection = (default_connection_s *)data;
559 default_connection_s *connection = NULL;
561 if (old_connection != NULL)
562 connection = old_connection;
564 connection = stc_get_default_connection();
566 /* no default ifname */
567 if (connection->ifname == NULL)
570 /* rstn not applicable for this interface */
571 if (rstn_key->ifname != NULL && g_strcmp0("", rstn_key->ifname) != 0 &&
572 g_strcmp0(connection->ifname, rstn_key->ifname) != 0)
575 /* classid is invalid */
576 if (rstn_value->classid <= STC_UNKNOWN_CLASSID)
579 effective_data_limit = rstn_value->data_limit;
580 effective_data_warn_limit = rstn_value->data_warn_limit;
582 if (rst_type == RST_SET) {
583 /* TODO: Change this to runtime memory */
584 table_counters_info info;
586 memset(&info, 0, sizeof(table_counters_info));
587 table_counters_get(rstn_value->restriction_id, &info);
589 effective_data_limit -= info.data_counter;
590 effective_data_warn_limit -= info.data_counter;
592 if (effective_data_limit < 0) {
593 effective_data_limit = 0; //LCOV_EXCL_LINE
594 rstn_value->data_limit_reached = TRUE; //LCOV_EXCL_LINE
597 if (effective_data_warn_limit < 0)
598 effective_data_warn_limit = 0; //LCOV_EXCL_LINE
600 STC_LOGD("datausage [%lld] bytes", info.data_counter);
603 STC_LOGD("rstn_id [%llu], effective_data_limit [%lld] bytes, "
604 "effective_data_warn_limit [%lld] bytes",
605 rstn_value->restriction_id, effective_data_limit,
606 effective_data_warn_limit);
610 if (effective_data_limit <= 0)
611 __add_iptables_rule(rstn_value->classid, NFACCT_BLOCK,
614 rstn_value->rst_state = STC_RESTRICTION_ACTIVATED;
615 rstn_value->data_limit_reached = FALSE;
618 __add_iptables_rule(rstn_value->classid, NFACCT_ALLOW,
621 rstn_value->rst_state = STC_RESTRICTION_ACTIVATED;
622 rstn_value->data_limit_reached = TRUE;
625 __del_iptables_rule(rstn_value->classid, rstn_value->rst_type,
628 rstn_value->rst_state = STC_RESTRICTION_DEACTIVATED;
629 rstn_value->data_limit_reached = FALSE;
637 static gboolean __remove_rstns_foreach_application(gpointer key,
641 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
642 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
643 gchar *app_id = (gchar *)data;
645 /* rstn rule is not for applications */
646 if (rstn_key->app_id == NULL)
649 /* rstn rule is not for this application */
650 if (g_strcmp0(rstn_key->app_id, app_id) != 0)
653 /* rstn rule is already removed */
654 if (rstn_value->rst_state == STC_RESTRICTION_DEACTIVATED)
657 /* remove restriction from system */
658 __process_restriction(RST_UNSET, rstn_key, rstn_value, NULL);
660 __print_rstn(rstn_key, rstn_value);
666 static void __remove_rstns_for_application(gchar *app_id)
668 g_tree_foreach(g_system->rstns, __remove_rstns_foreach_application,
672 static stc_error_e __application_remove_if_empty(const stc_app_key_s *app_key)
674 stc_error_e ret = STC_ERROR_NONE;
676 stc_app_value_s *lookup;
678 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
680 lookup = __application_lookup(g_system->apps, app_key);
682 STC_LOGE("app_key not found"); //LCOV_EXCL_LINE
683 return STC_ERROR_NO_DATA; //LCOV_EXCL_LINE
686 g_tree_foreach(lookup->processes, __processes_tree_check_empty,
690 /* remove nfacct rule for this classid */
691 __remove_application_monitor((gpointer) app_key, lookup,
692 stc_get_default_connection());
693 __remove_rstns_for_application(app_key->app_id);
696 if (!g_tree_remove(g_system->apps, app_key)) {
697 ret = STC_ERROR_NO_DATA; //LCOV_EXCL_LINE
698 STC_LOGE("key not found"); //LCOV_EXCL_LINE
704 static stc_error_e __close_contr_sock(stc_system_s *system)
706 ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
708 /* close netlink socket for updating kernel counters */
709 if (system->contr_sock != -1) {
710 close(system->contr_sock);
711 system->contr_sock = -1;
714 if (system->contr_gsource_id != 0) {
715 g_source_remove(system->contr_gsource_id);
716 system->contr_gsource_id = 0;
719 return STC_ERROR_NONE;
722 static gboolean __process_contr_reply(GIOChannel *source,
723 GIOCondition condition,
727 static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system)
729 GIOChannel *gio = NULL;
730 ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
732 /* close netlink socket for updating kernel counters */
733 if (system->contr_sock != -1) {
734 close(system->contr_sock);
735 system->contr_sock = -1;
738 if (system->contr_gsource_id != 0) {
739 g_source_remove(system->contr_gsource_id);
740 system->contr_gsource_id = 0;
743 /* create netlink socket for updating kernel counters */
744 system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
745 if (system->contr_sock < 0) {
746 STC_LOGE("failed to open socket");
748 return STC_ERROR_FAIL;
751 gio = g_io_channel_unix_new(system->contr_sock);
752 system->contr_gsource_id =
753 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
754 (GIOFunc) __process_contr_reply,
756 g_io_channel_unref(gio);
758 return STC_ERROR_NONE;
761 static gboolean __rstn_counter_update(stc_rstn_key_s *rstn_key,
762 stc_rstn_value_s *rstn_value,
763 classid_bytes_context_s *context)
765 switch (context->counter->iotype) {
766 case NFACCT_COUNTER_IN:
767 case NFACCT_COUNTER_OUT:
768 rstn_value->data_counter += context->bytes;
770 if (rstn_value->data_counter >= rstn_value->data_warn_limit &&
771 rstn_value->warn_limit_crossed_notified == FALSE) {
774 char iftype[MAX_INT_LENGTH];
775 char byte[MAX_INT_LENGTH];
776 stc_s *stc = (stc_s *)stc_get_manager();
777 ret_value_msg_if(stc == NULL, FALSE, "failed to get stc data");
780 rv = stc_manager_dbus_emit_signal(stc->connection,
781 STC_DBUS_SERVICE_RESTRICTION_PATH,
782 STC_DBUS_INTERFACE_RESTRICTION,
783 "WarnThresholdCrossed",
784 g_variant_new("(si)", rstn_key->app_id, rstn_key->iftype));
786 rstn_value->warn_limit_crossed_notified = TRUE;
788 snprintf(iftype, MAX_INT_LENGTH, "%d", rstn_key->iftype);
789 snprintf(byte, MAX_INT_LENGTH, "%lld", rstn_value->data_warn_limit);
790 stc_plugin_appstatus_send_warn_message("warn threshold crossed",
796 if (rstn_value->data_counter >= rstn_value->data_limit &&
797 rstn_value->rstn_limit_crossed_notified == FALSE) {
800 char iftype[MAX_INT_LENGTH];
801 char byte[MAX_INT_LENGTH];
802 stc_s *stc = (stc_s *)stc_get_manager();
803 ret_value_msg_if(stc == NULL, FALSE, "failed to get stc data");
805 /* block immediately */
806 context->counter->intend = NFACCT_BLOCK;
807 __del_iptables_in(context->counter);
808 __del_iptables_out(context->counter);
809 __add_iptables_in(context->counter);
810 __add_iptables_out(context->counter);
812 __del_ip6tables_in(context->counter);
813 __del_ip6tables_out(context->counter);
814 __add_ip6tables_in(context->counter);
815 __add_ip6tables_out(context->counter);
816 context->counter->intend = NFACCT_COUNTER;
818 rstn_value->data_limit_reached = TRUE;
821 rv = stc_manager_dbus_emit_signal(stc->connection,
822 STC_DBUS_SERVICE_RESTRICTION_PATH,
823 STC_DBUS_INTERFACE_RESTRICTION,
824 "RestrictionThresholdCrossed",
825 g_variant_new("(si)", rstn_key->app_id, rstn_key->iftype));
827 rstn_value->rstn_limit_crossed_notified = TRUE;
829 snprintf(iftype, MAX_INT_LENGTH, "%d", rstn_key->iftype);
830 snprintf(byte, MAX_INT_LENGTH, "%lld", rstn_value->data_limit);
831 stc_plugin_appstatus_send_restriction_message("restriction threshold crossed",
832 "restriction_noti", rstn_key->app_id,
836 g_system->rstns_tree_updated = TRUE;
837 __print_rstn(rstn_key, rstn_value);
840 STC_LOGE("unknown iotype");
846 static gboolean __interface_rstn_counter_update(stc_rstn_key_s *rstn_key,
847 stc_rstn_value_s *rstn_value,
848 classid_bytes_context_s *context)
850 if ((rstn_value->classid == STC_TOTAL_DATACALL_CLASSID &&
851 context->counter->iftype == STC_IFACE_DATACALL) ||
852 (rstn_value->classid == STC_TOTAL_WIFI_CLASSID &&
853 context->counter->iftype == STC_IFACE_WIFI) ||
854 (rstn_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
855 context->counter->iftype == STC_IFACE_BLUETOOTH)) {
856 context->counter->classid = rstn_value->classid;
857 return __rstn_counter_update(rstn_key, rstn_value, context);
863 static gboolean __rstn_counter_update_foreach_classid(gpointer key,
868 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
869 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
870 classid_bytes_context_s *context = (classid_bytes_context_s *)data;
873 if (context->counter->intend != NFACCT_COUNTER)
874 goto try_next_callback;
876 if (rstn_value->data_limit_reached == TRUE) {
877 context->data_limit_reached = TRUE; //LCOV_EXCL_LINE
878 goto try_next_callback; //LCOV_EXCL_LINE
881 classid = context->counter->classid;
882 rv = __interface_rstn_counter_update(rstn_key, rstn_value, context);
884 context->counter->classid = classid;
885 if (rstn_value->classid != context->counter->classid)
886 goto try_next_callback;
888 rv = __rstn_counter_update(rstn_key, rstn_value, context);
895 static gboolean __update_app_statistics(gpointer key, gpointer value,
898 stc_app_key_s *app_key = (stc_app_key_s *)key;
899 stc_app_value_s *app_value = (stc_app_value_s *)value;
900 time_t *touch_time = (time_t *)data;
901 stc_db_classid_iftype_key stat_key;
902 stc_db_app_stats stat;
903 default_connection_s *default_connection = stc_get_default_connection();
905 memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key));
906 memset(&stat, 0 , sizeof(stc_db_app_stats));
908 stat_key.classid = app_value->classid;
909 stat_key.iftype = default_connection->type;
911 if (STC_IFACE_DATACALL == stat_key.iftype)
912 stat_key.subscriber_id = g_strdup(default_connection->subscriber_id);
914 stat_key.subscriber_id = g_strdup("none_subid"); //LCOV_EXCL_LINE
916 g_strlcpy(stat_key.ifname, default_connection->ifname,
919 stat.app_id = g_strdup(app_key->app_id);
920 stat.snd_count = app_value->counter.out_bytes;
921 stat.rcv_count = app_value->counter.in_bytes;
922 stat.is_roaming = default_connection->roaming;
924 if (strstr(stat.app_id, "_BACKGROUND")) {
925 stat.ground = STC_APP_STATE_BACKGROUND;
927 if (strstr(stat.app_id, "TOTAL_"))
928 stat.ground = STC_APP_STATE_UNKNOWN;
930 stat.ground = STC_APP_STATE_FOREGROUND;
933 table_statistics_insert(&stat_key, &stat, *touch_time);
935 app_value->counter.out_bytes = 0;
936 app_value->counter.in_bytes = 0;
939 FREE(stat_key.subscriber_id);
944 static gboolean __flush_apps_stats_to_database(gpointer user_data)
946 time_t current_time = time(0);
948 if (g_system->apps_tree_updated == FALSE)
949 return G_SOURCE_REMOVE;
951 g_system->apps_tree_updated = FALSE;
954 g_tree_foreach(g_system->apps,
955 __update_app_statistics,
958 STC_LOGI("Flushed app stats to database");
959 return G_SOURCE_REMOVE;
963 static gboolean __update_counter_statistics(gpointer key, gpointer value,
966 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
967 table_counters_info info = {
968 .restriction_id = rstn_value->restriction_id,
969 .data_counter = rstn_value->data_counter
972 table_counters_update_counters(&info);
977 static gboolean __flush_rstns_counter_to_database(gpointer user_data)
979 time_t current_time = time(0);
981 if (g_system->rstns_tree_updated == FALSE)
982 return G_SOURCE_REMOVE;
984 g_system->rstns_tree_updated = FALSE;
987 g_tree_foreach(g_system->rstns,
988 __update_counter_statistics,
991 STC_LOGI("Flushed rstns counters to database");
992 return G_SOURCE_REMOVE;
996 static void __app_counter_update(stc_app_key_s *app_key,
997 stc_app_value_s *app_value,
998 classid_bytes_context_s *context)
1000 switch (context->counter->iotype) {
1001 case NFACCT_COUNTER_IN:
1002 app_value->data_usage.in_bytes += context->bytes;
1003 app_value->counter.in_bytes = context->bytes;
1004 g_system->apps_tree_updated = TRUE;
1007 __apps_tree_foreach_print(app_key, app_value, NULL); //LCOV_EXCL_LINE
1009 case NFACCT_COUNTER_OUT:
1010 app_value->data_usage.out_bytes += context->bytes;
1011 app_value->counter.out_bytes = context->bytes;
1012 g_system->apps_tree_updated = TRUE;
1015 __apps_tree_foreach_print(app_key, app_value, NULL); //LCOV_EXCL_LINE
1018 STC_LOGE("unknown iotype"); //LCOV_EXCL_LINE
1022 static void __interface_counter_update(stc_app_key_s *app_key,
1023 stc_app_value_s *app_value,
1024 classid_bytes_context_s *context)
1026 if ((app_value->classid == STC_TOTAL_DATACALL_CLASSID &&
1027 context->counter->iftype == STC_IFACE_DATACALL) ||
1028 (app_value->classid == STC_TOTAL_WIFI_CLASSID &&
1029 context->counter->iftype == STC_IFACE_WIFI) ||
1030 (app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
1031 context->counter->iftype == STC_IFACE_BLUETOOTH))
1032 __app_counter_update(app_key, app_value, context);
1036 static gboolean __apps_counter_update_foreach_classid(gpointer key,
1040 stc_app_key_s *app_key = (stc_app_key_s *)key;
1041 stc_app_value_s *app_value = (stc_app_value_s *)value;
1042 classid_bytes_context_s *context = (classid_bytes_context_s *)data;
1044 if (context->counter->intend != NFACCT_COUNTER)
1045 goto try_next_callback;
1047 __interface_counter_update(app_key, app_value, context);
1049 if (app_value->classid != context->counter->classid)
1050 goto try_next_callback;
1052 __app_counter_update(app_key, app_value, context);
1058 static void __fill_nfacct_result(char *cnt_name, int64_t bytes,
1059 struct counter_arg *carg)
1061 struct nfacct_rule counter = {
1068 classid_bytes_context_s context = {
1069 .counter = &counter,
1071 .data_limit_reached = FALSE,
1075 STC_LOGD("cnt_name %s", cnt_name); //LCOV_EXCL_LINE
1077 if (!recreate_counter_by_name(cnt_name, &counter)) {
1078 STC_LOGE("Can't parse counter name %s", cnt_name); //LCOV_EXCL_LINE
1079 return; //LCOV_EXCL_LINE
1082 STC_LOGI("classid %lu, iftype %u, iotype %d, intend %d, ifname %s, bytes %lld",
1083 context.counter->classid, context.counter->iftype,
1084 context.counter->iotype, context.counter->intend,
1085 context.counter->ifname, context.bytes);
1087 if (g_system->rstns)
1088 g_tree_foreach(g_system->rstns,
1089 __rstn_counter_update_foreach_classid,
1093 g_tree_foreach(g_system->apps,
1094 __apps_counter_update_foreach_classid,
1098 static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
1101 struct counter_arg *carg = user_data;
1102 char *cnt_name = (char *)RTA_DATA(attr_list[NFACCT_NAME]);
1103 if (carg->initiate) {
1105 * TODO: this will be used when daemon starts to update existing
1106 * counter data if present.
1108 populate_counters(cnt_name, carg);
1112 (int64_t *)RTA_DATA(attr_list[NFACCT_BYTES]);
1113 int bytes = be64toh(*bytes_p);
1115 ++carg->serialized_counters;
1116 __fill_nfacct_result(cnt_name, bytes, carg);
1123 static int __post_fill_counters(void *user_data)
1125 struct counter_arg *carg = user_data;
1133 static void __process_network_counter(struct genl *ans,
1134 struct counter_arg *carg)
1136 struct netlink_serialization_params ser_params = {
1139 .eval_attr = __fill_counters,
1140 .post_eval_attr = __post_fill_counters,
1143 netlink_serialization_command *netlink =
1144 netlink_create_command(&ser_params);
1146 STC_LOGE("Can not create command"); //LCOV_EXCL_LINE
1147 return; //LCOV_EXCL_LINE
1150 netlink->deserialize_answer(&(netlink->params));
1153 static gboolean __process_contr_reply(GIOChannel *source,
1154 GIOCondition condition,
1157 int sock = g_io_channel_unix_get_fd(source);
1160 stc_s *stc = stc_get_manager();
1163 void __gcov_flush(void);
1167 if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
1168 (condition & G_IO_NVAL)) {
1169 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
1171 STC_LOGE("Counter socket received G_IO event, closing socket." //LCOV_EXCL_LINE
1172 "G_IO_ERR [%d], G_IO_HUP [%d], G_IO_NVAL [%s]",
1173 (condition & G_IO_ERR), (condition & G_IO_HUP),
1174 (condition & G_IO_NVAL));
1175 __close_and_reopen_contr_sock(g_system); //LCOV_EXCL_LINE
1176 return FALSE; //LCOV_EXCL_LINE
1179 ans = MALLOC0(struct genl, 1);
1181 STC_LOGE("Failed allocate memory to genl reply message"); //LCOV_EXCL_LINE
1182 return TRUE; //LCOV_EXCL_LINE
1186 STC_LOGE("Can't get stc data"); //LCOV_EXCL_LINE
1187 goto out; //LCOV_EXCL_LINE
1190 ret = read_netlink(sock, ans, sizeof(struct genl));
1191 /* STC_LOGD("Counter data received ret [%d]", ret); */
1195 stc->carg->ans_len = ret;
1196 __process_network_counter(ans, stc->carg);
1198 g_idle_add(__flush_apps_stats_to_database, NULL);
1199 g_idle_add(__flush_rstns_counter_to_database, NULL);
1206 static gboolean __update_contr_cb(void *user_data)
1208 /* Here we just sent command, answer we receive in another callback */
1209 stc_s *stc = stc_get_manager();
1210 ret_value_msg_if(stc == NULL, STC_ERROR_FAIL, "Can't get stc data");
1212 stc->carg = MALLOC0(counter_arg_s, 1);
1213 if (stc->carg == NULL)
1214 return TRUE; /* we need to continue the timer */
1216 stc->carg->sock = stc_monitor_get_counter_socket();
1220 void __gcov_flush(void);
1224 /* STC_LOGD("Get all counters"); */
1225 nfacct_send_get_all(stc->carg);
1227 /* we need to continue the timer */
1232 static gboolean __rstn_tree_foreach_print(gpointer key, gpointer value,
1235 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1236 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1238 __print_rstn(rstn_key, rstn_value);
1242 static void __rstn_tree_printall(void)
1244 g_tree_foreach(g_system->rstns, __rstn_tree_foreach_print, NULL);
1248 static stc_rstn_value_s * __rstn_lookup(GTree *rstns_tree,
1249 const stc_rstn_key_s *key)
1251 stc_rstn_value_s *lookup;
1253 ret_value_msg_if(rstns_tree == NULL, NULL, "rstns_tree is null!");
1255 lookup = g_tree_lookup(rstns_tree, key);
1260 static gboolean __remove_restriction(gpointer key, gpointer value,
1263 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1264 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1266 __process_restriction(RST_UNSET, rstn_key, rstn_value, data);
1267 __print_rstn(rstn_key, rstn_value);
1271 static gboolean __add_restriction_debug(gpointer key, gpointer value,
1274 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1275 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1277 /* rstn rule is activated */
1278 if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED)
1281 if (rstn_value->rst_type == STC_RSTN_TYPE_EXCLUDED)
1282 __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
1284 __process_restriction(RST_SET, rstn_key, rstn_value, data);
1286 __print_rstn(rstn_key, rstn_value);
1292 static gboolean __add_restriction(gpointer key, gpointer value, gpointer data)
1294 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1295 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1297 /* rstn rule is activated */
1298 if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED)
1301 if (rstn_value->rst_type == STC_RSTN_TYPE_EXCLUDED)
1302 __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
1304 __process_restriction(RST_SET, rstn_key, rstn_value, data);
1310 static stc_error_e __rstn_tree_remove(stc_rstn_key_s *key)
1312 stc_rstn_value_s *lookup_value;
1314 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1316 lookup_value = __rstn_lookup(g_system->rstns, key);
1317 if (!lookup_value) {
1318 STC_LOGE("key not found"); //LCOV_EXCL_LINE
1319 return STC_ERROR_NO_DATA; //LCOV_EXCL_LINE
1322 __remove_restriction(key, lookup_value, NULL);
1324 /* remove counter also */
1325 table_counters_delete(lookup_value->restriction_id);
1327 if (!g_tree_remove(g_system->rstns, key)) {
1328 STC_LOGD("key not found"); //LCOV_EXCL_LINE
1329 return STC_ERROR_NO_DATA; //LCOV_EXCL_LINE
1332 return STC_ERROR_NONE;
1335 static stc_error_e __rstn_tree_add(stc_rstn_key_s *key,
1336 stc_rstn_value_s *value, gboolean debug)
1338 stc_rstn_key_s *rstn_key;
1339 stc_rstn_value_s *rstn_value;
1341 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1343 rstn_value = __rstn_lookup(g_system->rstns, key);
1345 __rstn_tree_remove(key);
1347 rstn_key = MALLOC0(stc_rstn_key_s, 1);
1349 STC_LOGE("rstn_key allocation failed"); //LCOV_EXCL_LINE
1350 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
1353 rstn_value = MALLOC0(stc_rstn_value_s, 1);
1355 STC_LOGE("rstn_value allocation failed"); //LCOV_EXCL_LINE
1356 FREE(rstn_key); //LCOV_EXCL_LINE
1357 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
1360 rstn_key->app_id = g_strdup(key->app_id);
1361 rstn_key->ifname = g_strdup(key->ifname);
1362 rstn_key->subscriber_id = g_strdup(key->subscriber_id);
1363 rstn_key->iftype = key->iftype;
1364 rstn_key->roaming = key->roaming;
1366 g_tree_insert(g_system->rstns, rstn_key, rstn_value);
1368 rstn_value->restriction_id = value->restriction_id;
1369 rstn_value->rst_state = value->rst_state;
1370 rstn_value->rst_type = value->rst_type;
1371 rstn_value->classid = value->classid;
1372 rstn_value->data_limit = value->data_limit;
1373 rstn_value->data_warn_limit = value->data_warn_limit;
1374 rstn_value->data_counter = 0;
1375 rstn_value->warn_limit_crossed_notified = FALSE;
1376 rstn_value->rstn_limit_crossed_notified = FALSE;
1379 __add_restriction_debug(key, rstn_value, NULL);
1381 __add_restriction(key, rstn_value, NULL);
1383 return STC_ERROR_NONE;
1387 static stc_cb_ret_e __insert_restriction_cb(const table_restrictions_info *info,
1390 stc_cb_ret_e ret = STC_CONTINUE;
1393 stc_rstn_value_s value;
1395 memset(&key, 0, sizeof(stc_rstn_key_s));
1396 memset(&value, 0, sizeof(stc_rstn_value_s));
1398 key.app_id = g_strdup(info->app_id);
1399 key.ifname = g_strdup(info->ifname);
1400 key.subscriber_id = g_strdup(info->subscriber_id);
1401 key.iftype = info->iftype;
1402 key.roaming = info->roaming;
1404 value.rst_type = info->rst_type;
1405 value.rst_state = STC_RESTRICTION_UNKNOWN;
1406 value.restriction_id = info->restriction_id;
1409 value.classid = get_classid_by_app_id(info->app_id, TRUE);
1411 value.classid = STC_UNKNOWN_CLASSID;
1413 value.data_limit = info->data_limit;
1414 value.data_warn_limit = info->data_warn_limit;
1416 if (__rstn_tree_add(&key, &value, FALSE) != STC_ERROR_NONE)
1421 FREE(key.subscriber_id);
1425 static void __fill_restritions_list(void)
1427 table_restrictions_foreach(__insert_restriction_cb, NULL);
1430 __rstn_tree_printall();
1433 static gboolean __add_rstn_foreach_application(gpointer key,
1437 stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1438 stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1439 gchar *app_id = (gchar *)data;
1441 /* rstn rule is not for applications */
1442 if (rstn_key->app_id == NULL)
1445 /* rstn rule is not for this application */
1446 if (g_strcmp0(rstn_key->app_id, app_id) != 0)
1449 /* rstn rule is already applied */
1450 if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED)
1453 /* add restriction to system */
1454 if (rstn_value->rst_type == STC_RSTN_TYPE_EXCLUDED)
1455 __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, NULL);
1457 __process_restriction(RST_SET, rstn_key, rstn_value, NULL);
1459 __print_rstn(rstn_key, rstn_value);
1465 static void __add_rstns_for_application(gchar *app_id)
1467 g_tree_foreach(g_system->rstns, __add_rstn_foreach_application,
1471 static void __add_application_by_interface(const char *app_id)
1473 stc_app_key_s app_key;
1474 stc_app_value_s app_value;
1477 return; //LCOV_EXCL_LINE
1479 memset(&app_key, 0, sizeof(stc_app_key_s));
1480 memset(&app_value, 0, sizeof(stc_app_value_s));
1482 app_key.pkg_id = g_strdup(app_id);
1483 app_key.app_id = g_strdup(app_id);
1485 app_value.type = STC_APP_TYPE_NONE;
1486 app_value.processes = NULL;
1487 app_value.counter.in_bytes = 0;
1488 app_value.counter.out_bytes = 0;
1490 stc_monitor_application_add(app_key, app_value);
1492 FREE(app_key.pkg_id);
1493 FREE(app_key.app_id);
1496 static int __vconf_get_int(const char *key, int *value)
1500 ret = vconf_get_int(key, value);
1501 if (ret != VCONF_OK) {
1502 STC_LOGE("Failed to get vconfkey [%s] value", key); //LCOV_EXCL_LINE
1503 return -1; //LCOV_EXCL_LINE
1510 static int __vconf_set_int(const char *key, int value)
1514 ret = vconf_set_int(key, value);
1515 if (ret != VCONF_OK) {
1516 STC_LOGE("Failed to set vconfkey [%s] value", key); //LCOV_EXCL_LINE
1517 return -1; //LCOV_EXCL_LINE
1523 static guint __get_background_state(void)
1525 return g_system->background_state;;
1528 static void __set_background_state(guint state)
1530 g_system->background_state = state;
1533 static gboolean __processes_tree_foreach_background(gpointer key,
1537 stc_process_key_s *proc_key = (stc_process_key_s *)key;
1538 stc_app_key_s *app_key = (stc_app_key_s *)data;
1540 if (g_system->background_state)
1541 place_pids_to_net_cgroup(proc_key->pid, STC_BACKGROUND_APP_ID);
1543 place_pids_to_net_cgroup(proc_key->pid, app_key->app_id);
1548 static gboolean __apps_tree_foreach_background(gpointer key, gpointer value,
1551 stc_app_key_s *app_key = (stc_app_key_s *)key;
1552 stc_app_value_s *app_value = (stc_app_value_s *)value;
1554 if (strstr(app_key->app_id, STC_BACKGROUND_APP_SUFFIX))
1555 g_tree_foreach(app_value->processes,
1556 __processes_tree_foreach_background, app_key);
1561 static stc_error_e __process_update_background(void)
1563 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1565 g_tree_foreach(g_system->apps, __apps_tree_foreach_background, NULL);
1567 return STC_ERROR_NONE;
1571 static void __fill_exceptions_list(void)
1573 stc_plugin_fill_exception_list();
1576 stc_error_e stc_monitor_init(void)
1578 stc_system_s *system = MALLOC0(stc_system_s, 1);
1579 GIOChannel *gio = NULL;
1581 ret_value_msg_if(system == NULL, STC_ERROR_OUT_OF_MEMORY, "stc_system_s malloc fail!");
1583 /* initializing current classid */
1584 init_current_classid();
1586 /* initializing cgroups */
1589 /* creating monitored application tree */
1590 system->apps = g_tree_new_full(__apps_tree_key_compare, NULL,
1591 __apps_tree_key_free,
1592 __apps_tree_value_free);
1594 system->rstns = g_tree_new_full(__rstns_tree_key_compare, NULL,
1595 __rstns_tree_key_free,
1596 __rstns_tree_value_free);
1598 /* create netlink socket for updating kernel counters */
1599 system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
1600 if (system->contr_sock < 0) {
1601 STC_LOGE("failed to open socket"); //LCOV_EXCL_LINE
1602 FREE(system); //LCOV_EXCL_LINE
1603 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
1606 gio = g_io_channel_unix_new(system->contr_sock);
1607 system->contr_gsource_id =
1608 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
1609 (GIOFunc) __process_contr_reply,
1611 g_io_channel_unref(gio);
1615 __add_application_by_interface(STC_TOTAL_DATACALL);
1616 __add_application_by_interface(STC_TOTAL_WIFI);
1617 __add_application_by_interface(STC_TOTAL_BLUETOOTH);
1618 __add_application_by_interface(STC_TOTAL_IPV4);
1619 __add_application_by_interface(STC_TOTAL_IPV6);
1621 /* creating restriction rules tree */
1622 __update_contr_cb(NULL);
1624 /* registering periodic kernel counters update callback */
1625 g_system->contr_timer_id = g_timeout_add_seconds(CONTR_TIMER_INTERVAL,
1628 if (g_system->contr_timer_id == 0) {
1629 STC_LOGE("Failed to register kernel counters update timer"); //LCOV_EXCL_LINE
1630 __close_contr_sock(g_system); //LCOV_EXCL_LINE
1631 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
1634 __vconf_get_int(VCONFKEY_STC_BACKGROUND_STATE,
1635 (int *)&g_system->background_state);
1637 __fill_exceptions_list();
1638 __fill_restritions_list();
1640 return STC_ERROR_NONE;
1643 stc_error_e stc_monitor_deinit(void)
1645 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1647 /* close netlink socket for updating kernel counters */
1648 __close_contr_sock(g_system);
1650 /* remove kernel counters update timer */
1651 if (g_system->contr_timer_id > 0) {
1652 g_source_remove(g_system->contr_timer_id);
1653 g_system->contr_timer_id = 0;
1656 /* destroy monitored application tree */
1657 g_tree_destroy(g_system->apps);
1658 g_system->apps = NULL;
1660 /* destroy restriction rules tree */
1661 g_tree_destroy(g_system->rstns);
1662 g_system->rstns = NULL;
1666 return STC_ERROR_NONE;
1669 API stc_error_e stc_monitor_application_add(const stc_app_key_s app_key,
1670 const stc_app_value_s app_value)
1672 stc_error_e ret = STC_ERROR_NONE;
1674 stc_app_value_s *value;
1675 stc_app_value_s *lookup;
1677 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1679 lookup = __application_lookup(g_system->apps, &app_key);
1681 STC_LOGD("app_key already present"); //LCOV_EXCL_LINE
1682 return STC_ERROR_NONE; //LCOV_EXCL_LINE
1685 key = MALLOC0(stc_app_key_s, 1);
1687 STC_LOGE("key allocation failed"); //LCOV_EXCL_LINE
1688 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
1691 value = MALLOC0(stc_app_value_s, 1);
1693 STC_LOGE("value allocation failed"); //LCOV_EXCL_LINE
1694 FREE(key); //LCOV_EXCL_LINE
1695 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
1698 key->app_id = g_strdup(app_key.app_id);
1699 key->pkg_id = g_strdup(app_key.pkg_id);
1701 value->type = app_value.type;
1702 value->data_usage.in_bytes = app_value.data_usage.in_bytes;
1703 value->data_usage.out_bytes = app_value.data_usage.out_bytes;
1705 value->processes = g_tree_new_full(__processes_tree_key_compare, NULL,
1706 __processes_tree_key_free,
1707 __processes_tree_value_free);
1709 /* create cgroup and update classid */
1710 value->classid = get_classid_by_app_id(app_key.app_id, TRUE);
1712 g_tree_insert(g_system->apps, key, value);
1714 /* add nfacct rule for this classid */
1715 __add_application_monitor(key, value, stc_get_default_connection());
1716 __add_rstns_for_application(app_key.app_id);
1721 API stc_error_e stc_monitor_process_add(const stc_app_key_s app_key,
1722 const stc_process_key_s proc_key,
1723 const stc_process_value_s proc_value)
1725 stc_error_e ret = STC_ERROR_NONE;
1726 stc_app_value_s *app_lookup;
1727 stc_process_key_s *key;
1728 stc_process_value_s *value;
1729 stc_process_value_s *proc_lookup;
1731 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1733 app_lookup = __application_lookup(g_system->apps, &app_key);
1735 STC_LOGD("app_key not found"); //LCOV_EXCL_LINE
1736 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
1739 proc_lookup = __process_lookup(app_lookup->processes, &proc_key);
1741 STC_LOGD("proc_key already present"); //LCOV_EXCL_LINE
1742 return STC_ERROR_NONE; //LCOV_EXCL_LINE
1745 key = MALLOC0(stc_process_key_s, 1);
1747 STC_LOGE("key allocation failed"); //LCOV_EXCL_LINE
1748 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
1751 value = MALLOC0(stc_process_value_s, 1);
1753 STC_LOGE("value allocation failed"); //LCOV_EXCL_LINE
1754 FREE(key); //LCOV_EXCL_LINE
1755 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
1758 key->pid = proc_key.pid;
1760 value->ground = proc_value.ground;
1762 g_tree_insert(app_lookup->processes, key, value);
1764 /* add pid to application cgroup */
1765 place_pids_to_net_cgroup(proc_key.pid, app_key.app_id);
1768 __apps_tree_printall(); //LCOV_EXCL_LINE
1773 API stc_error_e stc_monitor_process_remove(pid_t pid)
1775 stc_error_e ret = STC_ERROR_NONE;
1776 stc_process_key_s proc_key = {
1780 remove_pid_context_s context = {
1782 .proc_key = &proc_key,
1783 .entry_removed = FALSE,
1786 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1788 g_tree_foreach(g_system->apps, __apps_tree_foreach_remove_pid,
1791 if (context.entry_removed)
1792 __application_remove_if_empty(context.app_key);
1795 __apps_tree_printall(); //LCOV_EXCL_LINE
1801 API stc_error_e stc_monitor_process_update_ground(const stc_app_key_s app_key,
1802 const stc_process_key_s proc_key,
1803 stc_app_state_e ground)
1805 stc_error_e ret = STC_ERROR_NONE;
1806 stc_app_value_s *app_lookup;
1807 stc_process_value_s *proc_lookup;
1809 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1811 app_lookup = __application_lookup(g_system->apps, &app_key);
1813 STC_LOGD("app_key not found");
1814 return STC_ERROR_FAIL;
1817 proc_lookup = __process_lookup(app_lookup->processes, &proc_key);
1819 STC_LOGD("proc_key not found");
1820 return STC_ERROR_FAIL;
1823 if (proc_lookup->ground != ground)
1824 proc_lookup->ground = ground;
1826 if (ground == STC_APP_STATE_BACKGROUND && __get_background_state())
1827 place_pids_to_net_cgroup(proc_key.pid, STC_BACKGROUND_APP_ID);
1829 place_pids_to_net_cgroup(proc_key.pid, app_key.app_id);
1835 void stc_monitor_update_rstn_by_default_connection(void *data)
1837 static default_connection_s old_connection;
1838 default_connection_s *new_connection = (default_connection_s *)data;
1840 if (old_connection.path != NULL) {
1843 g_tree_foreach(g_system->apps,
1844 __remove_application_monitor,
1845 (gpointer)&old_connection);
1847 if (g_system->rstns)
1848 g_tree_foreach(g_system->rstns,
1849 __remove_restriction,
1850 (gpointer)&old_connection);
1852 iptables_flush_chains();
1856 FREE(old_connection.path);
1857 FREE(old_connection.ifname);
1858 old_connection.type = 0;
1859 old_connection.roaming = 0;
1861 if (new_connection != NULL && new_connection->path != NULL) {
1863 g_tree_foreach(g_system->apps,
1864 __add_application_monitor,
1865 (gpointer)new_connection);
1867 if (g_system->rstns)
1868 g_tree_foreach(g_system->rstns, __add_restriction,
1871 old_connection.path = g_strdup(new_connection->path);
1872 old_connection.ifname = g_strdup(new_connection->ifname);
1873 old_connection.type = new_connection->type;
1874 old_connection.roaming = new_connection->roaming;
1878 stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info)
1883 stc_rstn_value_s value;
1885 memset(&key, 0, sizeof(stc_rstn_key_s));
1886 memset(&value, 0, sizeof(stc_rstn_value_s));
1888 key.app_id = g_strdup(info->app_id);
1889 key.ifname = g_strdup(info->ifname);
1890 key.subscriber_id = g_strdup(info->subscriber_id);
1891 key.iftype = info->iftype;
1892 key.roaming = info->roaming;
1894 value.rst_type = info->rst_type;
1895 value.rst_state = STC_RESTRICTION_UNKNOWN;
1896 value.restriction_id = info->restriction_id;
1899 value.classid = get_classid_by_app_id(info->app_id, TRUE);
1901 value.classid = STC_UNKNOWN_CLASSID;
1903 if (value.classid == STC_BACKGROUND_APP_CLASSID) {
1904 __set_background_state(TRUE); //LCOV_EXCL_LINE
1905 __vconf_set_int(VCONFKEY_STC_BACKGROUND_STATE, g_system->background_state); //LCOV_EXCL_LINE
1906 __process_update_background(); //LCOV_EXCL_LINE
1909 value.data_limit = info->data_limit;
1910 value.data_warn_limit = info->data_warn_limit;
1912 ret = __rstn_tree_add(&key, &value, TRUE);
1916 FREE(key.subscriber_id);
1920 stc_error_e stc_monitor_rstns_tree_remove(const table_restrictions_info *info)
1924 stc_rstn_key_s key = {
1925 .app_id = g_strdup(info->app_id),
1926 .ifname = g_strdup(info->ifname),
1927 .subscriber_id = g_strdup(info->subscriber_id),
1928 .iftype = info->iftype,
1929 .roaming = info->roaming,
1932 if (!strcmp(key.app_id, STC_BACKGROUND_APP_ID)) {
1933 __set_background_state(FALSE); //LCOV_EXCL_LINE
1934 __vconf_set_int(VCONFKEY_STC_BACKGROUND_STATE, g_system->background_state); //LCOV_EXCL_LINE
1935 __process_update_background(); //LCOV_EXCL_LINE
1938 ret = __rstn_tree_remove(&key);
1942 FREE(key.subscriber_id);
1946 API stc_error_e stc_monitor_check_excn_by_cmdline(char *cmdline)
1948 return stc_plugin_check_exception_by_cmdline(cmdline);
1951 int stc_monitor_get_counter_socket(void)
1953 return g_system->contr_sock;