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-exception.h"
32 #include "stc-manager-plugin-tether.h"
34 static stc_system_s *g_system = NULL;
36 static int __vconf_get_int(const char *key, int *value)
40 ret = vconf_get_int(key, value);
41 if (ret != VCONF_OK) {
42 STC_LOGE("Failed to get vconfkey [%s] value", key);
49 static stc_error_e __close_contr_sock(stc_system_s *system)
51 ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
53 /* close netlink socket for updating kernel counters */
54 if (system->contr_sock != -1) {
55 close(system->contr_sock);
56 system->contr_sock = -1;
59 if (system->contr_gsource_id != 0) {
60 g_source_remove(system->contr_gsource_id);
61 system->contr_gsource_id = 0;
64 return STC_ERROR_NONE;
67 static gboolean __process_contr_reply(GIOChannel *source,
68 GIOCondition condition,
71 static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system)
73 GIOChannel *gio = NULL;
74 ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
76 /* close netlink socket for updating kernel counters */
77 if (system->contr_sock != -1) {
78 close(system->contr_sock);
79 system->contr_sock = -1;
82 if (system->contr_gsource_id != 0) {
83 g_source_remove(system->contr_gsource_id);
84 system->contr_gsource_id = 0;
87 /* create netlink socket for updating kernel counters */
88 system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
89 if (system->contr_sock < 0) {
90 STC_LOGE("failed to open socket");
92 return STC_ERROR_FAIL;
95 gio = g_io_channel_unix_new(system->contr_sock);
96 system->contr_gsource_id =
97 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
98 (GIOFunc) __process_contr_reply,
100 g_io_channel_unref(gio);
102 return STC_ERROR_NONE;
105 static void __check_rstn_limit_exceeded(gpointer data,
108 stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
109 int32_t *limit_exceeded = (int32_t *)user_data;
111 if (rstn_data->limit_exceeded != 0)
112 *limit_exceeded = rstn_data->limit_exceeded;
115 static void __fill_nfacct_result(char *cnt_name, int64_t bytes,
116 struct counter_arg *carg)
118 stc_monitor_rstn_reset_time_counters_if_required();
120 struct nfacct_rule counter = {
127 classid_bytes_context_s context = {
130 .data_limit_exceeded = FALSE,
133 if (!recreate_counter_by_name(cnt_name, &counter)) {
134 STC_LOGE("Can't parse counter name %s", cnt_name);
139 STC_LOGI("classid[\033[1;36m%u\033[0;m] iftype[%u] "
140 "iotype[%d] intend[%d] ifname[%s] bytes[%lld]",
141 context.counter->classid, context.counter->iftype,
142 context.counter->iotype, context.counter->intend,
143 context.counter->ifname, context.bytes);
145 if (context.counter->intend == NFACCT_COUNTER ||
146 context.counter->intend == NFACCT_TETH_COUNTER) {
147 if (g_system->apps) {
148 stc_app_value_s *lookup_app;
149 stc_rstn_value_s *lookup_rstn;
151 stc_monitor_app_update_iface_counter(&context);
153 lookup_app = g_hash_table_lookup(g_system->apps,
154 GUINT_TO_POINTER(context.counter->classid));
156 stc_monitor_app_update_counter(lookup_app, &context);
158 lookup_rstn = g_hash_table_lookup(g_system->rstns,
159 GUINT_TO_POINTER(context.counter->classid));
161 int32_t limit_exceeded = 0;
162 g_slist_foreach(lookup_rstn->rules,
163 __check_rstn_limit_exceeded, &limit_exceeded);
165 if (limit_exceeded != 0)
170 if (g_system->rstns) {
171 stc_rstn_value_s *lookup_value;
172 uint32_t classid = context.counter->classid;
174 stc_monitor_rstn_update_iface_counter(&context);
175 context.counter->classid = classid;
177 lookup_value = g_hash_table_lookup(g_system->rstns,
178 GUINT_TO_POINTER(classid));
180 g_slist_foreach(lookup_value->rules,
181 stc_monitor_rstn_update_counter,
188 static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
191 struct counter_arg *carg = user_data;
192 char *cnt_name = (char *)RTA_DATA(attr_list[NFACCT_NAME]);
193 if (carg->initiate) {
195 * TODO: this will be used when daemon starts to update existing
196 * counter data if present.
198 populate_counters(cnt_name, carg);
202 (int64_t *)RTA_DATA(attr_list[NFACCT_BYTES]);
203 int bytes = be64toh(*bytes_p);
205 ++carg->serialized_counters;
206 __fill_nfacct_result(cnt_name, bytes, carg);
213 static int __post_fill_counters(void *user_data)
215 struct counter_arg *carg = user_data;
223 static void __process_network_counter(struct genl *ans,
224 struct counter_arg *carg)
226 struct netlink_serialization_params ser_params = {
229 .eval_attr = __fill_counters,
230 .post_eval_attr = __post_fill_counters,
233 netlink_serialization_command *netlink =
234 netlink_create_command(&ser_params);
236 STC_LOGE("Can not create command");
240 netlink->deserialize_answer(&(netlink->params));
243 static gboolean __process_contr_reply(GIOChannel *source,
244 GIOCondition condition,
247 int sock = g_io_channel_unix_get_fd(source);
250 stc_s *stc = stc_get_manager();
253 void __gcov_flush(void);
257 if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
258 (condition & G_IO_NVAL)) {
259 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
261 STC_LOGE("Counter socket received G_IO event, closing socket."
262 "G_IO_ERR [%u], G_IO_HUP [%u], G_IO_NVAL [%u]",
263 (condition & G_IO_ERR), (condition & G_IO_HUP),
264 (condition & G_IO_NVAL));
265 __close_and_reopen_contr_sock(g_system);
269 ans = MALLOC0(struct genl, 1);
271 STC_LOGE("Failed allocate memory to genl reply message");
276 STC_LOGE("Can't get stc data");
280 ret = read_netlink(sock, ans, sizeof(struct genl));
285 stc->carg->ans_len = ret;
286 stc->carg->last_run_time = time(NULL);
288 __process_network_counter(ans, stc->carg);
290 g_idle_add(stc_monitor_app_flush_stats_to_db, NULL);
291 g_idle_add(stc_monitor_rstn_flush_contr_to_db, NULL);
298 static gboolean __update_contr_cb(void *user_data)
300 /* Here we just sent command, answer we receive in another callback */
301 stc_s *stc = stc_get_manager();
302 ret_value_msg_if(stc == NULL, STC_ERROR_FAIL, "Can't get stc data");
304 stc->carg = MALLOC0(counter_arg_s, 1);
305 if (stc->carg == NULL)
306 return TRUE; /* we need to continue the timer */
308 stc->carg->sock = g_system->contr_sock;
312 void __gcov_flush(void);
316 /* STC_LOGD("Get all counters"); */
317 nfacct_send_get_all(stc->carg);
319 /* we need to continue the timer */
323 static void __fill_exceptions_list(void)
325 stc_plugin_fill_exception_list();
328 stc_error_e stc_monitor_init(void)
330 stc_system_s *system = MALLOC0(stc_system_s, 1);
331 GIOChannel *gio = NULL;
333 ret_value_msg_if(system == NULL, STC_ERROR_OUT_OF_MEMORY,
334 "stc_system_s malloc fail!");
336 /* initializing current classid */
337 init_current_classid();
339 /* initializing cgroups */
342 /* creating monitored application tree */
343 system->apps = stc_monitor_apps_init();
344 system->rstns = stc_monitor_rstns_init();
346 /* create netlink socket for updating kernel counters */
347 system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
348 if (system->contr_sock < 0) {
349 STC_LOGE("failed to open socket");
351 return STC_ERROR_FAIL;
354 gio = g_io_channel_unix_new(system->contr_sock);
355 system->contr_gsource_id =
356 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
357 (GIOFunc) __process_contr_reply,
359 g_io_channel_unref(gio);
363 stc_monitor_app_add_by_iface(STC_TOTAL_DATACALL);
364 stc_monitor_app_add_by_iface(STC_TOTAL_WIFI);
365 stc_monitor_app_add_by_iface(STC_TOTAL_BLUETOOTH);
366 stc_monitor_app_add_by_iface(STC_TOTAL_IPV4);
367 stc_monitor_app_add_by_iface(STC_TOTAL_IPV6);
368 /* stc_monitor_app_add_by_iface(STC_TOTAL_TETHERING); */
370 __update_contr_cb(NULL);
372 /* registering periodic kernel counters update callback */
373 g_system->contr_timer_id = g_timeout_add_seconds(CONTR_TIMER_INTERVAL,
376 if (g_system->contr_timer_id == 0) {
377 STC_LOGE("Failed to register kernel counters update timer");
378 __close_contr_sock(g_system);
379 return STC_ERROR_FAIL;
382 __vconf_get_int(VCONFKEY_STC_BACKGROUND_STATE,
383 (int *)&g_system->background_state);
385 __fill_exceptions_list();
386 stc_monitor_rstns_load();
388 return STC_ERROR_NONE;
391 stc_error_e stc_monitor_deinit(void)
393 ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
395 /* close netlink socket for updating kernel counters */
396 __close_contr_sock(g_system);
398 /* remove kernel counters update timer */
399 if (g_system->contr_timer_id > 0) {
400 g_source_remove(g_system->contr_timer_id);
401 g_system->contr_timer_id = 0;
404 /* destroy monitored application tree */
405 g_hash_table_destroy(g_system->apps);
406 g_system->apps = NULL;
408 /* destroy restriction rules tree */
409 g_hash_table_destroy(g_system->rstns);
410 g_system->rstns = NULL;
414 return STC_ERROR_NONE;
417 GHashTable *stc_monitor_get_system_apps(void)
419 ret_value_msg_if(g_system == NULL, NULL,
420 "stc monitor not initialized!");
422 ret_value_msg_if(g_system->apps == NULL, NULL,
425 return g_system->apps;
428 GHashTable *stc_monitor_get_system_rstns(void)
430 ret_value_msg_if(g_system == NULL, NULL,
431 "stc monitor not initialized!");
433 ret_value_msg_if(g_system->rstns == NULL, NULL,
436 return g_system->rstns;
439 int stc_monitor_get_contr_sock(void)
441 ret_value_msg_if(g_system == NULL, 0,
442 "stc monitor not initialized!");
444 return g_system->contr_sock;
447 time_t stc_monitor_get_last_month_ts(void)
449 ret_value_msg_if(g_system == NULL, 0,
450 "stc monitor not initialized!");
452 return g_system->last_month_ts;
455 void stc_monitor_set_last_month_ts(time_t time)
457 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
459 g_system->last_month_ts = time;
462 time_t stc_monitor_get_last_week_ts(void)
464 ret_value_msg_if(g_system == NULL, 0,
465 "stc monitor not initialized!");
467 return g_system->last_week_ts;
470 void stc_monitor_set_last_week_ts(time_t time)
472 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
474 g_system->last_week_ts = time;
477 time_t stc_monitor_get_last_day_ts(void)
479 ret_value_msg_if(g_system == NULL, 0,
480 "stc monitor not initialized!");
482 return g_system->last_day_ts;
485 void stc_monitor_set_last_day_ts(time_t time)
487 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
489 g_system->last_day_ts = time;
492 void stc_monitor_set_rstns_updated(gboolean value)
494 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
496 g_system->rstns_updated = value;
499 gboolean stc_monitor_get_rstns_updated(void)
501 ret_value_msg_if(g_system == NULL, FALSE,
502 "stc monitor not initialized!");
504 return g_system->rstns_updated;
507 void stc_monitor_set_apps_updated(gboolean value)
509 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
511 g_system->apps_updated = value;
514 gboolean stc_monitor_get_apps_updated(void)
516 ret_value_msg_if(g_system == NULL, FALSE,
517 "stc monitor not initialized!");
519 return g_system->apps_updated;
522 void stc_monitor_set_background_state(gboolean value)
524 ret_msg_if(g_system == NULL, "stc monitor not initialized!");
526 g_system->background_state = value;
529 gboolean stc_monitor_get_background_state(void)
531 ret_value_msg_if(g_system == NULL, FALSE,
532 "stc monitor not initialized!");
534 return g_system->background_state;
537 void stc_monitor_update_by_default_connection(void *data)
539 static default_connection_s old_connection;
540 default_connection_s *new_connection = (default_connection_s *)data;
542 if (old_connection.path != NULL) {
543 stc_monitor_app_remove_by_connection(&old_connection);
544 stc_monitor_rstn_remove_by_connection(&old_connection);
546 iptables_flush_chains();
549 FREE(old_connection.path);
550 FREE(old_connection.ifname);
551 FREE(old_connection.tether_iface.ifname);
552 old_connection.type = 0;
553 old_connection.roaming = 0;
554 old_connection.tether_state = FALSE;
555 old_connection.tether_iface.type = 0;
557 if (new_connection != NULL && new_connection->path != NULL) {
558 stc_monitor_app_add_by_connection(new_connection);
559 stc_monitor_rstn_add_by_connection(new_connection);
561 old_connection.path = g_strdup(new_connection->path);
562 old_connection.ifname = g_strdup(new_connection->ifname);
563 old_connection.tether_iface.ifname = g_strdup(new_connection->tether_iface.ifname);
564 old_connection.type = new_connection->type;
565 old_connection.roaming = new_connection->roaming;
566 old_connection.tether_state = new_connection->tether_state;
567 old_connection.tether_iface.type = new_connection->tether_iface.type;
571 API stc_error_e stc_monitor_check_excn_by_cmdline(char *cmdline)
573 return stc_plugin_check_exception_by_cmdline(cmdline);