tizen 2.3 release
[kernel/api/system-resource.git] / src / network / app-stat.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20
21 /*
22  * @file app-stat.c
23  *
24  * @desc application statistics entity helper functions
25  */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <pthread.h>
30
31 #include "app-stat.h"
32 #include "net-cls-cgroup.h"
33 #include "iface.h"
34 #include "macro.h"
35 #include "roaming.h"
36 #include "trace.h"
37
38 static void free_app(gpointer data)
39 {
40         struct application_stat *app_stat = (struct application_stat *)data;
41         if (!app_stat)
42                 return;
43
44         if (app_stat->application_id)
45                 free(app_stat->application_id);
46
47         free(app_stat);
48 }
49
50 static gint compare_classid(gconstpointer a, gconstpointer b,
51         gpointer __attribute__((__unused__)) userdata)
52 {
53         const struct classid_iftype_key *a_key = (struct classid_iftype_key*)a;
54         const struct classid_iftype_key *b_key = (struct classid_iftype_key*)b;
55         gint ret = 0;
56
57         ret = a_key->classid - b_key->classid;
58         if (!ret)
59                 return ret;
60
61         ret = a_key->iftype - b_key->iftype;
62         if (!ret)
63                 return ret;
64
65         return strcmp(a_key->ifname, b_key->ifname);
66 }
67
68 static void free_stat(gpointer data)
69 {
70         free(data);
71 }
72
73 struct application_stat_tree *create_app_stat_tree(void)
74 {
75         int ret;
76         struct application_stat_tree *app_stat_tree;
77         app_stat_tree =
78                 (struct application_stat_tree *) malloc
79                 (sizeof(struct application_stat_tree));
80         if (!app_stat_tree) {
81                 _E("Malloc of create_app_stat_tree failed\n");
82                 return NULL;
83         }
84
85         app_stat_tree->tree =
86                 (GTree *)g_tree_new_full(compare_classid,
87                                                          NULL, free_stat,
88                                                          free_app);
89         app_stat_tree->last_touch_time = time(0);
90         ret = pthread_rwlock_init(&app_stat_tree->guard, NULL);
91         if (ret != 0) {
92                 _E("Could not initialize tree guard %s.", strerror(ret));
93                 free(app_stat_tree);
94                 app_stat_tree = NULL;
95         }
96         return app_stat_tree;
97 }
98
99 void free_app_stat_tree(struct application_stat_tree *app_stat_tree)
100 {
101         /* do not check null pointer because it makes g_tree_destroy */
102         ret_msg_if(app_stat_tree == NULL,
103                 "Please provide valid app_stat_tree!");
104         g_tree_destroy((GTree *)app_stat_tree->tree);
105 }
106
107 void nulify_app_stat_tree(struct application_stat_tree **app_stat_tree)
108 {
109         free_app_stat_tree(*app_stat_tree);
110         free(*app_stat_tree);
111         *app_stat_tree = NULL;
112 }
113
114 traffic_stat_tree *create_traffic_stat_tree(void)
115 {
116         return g_tree_new_full(compare_classid, NULL, NULL, free_stat);
117 }
118
119 void free_traffic_stat_tree(traffic_stat_tree *tree)
120 {
121         g_tree_destroy((GTree *) tree);
122 }
123
124 static gboolean set_app_id(gpointer key, gpointer value,
125         void __attribute__((__unused__)) *data)
126 {
127         /* Open closed principle would be better here */
128         struct application_stat *stat = (struct application_stat *)value;
129         u_int32_t classid = ((struct classid_iftype_key*)key)->classid;
130
131         /* No need to request update classid table per each app entry */
132         stat->application_id = get_app_id_by_classid(classid, false);
133         return FALSE;
134 }
135
136 static inline void identify_application(
137         struct application_stat_tree *app_stat_tree)
138 {
139         g_tree_foreach(app_stat_tree->tree, (GTraverseFunc)set_app_id, NULL);
140 }
141
142 static gboolean fill_incomming(gpointer key,
143         gpointer value, gpointer data)
144 {
145         struct application_stat_tree *app_tree =
146                 (struct application_stat_tree *)data;
147         struct traffic_stat *in_event = (struct traffic_stat *)value;
148
149         struct application_stat *app_stat = NULL;
150         if (!is_allowed_ifindex(in_event->ifindex))
151                 return FALSE;
152
153         app_stat = (struct application_stat *)
154                 g_tree_lookup((GTree *)app_tree->tree, key);
155         if (app_stat)
156                 app_stat->rcv_count += in_event->bytes;
157         else {
158                 app_stat = g_new(struct application_stat, 1);
159                 memset(app_stat, 0, sizeof(struct application_stat));
160                 app_stat->rcv_count = in_event->bytes;
161                 g_tree_insert((GTree *)app_tree->tree, key, app_stat);
162         }
163         app_stat->delta_rcv += in_event->bytes;
164
165         /*only for debug purpose*/
166         if (!app_stat->ifindex)
167                 app_stat->ifindex = in_event->ifindex;
168
169         app_stat->is_roaming = get_roaming();
170         return FALSE;
171 }
172
173 static gboolean fill_outgoing(gpointer key,
174         gpointer value, gpointer data)
175 {
176         struct application_stat_tree *app_tree =
177                 (struct application_stat_tree *)data;
178         struct traffic_stat *out_event = (struct traffic_stat *)value;
179
180         struct application_stat *app_stat = (struct application_stat *)
181                 g_tree_lookup((GTree *)app_tree->tree, key);
182         if (app_stat)
183                 app_stat->snd_count += out_event->bytes;
184         else {
185                 app_stat = g_new(struct application_stat, 1);
186                 memset(app_stat, 0, sizeof(struct application_stat));
187                 app_stat->snd_count = out_event->bytes;
188                 g_tree_insert((GTree *)app_tree->tree, key, app_stat);
189         }
190         app_stat->delta_snd += out_event->bytes;
191
192         if (!app_stat->ifindex)
193                 app_stat->ifindex = out_event->ifindex;
194
195         if (!app_stat->is_roaming)
196                 app_stat->is_roaming = get_roaming();
197         return FALSE;
198 }
199
200
201 static void fill_result(traffic_stat_tree *tree_in,
202                 traffic_stat_tree *tree_out,
203                 struct application_stat_tree *result)
204 {
205
206         g_tree_foreach(tree_in, (GTraverseFunc)fill_incomming, result);
207         g_tree_foreach(tree_out, (GTraverseFunc)fill_outgoing, result);
208 }
209
210 resourced_ret_c prepare_application_stat(traffic_stat_tree *tree_in,
211                              traffic_stat_tree *tree_out,
212                              struct application_stat_tree *result,
213                              volatile struct daemon_opts *opts)
214 {
215         fill_result(tree_in, tree_out, result);
216         identify_application(result);
217
218         return RESOURCED_ERROR_NONE;
219 }