tizen 2.3.1 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         char buf[256];
77         struct application_stat_tree *app_stat_tree;
78         app_stat_tree =
79                 (struct application_stat_tree *) malloc
80                 (sizeof(struct application_stat_tree));
81         if (!app_stat_tree) {
82                 _E("Malloc of create_app_stat_tree failed\n");
83                 return NULL;
84         }
85
86         app_stat_tree->tree =
87                 (GTree *)g_tree_new_full(compare_classid,
88                                                          NULL, free_stat,
89                                                          free_app);
90         app_stat_tree->last_touch_time = time(0);
91         ret = pthread_rwlock_init(&app_stat_tree->guard, NULL);
92         if (ret != 0) {
93                 strerror_r(ret, buf, sizeof(buf));
94                 _E("Could not initialize tree guard %s.", buf);
95                 free(app_stat_tree);
96                 app_stat_tree = NULL;
97         }
98         return app_stat_tree;
99 }
100
101 void free_app_stat_tree(struct application_stat_tree *app_stat_tree)
102 {
103         /* do not check null pointer because it makes g_tree_destroy */
104         ret_msg_if(app_stat_tree == NULL,
105                 "Please provide valid app_stat_tree!");
106         g_tree_destroy((GTree *)app_stat_tree->tree);
107 }
108
109 void nulify_app_stat_tree(struct application_stat_tree **app_stat_tree)
110 {
111         free_app_stat_tree(*app_stat_tree);
112         free(*app_stat_tree);
113         *app_stat_tree = NULL;
114 }
115
116 traffic_stat_tree *create_traffic_stat_tree(void)
117 {
118         return g_tree_new_full(compare_classid, NULL, NULL, free_stat);
119 }
120
121 void free_traffic_stat_tree(traffic_stat_tree *tree)
122 {
123         g_tree_destroy((GTree *) tree);
124 }
125
126 static gboolean set_app_id(gpointer key, gpointer value,
127         void __attribute__((__unused__)) *data)
128 {
129         /* Open closed principle would be better here */
130         struct application_stat *stat = (struct application_stat *)value;
131         u_int32_t classid = ((struct classid_iftype_key*)key)->classid;
132
133         /* No need to request update classid table per each app entry */
134         stat->application_id = get_app_id_by_classid(classid, false);
135         return FALSE;
136 }
137
138 static inline void identify_application(
139         struct application_stat_tree *app_stat_tree)
140 {
141         g_tree_foreach(app_stat_tree->tree, (GTraverseFunc)set_app_id, NULL);
142 }
143
144 static gboolean fill_incomming(gpointer key,
145         gpointer value, gpointer data)
146 {
147         struct application_stat_tree *app_tree =
148                 (struct application_stat_tree *)data;
149         struct traffic_stat *in_event = (struct traffic_stat *)value;
150
151         struct application_stat *app_stat = NULL;
152         if (!is_allowed_ifindex(in_event->ifindex))
153                 return FALSE;
154
155         app_stat = (struct application_stat *)
156                 g_tree_lookup((GTree *)app_tree->tree, key);
157         if (app_stat)
158                 app_stat->rcv_count += in_event->bytes;
159         else {
160                 app_stat = g_new(struct application_stat, 1);
161                 memset(app_stat, 0, sizeof(struct application_stat));
162                 app_stat->rcv_count = in_event->bytes;
163                 g_tree_insert((GTree *)app_tree->tree, key, app_stat);
164         }
165         app_stat->delta_rcv += in_event->bytes;
166
167         /*only for debug purpose*/
168         if (!app_stat->ifindex)
169                 app_stat->ifindex = in_event->ifindex;
170
171         app_stat->is_roaming = get_roaming();
172         return FALSE;
173 }
174
175 static gboolean fill_outgoing(gpointer key,
176         gpointer value, gpointer data)
177 {
178         struct application_stat_tree *app_tree =
179                 (struct application_stat_tree *)data;
180         struct traffic_stat *out_event = (struct traffic_stat *)value;
181
182         struct application_stat *app_stat = (struct application_stat *)
183                 g_tree_lookup((GTree *)app_tree->tree, key);
184         if (app_stat)
185                 app_stat->snd_count += out_event->bytes;
186         else {
187                 app_stat = g_new(struct application_stat, 1);
188                 memset(app_stat, 0, sizeof(struct application_stat));
189                 app_stat->snd_count = out_event->bytes;
190                 g_tree_insert((GTree *)app_tree->tree, key, app_stat);
191         }
192         app_stat->delta_snd += out_event->bytes;
193
194         if (!app_stat->ifindex)
195                 app_stat->ifindex = out_event->ifindex;
196
197         if (!app_stat->is_roaming)
198                 app_stat->is_roaming = get_roaming();
199         return FALSE;
200 }
201
202
203 static void fill_result(traffic_stat_tree *tree_in,
204                 traffic_stat_tree *tree_out,
205                 struct application_stat_tree *result)
206 {
207
208         g_tree_foreach(tree_in, (GTraverseFunc)fill_incomming, result);
209         g_tree_foreach(tree_out, (GTraverseFunc)fill_outgoing, result);
210 }
211
212 resourced_ret_c prepare_application_stat(traffic_stat_tree *tree_in,
213                              traffic_stat_tree *tree_out,
214                              struct application_stat_tree *result,
215                              volatile struct daemon_opts *opts)
216 {
217         fill_result(tree_in, tree_out, result);
218         identify_application(result);
219
220         return RESOURCED_ERROR_NONE;
221 }