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] 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->classid,
39 app_value->data_usage.in_bytes,
40 app_value->data_usage.out_bytes);
43 static void __app_update_statistics(gpointer key,
44 gpointer value, gpointer data)
46 stc_app_value_s *app_value = (stc_app_value_s *)value;
47 time_t *touch_time = (time_t *)data;
48 stc_db_classid_iftype_key stat_key;
49 stc_db_app_stats stat;
50 default_connection_s *default_connection = stc_get_default_connection();
52 memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key));
53 memset(&stat, 0 , sizeof(stc_db_app_stats));
55 /* Do not update statistics for Tethering
56 * if tethering is in-active found */
57 if (default_connection &&
58 default_connection->tether_state == FALSE &&
59 !strcmp(app_value->app_id, STC_TOTAL_TETHERING))
62 /* Do not update statistics for Wi-Fi
63 * if tethering is active on wlan0 iface */
64 if (default_connection && default_connection->tether_state &&
65 default_connection->tether_iface.type == STC_IFACE_WIFI &&
66 !strcmp(app_value->app_id, STC_TOTAL_WIFI))
69 stat_key.classid = app_value->classid;
71 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
72 default_connection->tether_state == TRUE)
73 stat_key.iftype = default_connection->tether_iface.type;
74 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
75 stat_key.iftype = default_connection->tether_iface.type;
77 stat_key.iftype = default_connection->type;
79 if (STC_IFACE_DATACALL == stat_key.iftype)
80 stat_key.subscriber_id = g_strdup(default_connection->subscriber_id);
82 stat_key.subscriber_id = g_strdup(SUBSCRIBERID_NONE);
84 if (app_value->classid == STC_TETHERING_APP_CLASSID &&
85 default_connection->tether_state == TRUE)
86 g_strlcpy(stat_key.ifname, default_connection->tether_iface.ifname,
88 else if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX))
89 g_strlcpy(stat_key.ifname, default_connection->tether_iface.ifname,
92 g_strlcpy(stat_key.ifname, default_connection->ifname,
95 stat.app_id = g_strdup(app_value->app_id);
96 stat.snd_count = app_value->counter.out_bytes;
97 stat.rcv_count = app_value->counter.in_bytes;
98 stat.is_roaming = default_connection->roaming;
100 if (strstr(stat.app_id, "_BACKGROUND")) {
101 stat.ground = STC_APP_STATE_BACKGROUND;
103 if (strstr(stat.app_id, "TOTAL_"))
104 stat.ground = STC_APP_STATE_UNKNOWN;
106 stat.ground = STC_APP_STATE_FOREGROUND;
109 table_statistics_insert(&stat_key, &stat, *touch_time);
111 app_value->counter.out_bytes = 0;
112 app_value->counter.in_bytes = 0;
115 FREE(stat_key.subscriber_id);
120 static gboolean __add_app_monitor_for_tethering(gpointer key,
121 gpointer value, gpointer data)
123 stc_app_value_s *app_value = (stc_app_value_s *)value;
124 default_connection_s *connection = (default_connection_s *)data;
125 stc_s *stc = stc_get_manager();
126 struct nfacct_rule counter;
130 STC_LOGI("Add appid(%s) classid(%d)", app_value->app_id,
133 if (stc == NULL || connection == NULL)
137 stc->carg = MALLOC0(counter_arg_s, 1);
138 if (stc->carg == NULL)
141 stc->carg->sock = stc_monitor_get_contr_sock();
144 memset(&counter, 0, sizeof(struct nfacct_rule));
146 counter.carg = stc->carg;
147 counter.classid = app_value->classid;
148 counter.intend = NFACCT_TETH_COUNTER;
150 if (connection->tether_state != TRUE ||
151 connection->tether_iface.ifname == NULL)
154 counter.iftype = connection->tether_iface.type;
155 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
157 /* get the ip address of the station based on its mac address */
158 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
159 if (ret != STC_ERROR_NONE)
162 /* tethering iptables rule */
163 stc_monitor_tether_add_in(&counter, ipaddr);
164 stc_monitor_tether_add_out(&counter, ipaddr);
170 static gboolean __remove_app_monitor_for_tethering(gpointer key,
171 gpointer value, gpointer data)
173 stc_app_value_s *app_value = (stc_app_value_s *)value;
174 default_connection_s *connection = (default_connection_s *)data;
175 stc_s *stc = stc_get_manager();
176 struct nfacct_rule counter;
180 STC_LOGI("Remove appid(%s) classid(%d)", app_value->app_id,
183 if (stc == NULL || connection == NULL)
187 stc->carg = MALLOC0(counter_arg_s, 1);
188 if (stc->carg == NULL)
191 stc->carg->sock = stc_monitor_get_contr_sock();
194 memset(&counter, 0, sizeof(struct nfacct_rule));
196 counter.carg = stc->carg;
197 counter.classid = app_value->classid;
198 counter.intend = NFACCT_TETH_COUNTER;
200 if (connection->tether_state != TRUE ||
201 connection->tether_iface.ifname == NULL)
204 counter.iftype = connection->tether_iface.type;
205 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
207 /* get the ip address of the station based on its mac address */
208 ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
209 if (ret != STC_ERROR_NONE)
212 stc_monitor_tether_del_in(&counter, ipaddr);
213 stc_monitor_tether_del_out(&counter, ipaddr);
219 static void __app_value_destroy(gpointer data)
221 stc_app_value_s *app_value = (stc_app_value_s *)data;
223 FREE(app_value->pkg_id);
224 FREE(app_value->app_id);
225 g_hash_table_destroy(app_value->processes);
226 app_value->processes = NULL;
231 static void __check_rstn_limit_exceeded(gpointer data,
234 stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
235 int32_t *limit_exceeded = (int32_t *)user_data;
237 if (rstn_data->limit_exceeded != 0)
238 *limit_exceeded = rstn_data->limit_exceeded;
241 static void __app_update_counter(classid_bytes_context_s *context,
244 stc_app_value_s *lookup_app;
245 stc_rstn_value_s *lookup_rstn;
246 GHashTable *apps = stc_monitor_get_system_apps();
247 GHashTable *rstns = stc_monitor_get_system_rstns();
252 lookup_rstn = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
254 int32_t limit_exceeded = 0;
255 g_slist_foreach(lookup_rstn->rules,
256 __check_rstn_limit_exceeded, &limit_exceeded);
258 if (limit_exceeded != 0)
265 lookup_app = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
267 stc_monitor_app_update_counter(lookup_app, context);
270 void stc_monitor_app_update_counter(stc_app_value_s *value,
271 classid_bytes_context_s *context)
273 switch (context->counter->iotype) {
274 case NFACCT_COUNTER_IN:
275 value->data_usage.in_bytes += context->bytes;
276 value->counter.in_bytes = context->bytes;
277 stc_monitor_set_apps_updated(TRUE);
280 case NFACCT_COUNTER_OUT:
281 value->data_usage.out_bytes += context->bytes;
282 value->counter.out_bytes = context->bytes;
283 stc_monitor_set_apps_updated(TRUE);
287 STC_LOGE("Unknown iotype");
291 void stc_monitor_app_update_iface_counter(classid_bytes_context_s *context)
293 switch (context->counter->iftype) {
294 case STC_IFACE_DATACALL:
295 __app_update_counter(context, STC_TOTAL_DATACALL_CLASSID);
298 __app_update_counter(context, STC_TOTAL_WIFI_CLASSID);
299 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
301 case STC_IFACE_BLUETOOTH:
302 __app_update_counter(context, STC_TOTAL_BLUETOOTH_CLASSID);
303 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
306 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
309 __app_update_counter(context, STC_TETHERING_APP_CLASSID);
316 gboolean stc_monitor_app_flush_stats_to_db(gpointer user_data)
318 time_t current_time = 0;
319 stc_s *stc = stc_get_manager();
320 GHashTable *apps = stc_monitor_get_system_apps();
321 gboolean apps_updated = stc_monitor_get_apps_updated();
323 if (stc && stc->carg)
324 current_time = stc->carg->last_run_time;
326 if (apps_updated == FALSE)
327 return G_SOURCE_REMOVE;
329 stc_monitor_set_apps_updated(FALSE);
332 g_hash_table_foreach(apps,
333 __app_update_statistics,
336 STC_LOGI("Flushed app stats to database");
337 return G_SOURCE_REMOVE;
340 API stc_error_e stc_monitor_app_add(uint32_t classid,
343 const stc_app_value_s value)
345 stc_app_value_s *app_value;
346 stc_app_value_s *lookup_value;
348 GHashTable *apps = stc_monitor_get_system_apps();
351 return STC_ERROR_NO_DATA;
353 if (classid == STC_UNKNOWN_CLASSID)
354 classid = get_classid_by_app_id(app_id, TRUE);
356 lookup_value = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
359 STC_LOGE("Already exists [\033[1;36m%d\033[0;m:"
360 "\033[0;32m%s\033[0;m]", classid, app_id);
361 return STC_ERROR_NONE;
364 app_value = MALLOC0(stc_app_value_s, 1);
367 STC_LOGE("Value allocation failed");
368 return STC_ERROR_OUT_OF_MEMORY;
371 /* create cgroup and update classid */
372 app_value->classid = classid;
374 app_value->app_id = g_strdup(app_id);
375 app_value->pkg_id = g_strdup(pkg_id);
377 app_value->type = value.type;
378 app_value->data_usage.in_bytes = value.data_usage.in_bytes;
379 app_value->data_usage.out_bytes = value.data_usage.out_bytes;
380 g_strlcpy(app_value->mac, value.mac, MAC_ADDRESS_LEN);
382 app_value->processes = g_hash_table_new_full(g_direct_hash,
383 g_direct_equal, NULL, NULL);
385 /* update classid for tethering station based on its mac address */
386 if (g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX) &&
387 classid != STC_TETHERING_APP_CLASSID)
388 stc_plugin_tether_set_station_classid(app_value->mac, classid);
390 g_hash_table_insert(apps, GUINT_TO_POINTER(classid), app_value);
392 /* add nfacct rule for this classid */
393 stc_monitor_app_add_monitor(GUINT_TO_POINTER(classid),
394 app_value, stc_get_default_connection());
395 stc_monitor_rstn_add_for_app(classid);
398 __print_app(GUINT_TO_POINTER(classid), app_value, NULL);
399 STC_LOGD("\033[1;32mApplication added\033[0;m "
400 "[\033[1;36m%d\033[0;m]", classid);
403 return STC_ERROR_NONE;
406 void stc_monitor_app_add_by_iface(const char *ifname)
408 stc_app_value_s app_value;
413 memset(&app_value, 0, sizeof(stc_app_value_s));
415 app_value.type = STC_APP_TYPE_NONE;
416 app_value.processes = NULL;
417 app_value.counter.in_bytes = 0;
418 app_value.counter.out_bytes = 0;
420 stc_monitor_app_add(STC_UNKNOWN_CLASSID, ifname, ifname, app_value);
423 void stc_monitor_app_add_monitor(gpointer key,
424 gpointer value, gpointer data)
426 stc_app_value_s *app_value = (stc_app_value_s *)value;
427 default_connection_s *connection = (default_connection_s *)data;
428 stc_s *stc = stc_get_manager();
430 if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
431 app_value->classid == STC_TOTAL_WIFI_CLASSID ||
432 app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
435 if (stc && connection && connection->ifname) {
436 struct nfacct_rule counter;
439 stc->carg = MALLOC0(counter_arg_s, 1);
440 if (stc->carg == NULL)
443 stc->carg->sock = stc_monitor_get_contr_sock();
446 memset(&counter, 0, sizeof(struct nfacct_rule));
448 counter.carg = stc->carg;
449 counter.classid = app_value->classid;
450 counter.intend = NFACCT_COUNTER;
452 if (connection->tether_state == TRUE &&
453 connection->tether_iface.ifname != NULL &&
454 app_value->classid == STC_TETHERING_APP_CLASSID) {
455 counter.iftype = connection->tether_iface.type;
456 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
458 counter.iftype = connection->type;
459 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
462 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
463 app_value->classid != STC_TETHERING_APP_CLASSID) {
464 __add_app_monitor_for_tethering(key, value, data);
465 } else if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
466 stc_monitor_ipt_add_in(&counter);
467 stc_monitor_ipt_add_out(&counter);
468 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
469 stc_monitor_ip6t_add_in(&counter);
470 stc_monitor_ip6t_add_out(&counter);
472 stc_monitor_ipt_add_in(&counter);
473 stc_monitor_ipt_add_out(&counter);
474 stc_monitor_ip6t_add_in(&counter);
475 stc_monitor_ip6t_add_out(&counter);
480 void stc_monitor_app_add_by_connection(default_connection_s *conn)
482 GHashTable *apps = stc_monitor_get_system_apps();
487 g_hash_table_foreach(apps, stc_monitor_app_add_monitor, conn);
490 API stc_error_e stc_monitor_app_remove(uint32_t classid, const char *app_id)
492 stc_app_value_s *app_lookup;
493 GHashTable *apps = stc_monitor_get_system_apps();
496 return STC_ERROR_NO_DATA;
498 classid = get_classid_by_app_id(app_id, FALSE);
500 app_lookup = g_hash_table_lookup(apps, GUINT_TO_POINTER(classid));
503 STC_LOGD("Application not found [\033[1;36m%d\033[0;m]", classid);
504 return STC_ERROR_FAIL;
507 /* remove nfacct rule for this classid */
508 stc_monitor_app_remove_monitor(GUINT_TO_POINTER(classid),
509 app_lookup, stc_get_default_connection());
511 /* remove ristrictions if any */
512 stc_monitor_rstn_remove_for_app(classid);
515 __print_app(GUINT_TO_POINTER(classid), app_lookup, NULL);
517 /* remove app_key from the stc-manager */
518 g_hash_table_remove(apps, GUINT_TO_POINTER(classid));
520 return STC_ERROR_NONE;
523 void stc_monitor_app_remove_monitor(gpointer key,
524 gpointer value, gpointer data)
526 stc_app_value_s *app_value = (stc_app_value_s *)value;
527 default_connection_s *connection = (default_connection_s *)data;
528 stc_s *stc = stc_get_manager();
530 if (stc && connection && connection->ifname) {
531 struct nfacct_rule counter;
534 stc->carg = MALLOC0(counter_arg_s, 1);
535 if (stc->carg == NULL)
538 stc->carg->sock = stc_monitor_get_contr_sock();
541 memset(&counter, 0, sizeof(struct nfacct_rule));
543 counter.carg = stc->carg;
544 counter.classid = app_value->classid;
545 counter.intend = NFACCT_COUNTER;
547 if (g_str_has_suffix(app_value->app_id, STC_TETHERING_APP_SUFFIX) &&
548 app_value->classid != STC_TETHERING_APP_CLASSID) {
549 __remove_app_monitor_for_tethering(key, value, data);
551 } else if (connection->tether_state == FALSE &&
552 connection->tether_iface.ifname != NULL &&
553 app_value->classid == STC_TETHERING_APP_CLASSID) {
554 counter.iftype = connection->tether_iface.type;
555 g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
557 counter.iftype = connection->type;
558 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
561 stc_monitor_ipt_del_in(&counter);
562 stc_monitor_ipt_del_out(&counter);
563 stc_monitor_ip6t_del_in(&counter);
564 stc_monitor_ip6t_del_out(&counter);
570 void stc_monitor_app_remove_by_connection(default_connection_s *conn)
572 GHashTable *apps = stc_monitor_get_system_apps();
577 g_hash_table_foreach(apps, stc_monitor_app_remove_monitor, conn);
580 GHashTable *stc_monitor_apps_init(void)
582 return g_hash_table_new_full(g_direct_hash, g_direct_equal,
583 NULL, __app_value_destroy);