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