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