Separate monitoring function plugin
[platform/core/connectivity/stc-manager.git] / plugin / monitor / stc-plugin-monitor.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <linux/netlink.h>
18 #include <vconf.h>
19 #include <vconf-keys.h>
20
21 #include "helper-nl.h"
22 #include "helper-nfacct-rule.h"
23 #include "helper-net-cls.h"
24 #include "helper-cgroup.h"
25 #include "helper-iptables.h"
26 #include "counter.h"
27 #include "table-statistics.h"
28 #include "table-counters.h"
29 #include "stc-plugin-monitor.h"
30 #include "stc-plugin-monitor-connection.h"
31 #include "stc-plugin-monitor-rstn.h"
32 #include "stc-manager-plugin-exception.h"
33
34 static stc_system_s *g_system = NULL;
35
36 static int __vconf_get_int(const char *key, int *value)
37 {
38         int ret = 0;
39
40         ret = vconf_get_int(key, value);
41         if (ret != VCONF_OK) {
42                 STC_LOGE("Failed to get vconfkey [%s] value", key);
43                 return -1;
44         }
45
46         return 0;
47 }
48
49 static stc_error_e __close_contr_sock(stc_system_s *system)
50 {
51         ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
52
53         /* close netlink socket for updating kernel counters */
54         if (system->contr_sock != -1) {
55                 close(system->contr_sock);
56                 system->contr_sock = -1;
57         }
58
59         if (system->contr_gsource_id != 0) {
60                 g_source_remove(system->contr_gsource_id);
61                 system->contr_gsource_id = 0;
62         }
63
64         return STC_ERROR_NONE;
65 }
66
67 static gboolean __process_contr_reply(GIOChannel *source,
68                                       GIOCondition condition,
69                                       gpointer user_data);
70
71 static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system)
72 {
73         GIOChannel *gio = NULL;
74         ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
75
76         /* close netlink socket for updating kernel counters */
77         if (system->contr_sock != -1) {
78                 close(system->contr_sock);
79                 system->contr_sock = -1;
80         }
81
82         if (system->contr_gsource_id != 0) {
83                 g_source_remove(system->contr_gsource_id);
84                 system->contr_gsource_id = 0;
85         }
86
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");
91                 FREE(system);
92                 return STC_ERROR_FAIL;
93         }
94
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,
99                                NULL);
100         g_io_channel_unref(gio);
101
102         return STC_ERROR_NONE;
103 }
104
105 static void __check_rstn_limit_exceeded(gpointer data,
106                                 gpointer user_data)
107 {
108         stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
109         int32_t *limit_exceeded = (int32_t *)user_data;
110
111         if (rstn_data->limit_exceeded != 0)
112                 *limit_exceeded = rstn_data->limit_exceeded;
113 }
114
115 static void __fill_nfacct_result(char *cnt_name, int64_t bytes,
116                                 struct counter_arg *carg)
117 {
118         stc_monitor_rstn_reset_time_counters_if_required();
119
120         struct nfacct_rule counter = {
121                 .carg = carg,
122                 .name = {0},
123                 .ifname = {0},
124                 0
125         };
126
127         classid_bytes_context_s context = {
128                 .counter = &counter,
129                 .bytes = bytes,
130                 .data_limit_exceeded = FALSE,
131         };
132
133         if (!recreate_counter_by_name(cnt_name, &counter)) {
134                 STC_LOGE("Can't parse counter name %s", cnt_name);
135                 return;
136         }
137
138         if (STC_DEBUG_LOG)
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);
144
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;
150
151                         stc_monitor_app_update_iface_counter(&context);
152
153                         lookup_app = g_hash_table_lookup(g_system->apps,
154                                                 GUINT_TO_POINTER(context.counter->classid));
155                         if (lookup_app)
156                                 stc_monitor_app_update_counter(lookup_app, &context);
157
158                         lookup_rstn = g_hash_table_lookup(g_system->rstns,
159                                                 GUINT_TO_POINTER(context.counter->classid));
160                         if (lookup_rstn) {
161                                 int32_t limit_exceeded = 0;
162                                 g_slist_foreach(lookup_rstn->rules,
163                                         __check_rstn_limit_exceeded, &limit_exceeded);
164
165                                 if (limit_exceeded != 0)
166                                         return;
167                         }
168                 }
169
170                 if (g_system->rstns) {
171                         stc_rstn_value_s *lookup_value;
172                         uint32_t classid = context.counter->classid;
173
174                         stc_monitor_rstn_update_iface_counter(&context);
175                         context.counter->classid = classid;
176
177                         lookup_value = g_hash_table_lookup(g_system->rstns,
178                                                         GUINT_TO_POINTER(classid));
179                         if (lookup_value) {
180                                 g_slist_foreach(lookup_value->rules,
181                                         stc_monitor_rstn_update_counter,
182                                         &context);
183                         }
184                 }
185         }
186 }
187
188 static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
189                            void *user_data)
190 {
191         struct counter_arg *carg = user_data;
192         char *cnt_name = (char *)RTA_DATA(attr_list[NFACCT_NAME]);
193         if (carg->initiate) {
194                 /**
195                  * TODO: this will be used when daemon starts to update existing
196                  * counter data if present.
197                  *
198                  populate_counters(cnt_name, carg);
199                  */
200         } else {
201                 int64_t *bytes_p =
202                         (int64_t *)RTA_DATA(attr_list[NFACCT_BYTES]);
203                 int bytes = be64toh(*bytes_p);
204                 if (bytes) {
205                         ++carg->serialized_counters;
206                         __fill_nfacct_result(cnt_name, bytes, carg);
207                 }
208         }
209
210         return 0;
211 }
212
213 static int __post_fill_counters(void *user_data)
214 {
215         struct counter_arg *carg = user_data;
216
217         if (carg->initiate)
218                 carg->initiate = 0;
219
220         return 0;
221 }
222
223 static void __process_network_counter(struct genl *ans,
224                                       struct counter_arg *carg)
225 {
226         struct netlink_serialization_params ser_params = {
227                 .carg = carg,
228                 .ans = ans,
229                 .eval_attr = __fill_counters,
230                 .post_eval_attr = __post_fill_counters,
231         };
232
233         netlink_serialization_command *netlink =
234                 netlink_create_command(&ser_params);
235         if (!netlink) {
236                 STC_LOGE("Can not create command");
237                 return;
238         }
239
240         netlink->deserialize_answer(&(netlink->params));
241 }
242
243 static gboolean __process_contr_reply(GIOChannel *source,
244                                       GIOCondition condition,
245                                       gpointer user_data)
246 {
247         int sock = g_io_channel_unix_get_fd(source);
248         struct genl *ans;
249         int ret;
250         stc_s *stc = stc_get_manager();
251
252 #ifdef TIZEN_GTESTS
253         void __gcov_flush(void);
254         __gcov_flush();
255 #endif
256
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 */
260
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);
266                 return FALSE;
267         }
268
269         ans = MALLOC0(struct genl, 1);
270         if (ans == NULL) {
271                 STC_LOGE("Failed allocate memory to genl reply message");
272                 return TRUE;
273         }
274
275         if (stc == NULL) {
276                 STC_LOGE("Can't get stc data");
277                 goto out;
278         }
279
280         ret = read_netlink(sock, ans, sizeof(struct genl));
281
282         if (ret == 0)
283                 goto out;
284
285         stc->carg->ans_len = ret;
286         stc->carg->last_run_time = time(NULL);
287
288         __process_network_counter(ans, stc->carg);
289
290         g_idle_add(stc_monitor_app_flush_stats_to_db, NULL);
291         g_idle_add(stc_monitor_rstn_flush_contr_to_db, NULL);
292 out:
293
294         FREE(ans);
295         return TRUE;
296 }
297
298 static gboolean __update_contr_cb(void *user_data)
299 {
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");
303         if (!stc->carg) {
304                 stc->carg = MALLOC0(counter_arg_s, 1);
305                 if (stc->carg == NULL)
306                         return TRUE;  /* we need to continue the timer */
307
308                 stc->carg->sock = g_system->contr_sock;
309         }
310
311 #ifdef TIZEN_GTESTS
312         void __gcov_flush(void);
313         __gcov_flush();
314 #endif
315
316         /* STC_LOGD("Get all counters"); */
317         nfacct_send_get_all(stc->carg);
318
319         /* we need to continue the timer */
320         return TRUE;
321 }
322
323 static void __fill_exceptions_list(void)
324 {
325         stc_plugin_fill_exception_list();
326 }
327
328 stc_error_e stc_plugin_monitor_initialize(void)
329 {
330         __STC_LOG_FUNC_ENTER__;
331
332         stc_system_s *system = MALLOC0(stc_system_s, 1);
333         GIOChannel *gio = NULL;
334
335         ret_value_msg_if(system == NULL, STC_ERROR_OUT_OF_MEMORY,
336                                 "stc_system_s malloc fail!");
337
338         /* initializing current classid */
339         init_current_classid();
340
341         /* initializing cgroups */
342         cgroup_init();
343
344         /* creating monitored application tree */
345         system->apps = stc_monitor_apps_init();
346         system->rstns = stc_monitor_rstns_init();
347
348         /* create netlink socket for updating kernel counters */
349         system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
350         if (system->contr_sock < 0) {
351                 STC_LOGE("failed to open socket");
352                 FREE(system);
353                 return STC_ERROR_FAIL;
354         }
355
356         gio = g_io_channel_unix_new(system->contr_sock);
357         system->contr_gsource_id =
358                 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
359                                (GIOFunc) __process_contr_reply,
360                                NULL);
361         g_io_channel_unref(gio);
362
363         g_system = system;
364
365         stc_monitor_app_add_by_iface(STC_TOTAL_DATACALL);
366         stc_monitor_app_add_by_iface(STC_TOTAL_WIFI);
367         stc_monitor_app_add_by_iface(STC_TOTAL_BLUETOOTH);
368         stc_monitor_app_add_by_iface(STC_TOTAL_IPV4);
369         stc_monitor_app_add_by_iface(STC_TOTAL_IPV6);
370
371         __update_contr_cb(NULL);
372
373         /* registering periodic kernel counters update callback */
374         g_system->contr_timer_id = g_timeout_add_seconds(CONTR_TIMER_INTERVAL,
375                                                          __update_contr_cb,
376                                                          NULL);
377         if (g_system->contr_timer_id == 0) {
378                 STC_LOGE("Failed to register kernel counters update timer");
379                 __close_contr_sock(g_system);
380                 return STC_ERROR_FAIL;
381         }
382
383         __vconf_get_int(VCONFKEY_STC_BACKGROUND_STATE,
384                         (int *)&g_system->background_state);
385
386         __fill_exceptions_list();
387         stc_monitor_rstns_load();
388
389         __STC_LOG_FUNC_EXIT__;
390         return STC_ERROR_NONE;
391 }
392
393 stc_error_e stc_plugin_monitor_deinitialize(void)
394 {
395         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
396
397         /* close netlink socket for updating kernel counters */
398         __close_contr_sock(g_system);
399
400         /* remove kernel counters update timer */
401         if (g_system->contr_timer_id > 0) {
402                 g_source_remove(g_system->contr_timer_id);
403                 g_system->contr_timer_id = 0;
404         }
405
406         /* destroy monitored application tree */
407         g_hash_table_destroy(g_system->apps);
408         g_system->apps = NULL;
409
410         /* destroy restriction rules tree */
411         g_hash_table_destroy(g_system->rstns);
412         g_system->rstns = NULL;
413
414         FREE(g_system);
415
416         return STC_ERROR_NONE;
417 }
418
419 GHashTable *stc_monitor_get_system_apps(void)
420 {
421         ret_value_msg_if(g_system == NULL, NULL,
422                                 "stc monitor not initialized!");
423
424         ret_value_msg_if(g_system->apps == NULL, NULL,
425                                 "apps is null!");
426
427         return g_system->apps;
428 }
429
430 GHashTable *stc_monitor_get_system_rstns(void)
431 {
432         ret_value_msg_if(g_system == NULL, NULL,
433                                 "stc monitor not initialized!");
434
435         ret_value_msg_if(g_system->rstns == NULL, NULL,
436                                 "rstns is null!");
437
438         return g_system->rstns;
439 }
440
441 int stc_monitor_get_contr_sock(void)
442 {
443         ret_value_msg_if(g_system == NULL, 0,
444                                 "stc monitor not initialized!");
445
446         return g_system->contr_sock;
447 }
448
449 time_t stc_monitor_get_last_month_ts(void)
450 {
451         ret_value_msg_if(g_system == NULL, 0,
452                                 "stc monitor not initialized!");
453
454         return g_system->last_month_ts;
455 }
456
457 void stc_monitor_set_last_month_ts(time_t time)
458 {
459         ret_msg_if(g_system == NULL, "stc monitor not initialized!");
460
461         g_system->last_month_ts = time;
462 }
463
464 time_t stc_monitor_get_last_week_ts(void)
465 {
466         ret_value_msg_if(g_system == NULL, 0,
467                                 "stc monitor not initialized!");
468
469         return g_system->last_week_ts;
470 }
471
472 void stc_monitor_set_last_week_ts(time_t time)
473 {
474         ret_msg_if(g_system == NULL, "stc monitor not initialized!");
475
476         g_system->last_week_ts = time;
477 }
478
479 time_t stc_monitor_get_last_day_ts(void)
480 {
481         ret_value_msg_if(g_system == NULL, 0,
482                                 "stc monitor not initialized!");
483
484         return g_system->last_day_ts;
485 }
486
487 void stc_monitor_set_last_day_ts(time_t time)
488 {
489         ret_msg_if(g_system == NULL, "stc monitor not initialized!");
490
491         g_system->last_day_ts = time;
492 }
493
494 void stc_monitor_set_rstns_updated(gboolean value)
495 {
496         ret_msg_if(g_system == NULL, "stc monitor not initialized!");
497
498         g_system->rstns_updated = value;
499 }
500
501 gboolean stc_monitor_get_rstns_updated(void)
502 {
503         ret_value_msg_if(g_system == NULL, FALSE,
504                                 "stc monitor not initialized!");
505
506         return g_system->rstns_updated;
507 }
508
509 void stc_monitor_set_apps_updated(gboolean value)
510 {
511         ret_msg_if(g_system == NULL, "stc monitor not initialized!");
512
513         g_system->apps_updated = value;
514 }
515
516 gboolean stc_monitor_get_apps_updated(void)
517 {
518         ret_value_msg_if(g_system == NULL, FALSE,
519                                 "stc monitor not initialized!");
520
521         return g_system->apps_updated;
522 }
523
524 void stc_monitor_set_background_state(gboolean value)
525 {
526         ret_msg_if(g_system == NULL, "stc monitor not initialized!");
527
528         g_system->background_state = value;
529 }
530
531 gboolean stc_monitor_get_background_state(void)
532 {
533         ret_value_msg_if(g_system == NULL, FALSE,
534                                 "stc monitor not initialized!");
535
536         return g_system->background_state;
537 }
538
539 void stc_monitor_update_by_connection(void *data)
540 {
541         stc_connection_s *connection = (stc_connection_s *)data;
542
543         if (connection != NULL && connection->path != NULL) {
544                 stc_monitor_app_remove_by_connection(connection);
545                 stc_monitor_rstn_remove_by_connection(connection);
546
547                 iptables_flush_chains();
548
549                 stc_monitor_app_add_by_connection(connection);
550                 stc_monitor_rstn_add_by_connection(connection);
551         }
552 }
553
554 void stc_monitor_add_by_connection(void *data)
555 {
556         stc_connection_s *connection = (stc_connection_s *)data;
557
558         if (connection != NULL && connection->path != NULL) {
559                 stc_monitor_app_add_by_connection(connection);
560                 stc_monitor_rstn_add_by_connection(connection);
561         }
562 }
563
564 void stc_monitor_remove_by_connection(void *data)
565 {
566         stc_connection_s *connection = (stc_connection_s *)data;
567
568         if (connection != NULL && connection->path != NULL) {
569                 stc_monitor_app_remove_by_connection(connection);
570                 stc_monitor_rstn_remove_by_connection(connection);
571         }
572 }
573
574 API stc_plugin_monitor_s stc_plugin_monitor = {
575         .initialize_plugin =
576                 stc_plugin_monitor_initialize,
577         .deinitialize_plugin =
578                 stc_plugin_monitor_deinitialize,
579         .add_application =
580                 stc_plugin_monitor_app_add,
581         .remove_application =
582                 stc_plugin_monitor_app_remove,
583         .lookup_application =
584                 stc_plugin_monitor_app_lookup,
585         .add_restriction =
586                 stc_plugin_monitor_rstn_add,
587         .remove_restriction =
588                 stc_plugin_monitor_rstn_remove,
589         .init_connection =
590                 stc_plugin_monitor_connection_init,
591         .deinit_connection =
592                 stc_plugin_monitor_connection_deinit,
593         .add_process =
594                 stc_plugin_monitor_proc_add,
595         .remove_process =
596                 stc_plugin_monitor_proc_remove,
597         .move_process =
598                 stc_plugin_monitor_proc_move,
599         .update_process_ground =
600                 stc_plugin_monitor_proc_update_ground
601 };