Added exception lists for monitoring
[platform/core/connectivity/stc-manager.git] / src / monitor / stc-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 "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 "counter.h"
27 #include "table-statistics.h"
28 #include "table-counters.h"
29 #include "stc-exception.h"
30 #include "stc-monitor.h"
31 #include "stc-manager-plugin.h"
32
33 #define MAX_INT_LENGTH 128
34 #define VCONFKEY_STC_BACKGROUND_STATE "db/stc/background_state"
35
36 typedef struct {
37         stc_app_key_s *app_key;
38         stc_process_key_s *proc_key;
39         gboolean entry_removed;
40 } remove_pid_context_s;
41
42 typedef struct {
43         struct nfacct_rule *counter;
44         int64_t bytes;
45         gboolean data_limit_reached;
46 } classid_bytes_context_s;
47
48 static stc_system_s *g_system = NULL;
49
50 static nfacct_rule_jump __get_jump_by_intend(struct nfacct_rule *counter)
51 {
52         if (counter->intend == NFACCT_WARN)
53                 return NFACCT_JUMP_ACCEPT;
54         else if (counter->intend == NFACCT_BLOCK)
55                 return NFACCT_JUMP_REJECT;
56
57         return NFACCT_JUMP_UNKNOWN;
58 }
59
60 static stc_error_e __add_iptables_in(struct nfacct_rule *counter)
61 {
62         if (counter == NULL)
63                 return STC_ERROR_INVALID_PARAMETER;
64
65         counter->action = NFACCT_ACTION_INSERT;
66         counter->iotype = NFACCT_COUNTER_IN;
67         counter->jump = __get_jump_by_intend(counter);
68         counter->iptype = NFACCT_TYPE_IPV4;
69         counter->send_limit = 0;
70         counter->rcv_limit = 0;
71
72         return produce_net_rule(counter);
73 }
74
75 static stc_error_e __add_iptables_out(struct nfacct_rule *counter)
76 {
77         if (counter == NULL)
78                 return STC_ERROR_INVALID_PARAMETER;
79
80         counter->action = NFACCT_ACTION_INSERT;
81         counter->iotype = NFACCT_COUNTER_OUT;
82         counter->jump = __get_jump_by_intend(counter);
83         counter->iptype = NFACCT_TYPE_IPV4;
84         counter->send_limit = 0;
85         counter->rcv_limit = 0;
86
87         return produce_net_rule(counter);
88 }
89
90 static stc_error_e __del_iptables_in(struct nfacct_rule *counter)
91 {
92         if (counter == NULL)
93                 return STC_ERROR_INVALID_PARAMETER;
94
95         counter->action = NFACCT_ACTION_DELETE;
96         counter->iotype = NFACCT_COUNTER_IN;
97         counter->jump = __get_jump_by_intend(counter);
98         counter->iptype = NFACCT_TYPE_IPV4;
99         counter->send_limit = 0;
100         counter->rcv_limit = 0;
101
102         return produce_net_rule(counter);
103 }
104
105 static stc_error_e __del_iptables_out(struct nfacct_rule *counter)
106 {
107         if (counter == NULL)
108                 return STC_ERROR_INVALID_PARAMETER;
109
110         counter->action = NFACCT_ACTION_DELETE;
111         counter->iotype = NFACCT_COUNTER_OUT;
112         counter->jump = __get_jump_by_intend(counter);
113         counter->iptype = NFACCT_TYPE_IPV4;
114         counter->send_limit = 0;
115         counter->rcv_limit = 0;
116
117         return produce_net_rule(counter);
118 }
119
120 static stc_error_e __add_ip6tables_in(struct nfacct_rule *counter)
121 {
122         if (counter == NULL)
123                 return STC_ERROR_INVALID_PARAMETER;
124
125         counter->action = NFACCT_ACTION_INSERT;
126         counter->iotype = NFACCT_COUNTER_IN;
127         counter->jump = __get_jump_by_intend(counter);
128         counter->iptype = NFACCT_TYPE_IPV6;
129         counter->send_limit = 0;
130         counter->rcv_limit = 0;
131
132         return produce_net_rule(counter);
133 }
134
135 static stc_error_e __add_ip6tables_out(struct nfacct_rule *counter)
136 {
137         if (counter == NULL)
138                 return STC_ERROR_INVALID_PARAMETER;
139
140         counter->action = NFACCT_ACTION_INSERT;
141         counter->iotype = NFACCT_COUNTER_OUT;
142         counter->jump = __get_jump_by_intend(counter);
143         counter->iptype = NFACCT_TYPE_IPV6;
144         counter->send_limit = 0;
145         counter->rcv_limit = 0;
146
147         return produce_net_rule(counter);
148 }
149
150 static stc_error_e __del_ip6tables_in(struct nfacct_rule *counter)
151 {
152         if (counter == NULL)
153                 return STC_ERROR_INVALID_PARAMETER;
154
155         counter->action = NFACCT_ACTION_DELETE;
156         counter->iotype = NFACCT_COUNTER_IN;
157         counter->jump = __get_jump_by_intend(counter);
158         counter->iptype = NFACCT_TYPE_IPV6;
159         counter->send_limit = 0;
160         counter->rcv_limit = 0;
161
162         return produce_net_rule(counter);
163 }
164
165 static stc_error_e __del_ip6tables_out(struct nfacct_rule *counter)
166 {
167         if (counter == NULL)
168                 return STC_ERROR_INVALID_PARAMETER;
169
170         counter->action = NFACCT_ACTION_DELETE;
171         counter->iotype = NFACCT_COUNTER_OUT;
172         counter->jump = __get_jump_by_intend(counter);
173         counter->iptype = NFACCT_TYPE_IPV6;
174         counter->send_limit = 0;
175         counter->rcv_limit = 0;
176
177         return produce_net_rule(counter);
178 }
179
180 static int __processes_tree_key_compare(gconstpointer a, gconstpointer b,
181                                         gpointer UNUSED user_data)
182 {
183         stc_process_key_s *key_a = (stc_process_key_s *)a;
184         stc_process_key_s *key_b = (stc_process_key_s *)b;
185
186         return key_a->pid - key_b->pid;
187 }
188
189 static void __processes_tree_value_free(gpointer data)
190 {
191         stc_process_value_s *value = (stc_process_value_s *)data;
192
193         FREE(value);
194 }
195
196 static void __processes_tree_key_free(gpointer data)
197 {
198         stc_process_key_s *key = (stc_process_key_s *)data;
199
200         FREE(key);
201 }
202
203 static int __apps_tree_key_compare(gconstpointer a, gconstpointer b,
204                                    gpointer UNUSED user_data)
205 {
206         stc_app_key_s *key_a = (stc_app_key_s *)a;
207         stc_app_key_s *key_b = (stc_app_key_s *)b;
208         gint ret;
209
210         ret = g_strcmp0(key_a->pkg_id, key_b->pkg_id);
211         if (ret)
212                 return ret;
213
214         return g_strcmp0(key_a->app_id, key_b->app_id);
215 }
216
217 static void __apps_tree_value_free(gpointer data)
218 {
219         stc_app_value_s *value = (stc_app_value_s *)data;
220
221         g_tree_destroy(value->processes);
222         value->processes = NULL;
223
224         FREE(value);
225 }
226
227 static void __apps_tree_key_free(gpointer data)
228 {
229         stc_app_key_s *key = (stc_app_key_s *)data;
230
231         g_free(key->pkg_id);
232         g_free(key->app_id);
233         FREE(key);
234 }
235
236 static int __rstns_tree_key_compare(gconstpointer a, gconstpointer b,
237                                     gpointer UNUSED user_data)
238 {
239         stc_rstn_key_s *key_a = (stc_rstn_key_s *)a;
240         stc_rstn_key_s *key_b = (stc_rstn_key_s *)b;
241         int ret;
242
243         ret = g_strcmp0(key_a->app_id, key_b->app_id);
244         if (ret != 0)
245                 return ret;
246
247         ret = g_strcmp0(key_a->ifname, key_b->ifname);
248         if (ret != 0)
249                 return ret;
250
251         ret = g_strcmp0(key_a->imsi, key_b->imsi);
252         if (ret != 0)
253                 return ret;
254
255         ret = key_a->iftype - key_b->iftype;
256         if (ret != 0)
257                 return ret;
258
259         return 0;
260 }
261
262 static void __rstns_tree_value_free(gpointer data)
263 {
264         stc_rstn_value_s *value = (stc_rstn_value_s *)data;
265
266         FREE(value);
267 }
268
269 static void __rstns_tree_key_free(gpointer data)
270 {
271         stc_rstn_key_s *key = (stc_rstn_key_s *)data;
272
273         FREE(key->app_id);
274         FREE(key->ifname);
275         FREE(key->imsi);
276         FREE(key);
277 }
278
279 static gboolean __processes_tree_foreach_print(gpointer key, gpointer value,
280                                                gpointer data)
281 {
282         stc_process_key_s *proc_key = (stc_process_key_s *)key;
283         stc_process_value_s *proc_value = (stc_process_value_s *)value;
284
285         STC_LOGD("Process entry => PID [%d], Ground state [%d]",
286                  proc_key->pid, proc_value->ground);
287         return FALSE;
288 }
289
290 static void __processes_tree_printall(GTree *processes)
291 {
292         g_tree_foreach(processes, __processes_tree_foreach_print, NULL);
293 }
294
295 static gboolean __apps_tree_foreach_print(gpointer key, gpointer value,
296                                           gpointer data)
297 {
298         stc_app_key_s *app_key = (stc_app_key_s *)key;
299         stc_app_value_s *app_value = (stc_app_value_s *)value;
300
301         STC_LOGD("Application info => Pkg ID [%s], App ID [%s],"
302                  " Type [%d], classid [%d],"
303                  " counter [ in (%lld), out (%lld)]",
304                  app_key->pkg_id, app_key->app_id,
305                  app_value->type, app_value->classid,
306                  app_value->data_usage.in_bytes, app_value->data_usage.out_bytes);
307
308         __processes_tree_printall(app_value->processes);
309         return FALSE;
310 }
311
312 #if 0
313 static void __apps_tree_printall(void)
314 {
315         g_tree_foreach(g_system->apps, __apps_tree_foreach_print, NULL);
316 }
317 #endif
318
319 static gboolean __apps_tree_foreach_remove_pid(gpointer key, gpointer value,
320                                                gpointer data)
321 {
322         remove_pid_context_s *context = (remove_pid_context_s *)data;
323         stc_app_value_s *app_value = (stc_app_value_s *)value;
324
325         if (!g_tree_remove(app_value->processes, context->proc_key)) {
326                 STC_LOGD("key not found");
327                 return FALSE;
328         }
329
330         context->entry_removed = TRUE;
331         context->app_key = (stc_app_key_s *)key;
332
333         return TRUE;
334 }
335
336 static stc_app_value_s * __application_lookup(GTree *apps,
337                                               const stc_app_key_s *key)
338 {
339         stc_app_value_s *lookup;
340
341         ret_value_msg_if(apps == NULL, NULL, "apps is null!");
342
343         lookup = g_tree_lookup(apps, key);
344
345         return lookup;
346 }
347
348 static stc_process_value_s * __process_lookup(GTree *processes,
349                                               const stc_process_key_s *key)
350 {
351         stc_process_value_s *lookup;
352
353         ret_value_msg_if(processes == NULL, NULL, "processes is null!");
354
355         lookup = g_tree_lookup(processes, key);
356
357         return lookup;
358 }
359
360 static gboolean __processes_tree_check_empty(gpointer key, gpointer value,
361                                              gpointer data)
362 {
363         guint *pid_count = (guint *)data;
364         (*pid_count)++;
365         return TRUE;
366 }
367
368 static gboolean __add_application_monitor(gpointer key, gpointer value,
369                                           gpointer data)
370 {
371         stc_app_value_s *app_value = (stc_app_value_s *)value;
372         default_connection_s *connection = (default_connection_s *)data;
373         stc_s *stc = stc_get_manager();
374
375         if (app_value->classid == STC_TOTAL_DATACALL_CLASSID ||
376             app_value->classid == STC_TOTAL_WIFI_CLASSID ||
377             app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID)
378                 return FALSE;
379
380         if (stc && connection && connection->ifname) {
381                 struct nfacct_rule counter;
382
383                 if (!stc->carg) {
384                         stc->carg = MALLOC0(counter_arg_s, 1);
385                         if (stc->carg == NULL)
386                                 return FALSE;
387
388                         stc->carg->sock = stc_monitor_get_counter_socket();
389                 }
390
391                 memset(&counter, 0, sizeof(struct nfacct_rule));
392
393                 counter.carg = stc->carg;
394                 counter.classid = app_value->classid;
395                 counter.intend = NFACCT_COUNTER;
396                 counter.iftype = connection->type;
397                 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
398
399                 if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
400                         __add_iptables_in(&counter);
401                         __add_iptables_out(&counter);
402                 } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
403                         __add_ip6tables_in(&counter);
404                         __add_ip6tables_out(&counter);
405                 } else {
406                         __add_iptables_in(&counter);
407                         __add_iptables_out(&counter);
408                         __add_ip6tables_in(&counter);
409                         __add_ip6tables_out(&counter);
410                 }
411         }
412
413         return FALSE;
414 }
415
416 static gboolean __remove_application_monitor(gpointer key, gpointer value,
417                                              gpointer data)
418 {
419         stc_app_value_s *app_value = (stc_app_value_s *)value;
420         default_connection_s *connection = (default_connection_s *)data;
421         stc_s *stc = stc_get_manager();
422
423         if (stc && connection && connection->ifname) {
424                 struct nfacct_rule counter;
425
426                 if (!stc->carg) {
427                         stc->carg = MALLOC0(counter_arg_s, 1);
428                         if (stc->carg == NULL)
429                                 return FALSE;
430
431                         stc->carg->sock = stc_monitor_get_counter_socket();
432                 }
433
434                 memset(&counter, 0, sizeof(struct nfacct_rule));
435
436                 counter.carg = stc->carg;
437                 counter.classid = app_value->classid;
438                 counter.intend = NFACCT_COUNTER;
439                 counter.iftype = connection->type;
440                 g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
441
442                 __del_iptables_in(&counter);
443                 __del_iptables_out(&counter);
444                 __del_ip6tables_in(&counter);
445                 __del_ip6tables_out(&counter);
446         }
447
448         return FALSE;
449 }
450
451 static void __print_rstn(stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value)
452 {
453         STC_LOGI("rstn info => rstn_id [%llu], "
454                  "app_id [%s], classid [%lu], ifname [%s], "
455                  "iftype [%d], rst_state [%d], "
456                  "limit [ (%lld) bytes], "
457                  "warn_limit [ (%lld) bytes], "
458                  "counter [ (%lld) bytes], "
459                  "roaming [%d], imsi [%s]",
460                  rstn_value->restriction_id,
461                  rstn_key->app_id, rstn_value->classid , rstn_key->ifname,
462                  rstn_key->iftype, rstn_value->rst_state,
463                  rstn_value->data_limit,
464                  rstn_value->data_warn_limit,
465                  rstn_value->data_counter,
466                  rstn_key->roaming, rstn_key->imsi);
467 }
468
469 static void __process_restriction(enum traffic_restriction_type rst_type,
470                                   stc_rstn_key_s *rstn_key,
471                                   stc_rstn_value_s *rstn_value, void *data)
472 {
473         int64_t effective_data_limit, effective_data_warn_limit;
474         default_connection_s *old_connection = (default_connection_s *)data;
475         default_connection_s *connection = NULL;
476
477         if (old_connection != NULL)
478                 connection = old_connection;
479         else
480                 connection = stc_get_default_connection();
481
482         /* no default ifname */
483         if (connection->ifname == NULL)
484                 return;
485
486         /* rstn not applicable for this interface */
487         if (rstn_key->ifname != NULL && g_strcmp0("", rstn_key->ifname) != 0 &&
488             g_strcmp0(connection->ifname, rstn_key->ifname) != 0)
489                 return;
490
491         /* classid is invalid */
492         if (rstn_value->classid == STC_UNKNOWN_CLASSID)
493                 return;
494
495         effective_data_limit = rstn_value->data_limit;
496         effective_data_warn_limit = rstn_value->data_warn_limit;
497
498         if (rst_type == RST_SET) {
499                 /* TODO: Change this to runtime memory */
500                 table_counters_info info;
501
502                 memset(&info, 0, sizeof(table_counters_info));
503                 table_counters_get(rstn_value->restriction_id, &info);
504
505                 effective_data_limit -= info.data_counter;
506                 effective_data_warn_limit -= info.data_counter;
507
508                 if (effective_data_limit < 0) {
509                         effective_data_limit = 0;
510                         rstn_value->data_limit_reached = TRUE;
511                 }
512
513                 if (effective_data_warn_limit < 0)
514                         effective_data_warn_limit = 0;
515
516                 STC_LOGD("datausage [%lld] bytes", info.data_counter);
517         }
518
519         STC_LOGD("rstn_id [%llu], effective_data_limit [%lld] bytes, "
520                  "effective_data_warn_limit [%lld] bytes",
521                  rstn_value->restriction_id, effective_data_limit,
522                  effective_data_warn_limit);
523
524         switch (rst_type) {
525         case RST_SET:
526                 if (effective_data_limit <= 0) {
527                         char *default_ifname = stc_default_connection_get_ifname();
528                         struct nfacct_rule counter;
529                         stc_s *stc = stc_get_manager();
530
531                         if (!stc->carg) {
532                                 stc->carg = MALLOC0(counter_arg_s, 1);
533                                 if (stc->carg == NULL) {
534                                         g_free(default_ifname);
535                                         return;
536                                 }
537
538                                 stc->carg->sock =
539                                         stc_monitor_get_counter_socket();
540                         }
541
542                         counter.carg = stc->carg;
543                         counter.classid = rstn_value->classid;
544                         counter.intend = NFACCT_BLOCK;
545                         counter.iftype = rstn_key->iftype;
546                         g_strlcpy(counter.ifname, default_ifname,
547                                   MAX_IFACE_LENGTH);
548
549                         generate_counter_name(&counter);
550                         g_free(default_ifname);
551
552                         /* iptables rule */
553                         __add_iptables_in(&counter);
554                         __add_iptables_out(&counter);
555
556                         /* ip6tables rule */
557                         __add_ip6tables_in(&counter);
558                         __add_ip6tables_out(&counter);
559                 }
560
561                 rstn_value->rst_state = STC_RESTRICTION_ACTIVATED;
562                 rstn_value->data_limit_reached = FALSE;
563                 break;
564         case RST_EXCLUDE:
565                 ;//Do Nothing
566                 break;
567         case RST_UNSET:
568                 {
569                         char *default_ifname = stc_default_connection_get_ifname();
570                         struct nfacct_rule counter;
571                         stc_s *stc = stc_get_manager();
572
573                         if (!stc->carg) {
574                                 stc->carg = MALLOC0(counter_arg_s, 1);
575                                 if (stc->carg == NULL) {
576                                         g_free(default_ifname);
577                                         return;
578                                 }
579
580                                 stc->carg->sock =
581                                         stc_monitor_get_counter_socket();
582                         }
583
584                         counter.carg = stc->carg;
585                         counter.classid = rstn_value->classid;
586                         counter.intend = NFACCT_BLOCK;
587                         counter.iftype = rstn_key->iftype;
588                         g_strlcpy(counter.ifname, default_ifname,
589                                   MAX_IFACE_LENGTH);
590
591                         generate_counter_name(&counter);
592                         g_free(default_ifname);
593
594                         /* iptables rule */
595                         __del_iptables_in(&counter);
596                         __del_iptables_out(&counter);
597
598                         /* ip6tables rule */
599                         __del_ip6tables_in(&counter);
600                         __del_ip6tables_out(&counter);
601
602                         rstn_value->rst_state = STC_RESTRICTION_REMOVED;
603                         rstn_value->data_limit_reached = FALSE;
604                 }
605                 break;
606         default:
607                 ;//Do Nothing
608         }
609 }
610
611 static gboolean __remove_rstns_foreach_application(gpointer key,
612                                                    gpointer value,
613                                                    gpointer data)
614 {
615         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
616         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
617         gchar *app_id = (gchar *)data;
618
619         /* rstn rule is not for applications */
620         if (rstn_key->app_id == NULL)
621                 goto out;
622
623         /* rstn rule is not for this application */
624         if (g_strcmp0(rstn_key->app_id, app_id) != 0)
625                 goto out;
626
627         /* rstn rule is already removed */
628         if (rstn_value->rst_state == STC_RESTRICTION_REMOVED)
629                 goto out;
630
631         /* remove restriction from system */
632         __process_restriction(RST_UNSET, rstn_key, rstn_value, data);
633
634         __print_rstn(rstn_key, rstn_value);
635 out:
636         return FALSE;
637 }
638
639 static void __remove_rstns_for_application(gchar *app_id)
640 {
641         g_tree_foreach(g_system->rstns, __remove_rstns_foreach_application,
642                        app_id);
643 }
644
645 static stc_error_e __application_remove_if_empty(const stc_app_key_s *app_key)
646 {
647         stc_error_e ret = STC_ERROR_NONE;
648         guint pid_count = 0;
649         stc_app_value_s *lookup;
650
651         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
652
653         lookup = __application_lookup(g_system->apps, app_key);
654         if (!lookup) {
655                 STC_LOGE("app_key not found");
656                 return STC_ERROR_NO_DATA;
657         }
658
659         g_tree_foreach(lookup->processes, __processes_tree_check_empty,
660                        &pid_count);
661
662         if (!pid_count) {
663                 /* remove nfacct rule for this classid */
664                 __remove_application_monitor((gpointer) app_key, lookup,
665                                              stc_get_default_connection());
666                 __remove_rstns_for_application(app_key->app_id);
667         }
668
669         if (!g_tree_remove(g_system->apps, app_key)) {
670                 ret = STC_ERROR_NO_DATA;
671                 STC_LOGE("key not found");
672         }
673
674         return ret;
675 }
676
677 static stc_error_e __close_contr_sock(stc_system_s *system)
678 {
679         ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
680
681         /* close netlink socket for updating kernel counters */
682         if (system->contr_sock != -1) {
683                 close(system->contr_sock);
684                 system->contr_sock = -1;
685         }
686
687         if (system->contr_gsource_id != 0) {
688                 g_source_remove(system->contr_gsource_id);
689                 system->contr_gsource_id = 0;
690         }
691
692         return STC_ERROR_NONE;
693 }
694
695 static gboolean __process_contr_reply(GIOChannel *source,
696                                       GIOCondition condition,
697                                       gpointer user_data);
698
699 static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system)
700 {
701         GIOChannel *gio = NULL;
702         ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter");
703
704         /* close netlink socket for updating kernel counters */
705         if (system->contr_sock != -1) {
706                 close(system->contr_sock);
707                 system->contr_sock = -1;
708         }
709
710         if (system->contr_gsource_id != 0) {
711                 g_source_remove(system->contr_gsource_id);
712                 system->contr_gsource_id = 0;
713         }
714
715         /* create netlink socket for updating kernel counters */
716         system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
717         if (!(system->contr_sock)) {
718                 STC_LOGE("failed to open socket");
719                 FREE(system);
720                 return STC_ERROR_FAIL;
721         }
722
723         gio = g_io_channel_unix_new(system->contr_sock);
724         system->contr_gsource_id =
725                 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
726                                (GIOFunc) __process_contr_reply,
727                                NULL);
728         g_io_channel_unref(gio);
729
730         return STC_ERROR_NONE;
731 }
732
733 static gboolean __rstn_counter_update(stc_rstn_key_s *rstn_key,
734                                       stc_rstn_value_s *rstn_value,
735                                       classid_bytes_context_s *context)
736 {
737         switch (context->counter->iotype) {
738         case NFACCT_COUNTER_IN:
739         case NFACCT_COUNTER_OUT:
740                 rstn_value->data_counter += context->bytes;
741
742                 if (rstn_value->data_counter >= rstn_value->data_warn_limit &&
743                     rstn_value->warn_limit_crossed_notified == FALSE) {
744
745                         gboolean rv;
746                         char iftype[MAX_INT_LENGTH];
747                         char byte[MAX_INT_LENGTH];
748                         stc_s *stc = (stc_s *)stc_get_manager();
749                         ret_value_msg_if(stc == NULL, FALSE, "failed to get stc data");
750
751                         /* emit signal */
752                         rv = stc_manager_dbus_emit_signal(stc->connection,
753                                                           STC_DBUS_SERVICE_RESTRICTION_PATH,
754                                                           STC_DBUS_INTERFACE_RESTRICTION,
755                                                           "WarnThresholdCrossed",
756                                                           g_variant_new("(si)", rstn_key->app_id, rstn_key->iftype));
757                         if (rv == TRUE)
758                                 rstn_value->warn_limit_crossed_notified = TRUE;
759
760                         snprintf(iftype, MAX_INT_LENGTH, "%d", rstn_key->iftype);
761                         snprintf(byte, MAX_INT_LENGTH, "%lld", rstn_value->data_warn_limit);
762                         stc_send_warn_message_to_net_popup("warn threshold crossed",
763                                                            "warning_noti",
764                                                            rstn_key->app_id,
765                                                            iftype, byte);
766                 }
767
768                 if (rstn_value->data_counter >= rstn_value->data_limit &&
769                     rstn_value->rstn_limit_crossed_notified == FALSE) {
770
771                         gboolean rv;
772                         char iftype[MAX_INT_LENGTH];
773                         char byte[MAX_INT_LENGTH];
774                         stc_s *stc = (stc_s *)stc_get_manager();
775                         ret_value_msg_if(stc == NULL, FALSE, "failed to get stc data");
776
777                         /* block immediately */
778                         context->counter->intend = NFACCT_BLOCK;
779                         __del_iptables_in(context->counter);
780                         __del_iptables_out(context->counter);
781                         __add_iptables_in(context->counter);
782                         __add_iptables_out(context->counter);
783
784                         __del_ip6tables_in(context->counter);
785                         __del_ip6tables_out(context->counter);
786                         __add_ip6tables_in(context->counter);
787                         __add_ip6tables_out(context->counter);
788                         context->counter->intend = NFACCT_COUNTER;
789
790                         rstn_value->data_limit_reached = TRUE;
791
792                         /* emit signal */
793                         rv = stc_manager_dbus_emit_signal(stc->connection,
794                                                           STC_DBUS_SERVICE_RESTRICTION_PATH,
795                                                           STC_DBUS_INTERFACE_RESTRICTION,
796                                                           "RestrictionThresholdCrossed",
797                                                           g_variant_new("(si)", rstn_key->app_id, rstn_key->iftype));
798                         if (rv == TRUE)
799                                 rstn_value->rstn_limit_crossed_notified = TRUE;
800
801                         snprintf(iftype, MAX_INT_LENGTH, "%d", rstn_key->iftype);
802                         snprintf(byte, MAX_INT_LENGTH, "%lld", rstn_value->data_limit);
803                         stc_send_restriction_message_to_net_popup("restriction threshold crossed",
804                                                                   "restriction_noti", rstn_key->app_id,
805                                                                   iftype, byte);
806                 }
807
808                 g_system->rstns_tree_updated = TRUE;
809                 __print_rstn(rstn_key, rstn_value);
810                 break;
811         default:
812                 STC_LOGE("unknown iotype");
813         }
814
815         return FALSE;
816 }
817
818 static gboolean __interface_rstn_counter_update(stc_rstn_key_s *rstn_key,
819                                                 stc_rstn_value_s *rstn_value,
820                                                 classid_bytes_context_s *context)
821 {
822         if ((rstn_value->classid == STC_TOTAL_DATACALL_CLASSID &&
823              context->counter->iftype == STC_IFACE_DATACALL) ||
824             (rstn_value->classid == STC_TOTAL_WIFI_CLASSID &&
825              context->counter->iftype == STC_IFACE_WIFI) ||
826             (rstn_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
827              context->counter->iftype == STC_IFACE_BLUETOOTH)) {
828                 context->counter->classid = rstn_value->classid;
829                 return __rstn_counter_update(rstn_key, rstn_value, context);
830         }
831
832         return FALSE;
833 }
834
835 static gboolean __rstn_counter_update_foreach_classid(gpointer key,
836                                                       gpointer value,
837                                                       gpointer data)
838 {
839         gboolean rv = FALSE;
840         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
841         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
842         classid_bytes_context_s *context = (classid_bytes_context_s *)data;
843         uint32_t classid;
844
845         if (context->counter->intend != NFACCT_COUNTER)
846                 goto try_next_callback;
847
848         if (rstn_value->data_limit_reached == TRUE) {
849                 context->data_limit_reached = TRUE;
850                 goto try_next_callback;
851         }
852
853         classid = context->counter->classid;
854         rv = __interface_rstn_counter_update(rstn_key, rstn_value, context);
855
856         context->counter->classid = classid;
857         if (rstn_value->classid != context->counter->classid)
858                 goto try_next_callback;
859
860         rv = __rstn_counter_update(rstn_key, rstn_value, context);
861
862 try_next_callback:
863         return rv;
864 }
865
866 static gboolean __update_app_statistics(gpointer key, gpointer value,
867                                         gpointer data)
868 {
869         stc_app_key_s *app_key = (stc_app_key_s *)key;
870         stc_app_value_s *app_value = (stc_app_value_s *)value;
871         time_t *touch_time = (time_t *)data;
872         stc_db_classid_iftype_key stat_key;
873         stc_db_app_stats stat;
874         default_connection_s *default_connection = stc_get_default_connection();
875
876         memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key));
877         memset(&stat, 0 , sizeof(stc_db_app_stats));
878
879         stat_key.classid = app_value->classid;
880         stat_key.iftype = default_connection->type;
881
882         if (STC_IFACE_DATACALL == stat_key.iftype)
883                 stat_key.imsi = g_strdup(default_connection->imsi);
884         else
885                 stat_key.imsi = g_strdup("noneimsi");
886
887         g_strlcpy(stat_key.ifname, default_connection->ifname,
888                   MAX_IFACE_LENGTH);
889
890         stat.app_id = g_strdup(app_key->app_id);
891         stat.snd_count = app_value->counter.out_bytes;
892         stat.rcv_count = app_value->counter.in_bytes;
893         stat.is_roaming = default_connection->roaming;
894         stat.ground = STC_APP_STATE_UNKNOWN;
895
896         table_statistics_insert(&stat_key, &stat, *touch_time);
897
898         app_value->counter.out_bytes = 0;
899         app_value->counter.in_bytes = 0;
900
901         FREE(stat.app_id);
902         FREE(stat_key.imsi);
903
904         return FALSE;
905 }
906
907 static gboolean __flush_apps_stats_to_database(gpointer user_data)
908 {
909         time_t current_time = time(0);
910
911         if (g_system->apps_tree_updated == FALSE)
912                 return G_SOURCE_REMOVE;
913
914         g_system->apps_tree_updated = FALSE;
915
916         if (g_system->apps)
917                 g_tree_foreach(g_system->apps,
918                                __update_app_statistics,
919                                &current_time);
920
921         STC_LOGI("Flushed app stats to database");
922         return G_SOURCE_REMOVE;
923 }
924
925 static gboolean __update_counter_statistics(gpointer key, gpointer value,
926                                             gpointer data)
927 {
928         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
929         table_counters_info info = {
930                 .restriction_id = rstn_value->restriction_id,
931                 .data_counter = rstn_value->data_counter
932         };
933
934         table_counters_update_counters(&info);
935
936         return FALSE;
937 }
938
939 static gboolean __flush_rstns_counter_to_database(gpointer user_data)
940 {
941         time_t current_time = time(0);
942
943         if (g_system->rstns_tree_updated == FALSE)
944                 return G_SOURCE_REMOVE;
945
946         g_system->rstns_tree_updated = FALSE;
947
948         if (g_system->rstns)
949                 g_tree_foreach(g_system->rstns,
950                                __update_counter_statistics,
951                                &current_time);
952
953         STC_LOGI("Flushed rstns counters to database");
954         return G_SOURCE_REMOVE;
955 }
956
957 static void __app_counter_update(stc_app_key_s *app_key,
958                                  stc_app_value_s *app_value,
959                                  classid_bytes_context_s *context)
960 {
961         switch (context->counter->iotype) {
962         case NFACCT_COUNTER_IN:
963                 app_value->data_usage.in_bytes += context->bytes;
964                 app_value->counter.in_bytes = context->bytes;
965                 g_system->apps_tree_updated = TRUE;
966
967                 __apps_tree_foreach_print(app_key, app_value, NULL);
968                 break;
969         case NFACCT_COUNTER_OUT:
970                 app_value->data_usage.out_bytes += context->bytes;
971                 app_value->counter.out_bytes = context->bytes;
972                 g_system->apps_tree_updated = TRUE;
973
974                 __apps_tree_foreach_print(app_key, app_value, NULL);
975                 break;
976         default:
977                 STC_LOGE("unknown iotype");
978         }
979 }
980
981 static void __interface_counter_update(stc_app_key_s *app_key,
982                                        stc_app_value_s *app_value,
983                                        classid_bytes_context_s *context)
984 {
985         if ((app_value->classid == STC_TOTAL_DATACALL_CLASSID &&
986              context->counter->iftype == STC_IFACE_DATACALL) ||
987             (app_value->classid == STC_TOTAL_WIFI_CLASSID &&
988              context->counter->iftype == STC_IFACE_WIFI) ||
989             (app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
990              context->counter->iftype == STC_IFACE_BLUETOOTH))
991                 __app_counter_update(app_key, app_value, context);
992 }
993
994
995 static gboolean __apps_counter_update_foreach_classid(gpointer key,
996                                                       gpointer value,
997                                                       gpointer data)
998 {
999         stc_app_key_s *app_key = (stc_app_key_s *)key;
1000         stc_app_value_s *app_value = (stc_app_value_s *)value;
1001         classid_bytes_context_s *context = (classid_bytes_context_s *)data;
1002
1003         if (context->counter->intend != NFACCT_COUNTER)
1004                 goto try_next_callback;
1005
1006         __interface_counter_update(app_key, app_value, context);
1007
1008         if (app_value->classid != context->counter->classid)
1009                 goto try_next_callback;
1010
1011         __app_counter_update(app_key, app_value, context);
1012
1013 try_next_callback:
1014         return FALSE;
1015 }
1016
1017 static void __fill_nfacct_result(char *cnt_name, int64_t bytes,
1018                                  struct counter_arg *carg)
1019 {
1020         struct nfacct_rule counter = {
1021                 .carg = carg,
1022                 .name = {0},
1023                 .ifname = {0},
1024                 0
1025         };
1026
1027         classid_bytes_context_s context = {
1028                 .counter = &counter,
1029                 .bytes = bytes,
1030                 .data_limit_reached = FALSE,
1031         };
1032
1033         STC_LOGD("cnt_name %s", cnt_name);
1034
1035         if (!recreate_counter_by_name(cnt_name, &counter)) {
1036                 STC_LOGE("Can't parse counter name %s", cnt_name);
1037                 return;
1038         }
1039
1040         STC_LOGI("classid %lu, iftype %u, iotype %d, intend %d, ifname %s, bytes %lld",
1041                  context.counter->classid, context.counter->iftype,
1042                  context.counter->iotype, context.counter->intend,
1043                  context.counter->ifname, context.bytes);
1044
1045         if (g_system->rstns)
1046                 g_tree_foreach(g_system->rstns,
1047                                __rstn_counter_update_foreach_classid,
1048                                &context);
1049
1050         if (g_system->apps)
1051                 g_tree_foreach(g_system->apps,
1052                                __apps_counter_update_foreach_classid,
1053                                &context);
1054 }
1055
1056 static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
1057                            void *user_data)
1058 {
1059         struct counter_arg *carg = user_data;
1060         char *cnt_name = (char *)RTA_DATA(attr_list[NFACCT_NAME]);
1061         if (carg->initiate) {
1062                 /**
1063                  * TODO: this will be used when daemon starts to update existing
1064                  * counter data if present.
1065                  *
1066                  populate_counters(cnt_name, carg);
1067                  */
1068         } else {
1069                 int64_t *bytes_p =
1070                         (int64_t *)RTA_DATA(attr_list[NFACCT_BYTES]);
1071                 int bytes = be64toh(*bytes_p);
1072                 if (bytes) {
1073                         ++carg->serialized_counters;
1074                         __fill_nfacct_result(cnt_name, bytes, carg);
1075                 }
1076         }
1077
1078         return 0;
1079 }
1080
1081 static int __post_fill_counters(void *user_data)
1082 {
1083         struct counter_arg *carg = user_data;
1084
1085         if (carg->initiate)
1086                 carg->initiate = 0;
1087
1088         return 0;
1089 }
1090
1091 static void __process_network_counter(struct genl *ans,
1092                                       struct counter_arg *carg)
1093 {
1094         struct netlink_serialization_params ser_params = {
1095                 .carg = carg,
1096                 .ans = ans,
1097                 .eval_attr = __fill_counters,
1098                 .post_eval_attr = __post_fill_counters,
1099         };
1100
1101         netlink_serialization_command *netlink =
1102                 netlink_create_command(&ser_params);
1103         if (!netlink) {
1104                 STC_LOGE("Can not create command");
1105                 return;
1106         }
1107
1108         netlink->deserialize_answer(&(netlink->params));
1109 }
1110
1111 static gboolean __process_contr_reply(GIOChannel *source,
1112                                       GIOCondition condition,
1113                                       gpointer user_data)
1114 {
1115         int sock = g_io_channel_unix_get_fd(source);
1116         struct genl ans;
1117         int ret;
1118         stc_s *stc = stc_get_manager();
1119
1120         if ((condition & G_IO_ERR) ||
1121             (condition & G_IO_HUP) ||
1122             (condition & G_IO_NVAL)) {
1123                 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
1124
1125                 STC_LOGE("Counter socket received G_IO event, closing socket."
1126                          "G_IO_ERR [%d], G_IO_HUP [%d], G_IO_NVAL [%s]",
1127                          (condition & G_IO_ERR), (condition & G_IO_HUP),
1128                          (condition & G_IO_NVAL));
1129                 __close_and_reopen_contr_sock(g_system);
1130                 return FALSE;
1131         }
1132
1133         if (stc == NULL) {
1134                 STC_LOGE("Can't get stc data");
1135                 goto out;
1136         }
1137
1138         ret = read_netlink(sock,
1139                            &ans, sizeof(struct genl));
1140         /* STC_LOGD("Counter data received ret [%d]", ret); */
1141         if (ret == 0)
1142                 goto out;
1143
1144         stc->carg->ans_len = ret;
1145         __process_network_counter(&ans, stc->carg);
1146
1147         g_idle_add(__flush_apps_stats_to_database, NULL);
1148         g_idle_add(__flush_rstns_counter_to_database, NULL);
1149 out:
1150         return TRUE;
1151 }
1152
1153 static gboolean __update_contr_cb(void *user_data)
1154 {
1155         /* Here we just sent command, answer we receive in another callback */
1156         stc_s *stc = stc_get_manager();
1157         ret_value_msg_if(stc == NULL, STC_ERROR_FAIL, "Can't get stc data");
1158         if (!stc->carg) {
1159                 stc->carg = MALLOC0(counter_arg_s, 1);
1160                 if (stc->carg == NULL)
1161                         return TRUE;  /* we need to continue the timer */
1162
1163                 stc->carg->sock = stc_monitor_get_counter_socket();
1164         }
1165
1166         /* STC_LOGD("Get all counters"); */
1167         nfacct_send_get_all(stc->carg);
1168
1169         /* we need to continue the timer */
1170         return TRUE;
1171 }
1172 #if 0
1173 static gboolean __rstn_tree_foreach_print(gpointer key, gpointer value,
1174                                           gpointer data)
1175 {
1176         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1177         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1178
1179         __print_rstn(rstn_key, rstn_value);
1180         return FALSE;
1181 }
1182
1183 static void __rstn_tree_printall(void)
1184 {
1185         g_tree_foreach(g_system->rstns, __rstn_tree_foreach_print, NULL);
1186 }
1187 #endif
1188 static stc_rstn_value_s * __rstn_lookup(GTree *rstns_tree,
1189                                         const stc_rstn_key_s *key)
1190 {
1191         stc_rstn_value_s *lookup;
1192
1193         ret_value_msg_if(rstns_tree == NULL, NULL, "rstns_tree is null!");
1194
1195         lookup = g_tree_lookup(rstns_tree, key);
1196
1197         return lookup;
1198 }
1199
1200 static gboolean __remove_restriction(gpointer key, gpointer value,
1201                                      gpointer data)
1202 {
1203         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1204         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1205
1206         /* rstn rule is already removed */
1207         if (rstn_value->rst_state == STC_RESTRICTION_REMOVED)
1208                 return FALSE;
1209
1210         __process_restriction(RST_UNSET, rstn_key, rstn_value, data);
1211         __print_rstn(rstn_key, rstn_value);
1212         return FALSE;
1213 }
1214
1215 static gboolean __add_restriction_debug(gpointer key, gpointer value,
1216                                         gpointer data)
1217 {
1218         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1219         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1220
1221         /* rstn rule is activated */
1222         if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED)
1223                 return FALSE;
1224
1225         if (rstn_value->rst_state == STC_RESTRICTION_EXCLUDED)
1226                 __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
1227         else
1228                 __process_restriction(RST_SET, rstn_key, rstn_value, data);
1229
1230         __print_rstn(rstn_key, rstn_value);
1231
1232         return FALSE;
1233 }
1234
1235 static gboolean __add_restriction(gpointer key, gpointer value, gpointer data)
1236 {
1237         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1238         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1239
1240         /* rstn rule is activated */
1241         if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED)
1242                 return FALSE;
1243
1244         if (rstn_value->rst_state == STC_RESTRICTION_EXCLUDED)
1245                 __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
1246         else
1247                 __process_restriction(RST_SET, rstn_key, rstn_value, data);
1248
1249         return FALSE;
1250 }
1251
1252 static stc_error_e __rstn_tree_remove(stc_rstn_key_s *key)
1253 {
1254         stc_rstn_value_s *lookup_value;
1255
1256         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1257
1258         lookup_value = __rstn_lookup(g_system->rstns, key);
1259         if (!lookup_value) {
1260                 STC_LOGE("key not found");
1261                 return STC_ERROR_NO_DATA;
1262         }
1263
1264         __remove_restriction(key, lookup_value, NULL);
1265
1266         /* remove counter also */
1267         table_counters_delete(lookup_value->restriction_id);
1268
1269         if (!g_tree_remove(g_system->rstns, key)) {
1270                 STC_LOGD("key not found");
1271                 return STC_ERROR_NO_DATA;
1272         }
1273
1274         return STC_ERROR_NONE;
1275 }
1276
1277 static stc_error_e __rstn_tree_add(stc_rstn_key_s *key,
1278                                    stc_rstn_value_s *value, gboolean debug)
1279 {
1280         stc_rstn_value_s *rstn_value;
1281
1282         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1283
1284         rstn_value = __rstn_lookup(g_system->rstns, key);
1285         if (!rstn_value) {
1286                 stc_rstn_key_s *rstn_key = MALLOC0(stc_rstn_key_s, 1);
1287                 if (!rstn_key) {
1288                         STC_LOGE("rstn_key allocation failed");
1289                         return STC_ERROR_OUT_OF_MEMORY;
1290                 }
1291
1292                 rstn_value = MALLOC0(stc_rstn_value_s, 1);
1293                 if (!rstn_value) {
1294                         STC_LOGE("rstn_value allocation failed");
1295                         FREE(rstn_key);
1296                         return STC_ERROR_OUT_OF_MEMORY;
1297                 }
1298
1299                 rstn_key->app_id = g_strdup(key->app_id);
1300                 rstn_key->ifname = g_strdup(key->ifname);
1301                 rstn_key->imsi = g_strdup(key->imsi);
1302                 rstn_key->iftype = key->iftype;
1303                 rstn_key->roaming = key->roaming;
1304
1305                 g_tree_insert(g_system->rstns, rstn_key, rstn_value);
1306         }
1307
1308         rstn_value->restriction_id = value->restriction_id;
1309         rstn_value->rst_state = value->rst_state;
1310         rstn_value->classid = value->classid;
1311         rstn_value->data_limit = value->data_limit;
1312         rstn_value->data_warn_limit = value->data_warn_limit;
1313         rstn_value->data_counter = 0;
1314         rstn_value->warn_limit_crossed_notified = FALSE;
1315         rstn_value->rstn_limit_crossed_notified = FALSE;
1316
1317         if (debug == TRUE)
1318                 __add_restriction_debug(key, rstn_value, NULL);
1319         else
1320                 __add_restriction(key, rstn_value, NULL);
1321
1322         return STC_ERROR_NONE;
1323 }
1324
1325 static stc_cb_ret_e __insert_restriction_cb(const table_restrictions_info *info,
1326                                             void *user_data)
1327 {
1328         stc_cb_ret_e ret = STC_CONTINUE;
1329
1330         stc_rstn_key_s key;
1331         stc_rstn_value_s value;
1332
1333         memset(&key, 0, sizeof(stc_rstn_key_s));
1334         memset(&value, 0, sizeof(stc_rstn_value_s));
1335
1336         key.app_id = g_strdup(info->app_id);
1337         key.ifname = g_strdup(info->ifname);
1338         key.imsi = g_strdup(info->imsi);
1339         key.iftype = info->iftype;
1340         key.roaming = info->roaming;
1341
1342         value.rst_state = info->rst_state;
1343         value.restriction_id = info->restriction_id;
1344
1345         if (value.rst_state != STC_RESTRICTION_EXCLUDED && info->app_id)
1346                 value.classid = get_classid_by_app_id(info->app_id, TRUE);
1347         else
1348                 value.classid = STC_UNKNOWN_CLASSID;
1349
1350         value.data_limit = info->data_limit;
1351         value.data_warn_limit = info->data_warn_limit;
1352
1353         if (__rstn_tree_add(&key, &value, FALSE) != STC_ERROR_NONE)
1354                 ret = STC_CANCEL;
1355
1356         FREE(key.app_id);
1357         FREE(key.ifname);
1358         FREE(key.imsi);
1359         return ret;
1360 }
1361
1362 static void __fill_restritions_list(void)
1363 {
1364         table_restrictions_foreach(__insert_restriction_cb, NULL);
1365         //__rstn_tree_printall();
1366 }
1367
1368 static gboolean __add_rstn_foreach_application(gpointer key,
1369                                                gpointer value,
1370                                                gpointer data)
1371 {
1372         stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key;
1373         stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
1374         gchar *app_id = (gchar *)data;
1375
1376         /* rstn rule is not for applications */
1377         if (rstn_key->app_id == NULL)
1378                 goto out;
1379
1380         /* rstn rule is not for this application */
1381         if (g_strcmp0(rstn_key->app_id, app_id) != 0)
1382                 goto out;
1383
1384         /* rstn rule is already applied */
1385         if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED)
1386                 goto out;
1387
1388         /* add restriction to system */
1389         if (rstn_value->rst_state == STC_RESTRICTION_EXCLUDED)
1390                 __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
1391         else
1392                 __process_restriction(RST_SET, rstn_key, rstn_value, data);
1393
1394         __print_rstn(rstn_key, rstn_value);
1395 out:
1396         return FALSE;
1397 }
1398
1399 static void __add_rstns_for_application(gchar *app_id)
1400 {
1401         g_tree_foreach(g_system->rstns, __add_rstn_foreach_application,
1402                        app_id);
1403 }
1404
1405 static void __add_application_by_interface(const char *app_id)
1406 {
1407         stc_app_key_s app_key;
1408         stc_app_value_s app_value;
1409
1410         if (app_id == NULL)
1411                 return;
1412
1413         memset(&app_key, 0, sizeof(stc_app_key_s));
1414         memset(&app_value, 0, sizeof(stc_app_value_s));
1415
1416         app_key.pkg_id = g_strdup(app_id);
1417         app_key.app_id = g_strdup(app_id);
1418
1419         app_value.type = STC_APP_TYPE_NONE;
1420         app_value.processes = NULL;
1421         app_value.counter.in_bytes = 0;
1422         app_value.counter.out_bytes = 0;
1423
1424         stc_monitor_application_add(app_key, app_value);
1425
1426         FREE(app_key.pkg_id);
1427         FREE(app_key.app_id);
1428 }
1429
1430 static int __vconf_get_int(const char *key, int *value)
1431 {
1432         int ret = 0;
1433
1434         ret = vconf_get_int(key, value);
1435         if (ret != VCONF_OK) {
1436                 STC_LOGE("Failed to get vconfkey [%s] value", key);
1437                 return -1;
1438         }
1439
1440         return 0;
1441 }
1442
1443 static int __vconf_set_int(const char *key, int value)
1444 {
1445         int ret = 0;
1446
1447         ret = vconf_set_int(key, value);
1448         if (ret != VCONF_OK) {
1449                 STC_LOGE("Failed to set vconfkey [%s] value", key);
1450                 return -1;
1451         }
1452
1453         return 0;
1454 }
1455
1456 static guint __get_background_state(void)
1457 {
1458         return g_system->background_state;;
1459 }
1460
1461 static void __set_background_state(guint state)
1462 {
1463         g_system->background_state = state;
1464 }
1465
1466 static gboolean __processes_tree_foreach_background(gpointer key,
1467                                                     gpointer value,
1468                                                     gpointer data)
1469 {
1470         stc_process_key_s *proc_key = (stc_process_key_s *)key;
1471         stc_app_key_s *app_key = (stc_app_key_s *)data;
1472
1473         if (g_system->background_state)
1474                 place_pids_to_net_cgroup(proc_key->pid, STC_BACKGROUND_APP_ID);
1475         else
1476                 place_pids_to_net_cgroup(proc_key->pid, app_key->app_id);
1477
1478         return FALSE;
1479 }
1480
1481 static gboolean __apps_tree_foreach_background(gpointer key, gpointer value,
1482                                         gpointer data)
1483 {
1484         stc_app_key_s *app_key = (stc_app_key_s *)key;
1485         stc_app_value_s *app_value = (stc_app_value_s *)value;
1486
1487         if (strstr(app_key->app_id, STC_BACKGROUND_APP_SUFFIX))
1488                 g_tree_foreach(app_value->processes,
1489                                __processes_tree_foreach_background, app_key);
1490
1491         return FALSE;
1492 }
1493
1494 static stc_error_e __process_update_background(void)
1495 {
1496         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1497
1498         g_tree_foreach(g_system->apps, __apps_tree_foreach_background, NULL);
1499
1500         return STC_ERROR_NONE;
1501 }
1502
1503 static void __excn_hash_foreach_print(gpointer key, gpointer value,
1504                                           gpointer data)
1505 {
1506         const char *process_name = key;
1507         const char *exe_type = value;
1508
1509         STC_LOGI("excn info => process_name [%s] exe_type [%s]",
1510                 process_name, exe_type);
1511 }
1512
1513 static void __excn_hash_printall(void)
1514 {
1515         g_hash_table_foreach(g_system->excns_hash,
1516                 __excn_hash_foreach_print, NULL);
1517 }
1518
1519 static stc_cb_ret_e __insert_exception_cb(const table_exceptions_info *info,
1520                                             void *user_data)
1521 {
1522         stc_cb_ret_e ret = STC_CONTINUE;
1523
1524         if (g_hash_table_insert(g_system->excns_hash,
1525                         g_strdup(info->process_name),
1526                         g_strdup(info->exe_type)) != TRUE)
1527                 ret = STC_CANCEL;
1528
1529         return ret;
1530 }
1531
1532 static void __fill_exceptions_list(void)
1533 {
1534         table_exceptions_foreach(__insert_exception_cb, NULL);
1535         __excn_hash_printall();
1536 }
1537
1538 stc_error_e stc_monitor_init(void)
1539 {
1540         stc_system_s *system = MALLOC0(stc_system_s, 1);
1541         GIOChannel *gio = NULL;
1542
1543         ret_value_msg_if(system == NULL, STC_ERROR_OUT_OF_MEMORY, "stc_system_s malloc fail!");
1544
1545         /* initializing cgroups */
1546         cgroup_init();
1547
1548         /* creating monitored application tree */
1549         system->apps = g_tree_new_full(__apps_tree_key_compare, NULL,
1550                                        __apps_tree_key_free,
1551                                        __apps_tree_value_free);
1552
1553         system->rstns = g_tree_new_full(__rstns_tree_key_compare, NULL,
1554                                         __rstns_tree_key_free,
1555                                         __rstns_tree_value_free);
1556
1557         system->excns_hash = g_hash_table_new_full(g_str_hash,
1558                                         g_str_equal, g_free, g_free);
1559
1560         /* create netlink socket for updating kernel counters */
1561         system->contr_sock = create_netlink(NETLINK_NETFILTER, 0);
1562         if (!(system->contr_sock)) {
1563                 STC_LOGE("failed to open socket");
1564                 FREE(system);
1565                 return STC_ERROR_FAIL;
1566         }
1567
1568         gio = g_io_channel_unix_new(system->contr_sock);
1569         system->contr_gsource_id =
1570                 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
1571                                (GIOFunc) __process_contr_reply,
1572                                NULL);
1573         g_io_channel_unref(gio);
1574
1575         g_system = system;
1576
1577         __add_application_by_interface(STC_TOTAL_DATACALL);
1578         __add_application_by_interface(STC_TOTAL_WIFI);
1579         __add_application_by_interface(STC_TOTAL_BLUETOOTH);
1580         __add_application_by_interface(STC_TOTAL_IPV4);
1581         __add_application_by_interface(STC_TOTAL_IPV6);
1582
1583         /* creating restriction rules tree */
1584         __update_contr_cb(NULL);
1585
1586         /* registering periodic kernel counters update callback */
1587         g_system->contr_timer_id = g_timeout_add_seconds(CONTR_TIMER_INTERVAL,
1588                                                          __update_contr_cb,
1589                                                          NULL);
1590         if (g_system->contr_timer_id == 0) {
1591                 STC_LOGE("Failed to register kernel counters update timer");
1592                 __close_contr_sock(g_system);
1593                 return STC_ERROR_FAIL;
1594         }
1595
1596         __vconf_get_int(VCONFKEY_STC_BACKGROUND_STATE,
1597                         (int *)&g_system->background_state);
1598
1599         __fill_exceptions_list();
1600         __fill_restritions_list();
1601
1602         return STC_ERROR_NONE;
1603 }
1604
1605 stc_error_e stc_monitor_deinit(void)
1606 {
1607         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1608
1609         /* close netlink socket for updating kernel counters */
1610         __close_contr_sock(g_system);
1611
1612         /* remove kernel counters update timer */
1613         if (g_system->contr_timer_id > 0) {
1614                 g_source_remove(g_system->contr_timer_id);
1615                 g_system->contr_timer_id = 0;
1616         }
1617
1618         /* destroy monitored application tree */
1619         g_tree_destroy(g_system->apps);
1620         g_system->apps = NULL;
1621
1622         /* destroy restriction rules tree */
1623         g_tree_destroy(g_system->rstns);
1624         g_system->rstns = NULL;
1625
1626         /* destroy exception hash table */
1627         g_hash_table_destroy(g_system->excns_hash);
1628         g_system->excns_hash = NULL;
1629
1630         FREE(g_system);
1631
1632         return STC_ERROR_NONE;
1633 }
1634
1635 stc_error_e stc_monitor_application_add(const stc_app_key_s app_key,
1636                                         const stc_app_value_s app_value)
1637 {
1638         stc_error_e ret = STC_ERROR_NONE;
1639         stc_app_key_s *key;
1640         stc_app_value_s *value;
1641         stc_app_value_s *lookup;
1642
1643         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1644
1645         lookup = __application_lookup(g_system->apps, &app_key);
1646         if (lookup) {
1647                 STC_LOGD("app_key already present");
1648                 return STC_ERROR_NONE;
1649         }
1650
1651         key = MALLOC0(stc_app_key_s, 1);
1652         if (!key) {
1653                 STC_LOGE("key allocation failed");
1654                 return STC_ERROR_OUT_OF_MEMORY;
1655         }
1656
1657         value = MALLOC0(stc_app_value_s, 1);
1658         if (!value) {
1659                 STC_LOGE("value allocation failed");
1660                 FREE(key);
1661                 return STC_ERROR_OUT_OF_MEMORY;
1662         }
1663
1664         key->app_id = g_strdup(app_key.app_id);
1665         key->pkg_id = g_strdup(app_key.pkg_id);
1666
1667         value->type = app_value.type;
1668         value->data_usage.in_bytes = app_value.data_usage.in_bytes;
1669         value->data_usage.out_bytes = app_value.data_usage.out_bytes;
1670
1671         value->processes = g_tree_new_full(__processes_tree_key_compare, NULL,
1672                                            __processes_tree_key_free,
1673                                            __processes_tree_value_free);
1674
1675         /* create cgroup and update classid */
1676         value->classid = get_classid_by_app_id(app_key.app_id, TRUE);
1677
1678         g_tree_insert(g_system->apps, key, value);
1679
1680         /* add nfacct rule for this classid */
1681         __add_application_monitor(key, value, stc_get_default_connection());
1682         __add_rstns_for_application(app_key.app_id);
1683
1684         return ret;
1685 }
1686
1687 stc_error_e stc_monitor_process_add(const stc_app_key_s app_key,
1688                                     const stc_process_key_s proc_key,
1689                                     const stc_process_value_s proc_value)
1690 {
1691         stc_error_e ret = STC_ERROR_NONE;
1692         stc_app_value_s *app_lookup;
1693         stc_process_key_s *key;
1694         stc_process_value_s *value;
1695         stc_process_value_s *proc_lookup;
1696
1697         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1698
1699         app_lookup = __application_lookup(g_system->apps, &app_key);
1700         if (!app_lookup) {
1701                 STC_LOGD("app_key not found");
1702                 return STC_ERROR_FAIL;
1703         }
1704
1705         proc_lookup = __process_lookup(app_lookup->processes, &proc_key);
1706         if (proc_lookup) {
1707                 STC_LOGD("proc_key already present");
1708                 return STC_ERROR_NONE;
1709         }
1710
1711         key = MALLOC0(stc_process_key_s, 1);
1712         if (!key) {
1713                 STC_LOGE("key allocation failed");
1714                 return STC_ERROR_OUT_OF_MEMORY;
1715         }
1716
1717         value = MALLOC0(stc_process_value_s, 1);
1718         if (!value) {
1719                 STC_LOGE("value allocation failed");
1720                 FREE(key);
1721                 return STC_ERROR_OUT_OF_MEMORY;
1722         }
1723
1724         key->pid = proc_key.pid;
1725
1726         value->ground = proc_value.ground;
1727
1728         g_tree_insert(app_lookup->processes, key, value);
1729
1730         /* add pid to application cgroup */
1731         place_pids_to_net_cgroup(proc_key.pid, app_key.app_id);
1732
1733         return ret;
1734 }
1735
1736 stc_error_e stc_monitor_process_remove(pid_t pid)
1737 {
1738         stc_error_e ret = STC_ERROR_NONE;
1739         stc_process_key_s proc_key = {
1740                 .pid = pid
1741         };
1742
1743         remove_pid_context_s context = {
1744                 .app_key = NULL,
1745                 .proc_key = &proc_key,
1746                 .entry_removed = FALSE,
1747         };
1748
1749         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1750
1751         g_tree_foreach(g_system->apps, __apps_tree_foreach_remove_pid,
1752                        &context);
1753
1754         if (context.entry_removed)
1755                 __application_remove_if_empty(context.app_key);
1756
1757         return ret;
1758 }
1759
1760 stc_error_e stc_monitor_process_update_ground(const stc_app_key_s app_key,
1761                                               const stc_process_key_s proc_key,
1762                                               stc_app_state_e ground)
1763 {
1764         stc_error_e ret = STC_ERROR_NONE;
1765         stc_app_value_s *app_lookup;
1766         stc_process_value_s *proc_lookup;
1767
1768         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1769
1770         app_lookup = __application_lookup(g_system->apps, &app_key);
1771         if (!app_lookup) {
1772                 STC_LOGD("app_key not found");
1773                 return STC_ERROR_FAIL;
1774         }
1775
1776         proc_lookup = __process_lookup(app_lookup->processes, &proc_key);
1777         if (!proc_lookup) {
1778                 STC_LOGD("proc_key not found");
1779                 return STC_ERROR_FAIL;
1780         }
1781
1782         if (proc_lookup->ground != ground)
1783                 proc_lookup->ground = ground;
1784
1785         if (ground == STC_APP_STATE_BACKGROUND && __get_background_state())
1786                 place_pids_to_net_cgroup(proc_key.pid, STC_BACKGROUND_APP_ID);
1787         else
1788                 place_pids_to_net_cgroup(proc_key.pid, app_key.app_id);
1789
1790         return ret;
1791 }
1792
1793 void stc_monitor_update_rstn_by_default_connection(void *data)
1794 {
1795         static default_connection_s old_connection;
1796         default_connection_s *new_connection = (default_connection_s *)data;
1797
1798         if (old_connection.path != NULL) {
1799                 if (g_system->apps)
1800                         g_tree_foreach(g_system->apps,
1801                                        __remove_application_monitor,
1802                                        (gpointer)&old_connection);
1803
1804                 if (g_system->rstns)
1805                         g_tree_foreach(g_system->rstns,
1806                                        __remove_restriction,
1807                                        (gpointer)&old_connection);
1808         }
1809
1810         FREE(old_connection.path);
1811         FREE(old_connection.ifname);
1812         old_connection.type = 0;
1813         old_connection.roaming = 0;
1814
1815         if (new_connection != NULL && new_connection->path != NULL) {
1816                 if (g_system->apps)
1817                         g_tree_foreach(g_system->apps,
1818                                        __add_application_monitor,
1819                                        (gpointer)new_connection);
1820
1821                 if (g_system->rstns)
1822                         g_tree_foreach(g_system->rstns, __add_restriction,
1823                                        NULL);
1824
1825                 old_connection.path = g_strdup(new_connection->path);
1826                 old_connection.ifname = g_strdup(new_connection->ifname);
1827                 old_connection.type = new_connection->type;
1828                 old_connection.roaming = new_connection->roaming;
1829         }
1830 }
1831
1832 stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info)
1833 {
1834         stc_error_e ret;
1835
1836         stc_rstn_key_s key;
1837         stc_rstn_value_s value;
1838
1839         memset(&key, 0, sizeof(stc_rstn_key_s));
1840         memset(&value, 0, sizeof(stc_rstn_value_s));
1841
1842         key.app_id = g_strdup(info->app_id);
1843         key.ifname = g_strdup(info->ifname);
1844         key.imsi = g_strdup(info->imsi);
1845         key.iftype = info->iftype;
1846         key.roaming = info->roaming;
1847
1848         value.rst_state = info->rst_state;
1849         value.restriction_id = info->restriction_id;
1850
1851         if (value.rst_state != STC_RESTRICTION_EXCLUDED && info->app_id)
1852                 value.classid = get_classid_by_app_id(info->app_id, TRUE);
1853         else
1854                 value.classid = STC_UNKNOWN_CLASSID;
1855
1856         if (value.classid == STC_BACKGROUND_APP_CLASSID) {
1857                 __set_background_state(TRUE);
1858                 __vconf_set_int(VCONFKEY_STC_BACKGROUND_STATE, g_system->background_state);
1859                 __process_update_background();
1860         }
1861
1862         value.data_limit = info->data_limit;
1863         value.data_warn_limit = info->data_warn_limit;
1864
1865         ret = __rstn_tree_add(&key, &value, TRUE);
1866
1867         FREE(key.app_id);
1868         FREE(key.ifname);
1869         FREE(key.imsi);
1870         return ret;
1871 }
1872
1873 stc_error_e stc_monitor_rstns_tree_remove(const table_restrictions_info *info)
1874 {
1875         stc_error_e ret;
1876
1877         stc_rstn_key_s key = {
1878                 .app_id = g_strdup(info->app_id),
1879                 .ifname = g_strdup(info->ifname),
1880                 .imsi = g_strdup(info->imsi),
1881                 .iftype = info->iftype,
1882                 .roaming = info->roaming,
1883         };
1884
1885         if (!strcmp(key.app_id, STC_BACKGROUND_APP_ID)) {
1886                 __set_background_state(FALSE);
1887                 __vconf_set_int(VCONFKEY_STC_BACKGROUND_STATE, g_system->background_state);
1888                 __process_update_background();
1889         }
1890
1891         ret = __rstn_tree_remove(&key);
1892
1893         FREE(key.app_id);
1894         FREE(key.ifname);
1895         FREE(key.imsi);
1896         return ret;
1897 }
1898
1899 stc_error_e stc_monitor_check_excn_by_cmdline(char *cmdline)
1900 {
1901         ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
1902
1903         char *exe_type = NULL;
1904
1905         exe_type = g_hash_table_lookup(g_system->excns_hash, cmdline);
1906         if (!exe_type)
1907                 return STC_ERROR_NO_DATA;
1908
1909         return STC_ERROR_NONE;
1910 }
1911
1912 int stc_monitor_get_counter_socket(void)
1913 {
1914         return g_system->contr_sock;
1915 }