tizen 2.3.1 release
[kernel/api/system-resource.git] / src / network / foreach.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 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  * @file foreach.c
22  * @desc Implementation of the datausage foreach function.
23  *
24  */
25
26
27 #include <sqlite3.h>
28 #include <string.h>
29
30 #include "database.h"
31 #include "data_usage.h"
32 #include "datausage-foreach.h"
33 #include "macro.h"
34 #include "trace.h"
35
36 #define DATA_USAGE_FOR_PERIOD "select binpath, hw_net_protocol_type, "  \
37         "is_roaming, sum(received) as received, "                       \
38         "sum(sent) as sent from statistics where time_stamp between ? and ? " \
39         "group by binpath, is_roaming order by received desc"
40
41 #define DATA_USAGE_FOR_PERIOD_IFACE "select binpath, hw_net_protocol_type, " \
42         "is_roaming, sum(received) as received, "                       \
43         "sum(sent) as sent from statistics where time_stamp between ? and ? " \
44         "and iftype=? group by binpath, is_roaming order by received desc"
45
46 #define DATA_USAGE_CHUNKS "select binpath, hw_net_protocol_type, "      \
47         "is_roaming, sum(received) as received, "                       \
48         "sum(sent) as sent, time_stamp - time_stamp % ? as time_stamp " \
49         "from statistics where time_stamp between ? and ? " \
50         "group by binpath, time_stamp order by time_stamp"
51
52 #define DATA_USAGE_CHUNKS_IFACE "select binpath, hw_net_protocol_type, " \
53         "is_roaming, sum(received) as received, "                       \
54         "sum(sent) as sent, time_stamp as start_time, "                 \
55         "time_stamp - time_stamp % ? as time_stamp " \
56         "from statistics where time_stamp between ? and ? and iftype=?" \
57         "group by binpath, time_stamp order by time_stamp"
58
59 #define DATA_USAGE_APP_DETAILS "select iftype, hw_net_protocol_type, "  \
60         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
61         "ifname from statistics where time_stamp between ? and ? " \
62         "and binpath=? group by binpath, iftype, is_roaming order by iftype"
63
64 #define DATA_USAGE_APP_DETAILS_IFACE "select iftype, hw_net_protocol_type, " \
65         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
66         "ifname from statistics where time_stamp between ? and ? " \
67         "and binpath=? and iftype=?"
68
69 #define DATA_USAGE_CHUNKS_APP "select iftype, hw_net_protocol_type, "   \
70         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
71         "ifname, time_stamp - time_stamp % ? as time_stamp " \
72         "from statistics where time_stamp between ? and ? and binpath = ? " \
73         "group by iftype, time_stamp order by time_stamp, iftype"
74
75 #define DATA_USAGE_CHUNKS_APP_IFACE "select iftype, hw_net_protocol_type, " \
76         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
77         "ifname, time_stamp - time_stamp % ? as time_stamp " \
78         "from statistics where time_stamp between ? and ? and binpath = ? " \
79         "and iftype = ? group by time_stamp order by time_stamp"
80
81 #define DATA_USAGE_TOTAL "select iftype, hw_net_protocol_type, "        \
82         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
83         "ifname from statistics where time_stamp between ? and ? " \
84         "group by iftype order by iftype, is_roaming"
85
86 #define DATA_USAGE_TOTAL_IFACE "select iftype, hw_net_protocol_type, "  \
87         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
88         "ifname from statistics where time_stamp between ? and ? " \
89         "and iftype=?"
90
91 #define DATA_USAGE_CHUNKS_TOTAL "select iftype, hw_net_protocol_type, " \
92         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
93         "ifname, time_stamp - time_stamp % ? as time_stamp " \
94         "from statistics where time_stamp between ? and ? "             \
95         "group by iftype, time_stamp order by time_stamp, iftype"
96
97 #define DATA_USAGE_CHUNKS_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \
98         "is_roaming, sum(received) as received, sum(sent) as sent, "    \
99         "ifname, time_stamp - time_stamp % ? as time_stamp " \
100         "from statistics where time_stamp between ? and ? "             \
101         "and iftype = ? group by time_stamp order by time_stamp"
102
103 static sqlite3_stmt *data_usage_for_period;
104 static sqlite3_stmt *data_usage_for_period_iface;
105 static sqlite3_stmt *data_usage_chunks;
106 static sqlite3_stmt *data_usage_chunks_iface;
107 static sqlite3_stmt *data_usage_app_details;
108 static sqlite3_stmt *data_usage_app_details_iface;
109 static sqlite3_stmt *data_usage_chunks_app;
110 static sqlite3_stmt *data_usage_chunks_app_iface;
111 static sqlite3_stmt *data_usage_total;
112 static sqlite3_stmt *data_usage_total_iface;
113 static sqlite3_stmt *data_usage_chunks_total;
114 static sqlite3_stmt *data_usage_chunks_total_iface;
115
116 #define PREPARE(stm, query) do {                                \
117         rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL);     \
118         if (rc != SQLITE_OK) {                                  \
119                 stm = NULL;                                     \
120                 finalize_datausage_foreach();                           \
121                 _E("Failed to prepare %s\n", query);            \
122                 return rc;                                      \
123         }                                                       \
124 } while (0)
125
126 int init_datausage_foreach(sqlite3 *db)
127 {
128         int rc;
129         static int initialized;
130
131         if (initialized)
132                 return SQLITE_OK;
133
134         PREPARE(data_usage_for_period, DATA_USAGE_FOR_PERIOD);
135         PREPARE(data_usage_for_period_iface, DATA_USAGE_FOR_PERIOD_IFACE);
136         PREPARE(data_usage_chunks, DATA_USAGE_CHUNKS);
137         PREPARE(data_usage_chunks_iface, DATA_USAGE_CHUNKS_IFACE);
138         PREPARE(data_usage_app_details, DATA_USAGE_APP_DETAILS);
139         PREPARE(data_usage_app_details_iface, DATA_USAGE_APP_DETAILS_IFACE);
140         PREPARE(data_usage_chunks_app, DATA_USAGE_CHUNKS_APP);
141         PREPARE(data_usage_chunks_app_iface, DATA_USAGE_CHUNKS_APP_IFACE);
142         PREPARE(data_usage_total, DATA_USAGE_TOTAL);
143         PREPARE(data_usage_total_iface, DATA_USAGE_TOTAL_IFACE);
144         PREPARE(data_usage_chunks_total, DATA_USAGE_CHUNKS_TOTAL);
145         PREPARE(data_usage_chunks_total_iface, DATA_USAGE_CHUNKS_TOTAL_IFACE);
146
147         initialized = 1;
148         return SQLITE_OK;
149 }
150
151 #define FINALIZE(stm) do {              \
152         if (stm) {                      \
153                 sqlite3_finalize(stm);  \
154                 stm = NULL;             \
155         }                               \
156 } while (0)
157
158 void finalize_datausage_foreach(void)
159 {
160         FINALIZE(data_usage_for_period);
161         FINALIZE(data_usage_for_period_iface);
162         FINALIZE(data_usage_chunks);
163         FINALIZE(data_usage_chunks_iface);
164         FINALIZE(data_usage_app_details);
165         FINALIZE(data_usage_app_details_iface);
166         FINALIZE(data_usage_chunks_app);
167         FINALIZE(data_usage_chunks_app_iface);
168         FINALIZE(data_usage_total);
169         FINALIZE(data_usage_total_iface);
170         FINALIZE(data_usage_chunks_total);
171         FINALIZE(data_usage_chunks_total_iface);
172 }
173
174 static int is_iftype_defined(const resourced_iface_type iftype)
175 {
176         return iftype < RESOURCED_IFACE_LAST_ELEM &&
177                iftype > RESOURCED_IFACE_UNKNOWN &&
178                iftype != RESOURCED_IFACE_ALL;
179 }
180
181 API resourced_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
182                                        data_usage_info_cb info_cb,
183                                        void *user_data)
184 {
185         data_usage_info data;
186         sqlite3_stmt *stm;
187         resourced_ret_c result = RESOURCED_ERROR_NONE;
188         resourced_counters *cnt = &data.foreground.cnt;
189         int rc;
190         int pos = 1;/* running through positions where to
191                 bind parameters in the query */
192         resourced_tm_interval interval;
193
194         libresourced_db_initialize_once();
195         if (init_datausage_foreach(resourced_get_database())!= SQLITE_OK) {
196                 _D("Failed to initialize data usage statements: %s\n",
197                    sqlite3_errmsg(resourced_get_database()));
198                 return RESOURCED_ERROR_DB_FAILED;
199         }
200
201
202         memset(&data, 0, sizeof(data));
203
204         if (!rule || !info_cb)
205                 return RESOURCED_ERROR_INVALID_PARAMETER;
206
207         /* pick a statement depending on parameters */
208         if (rule->granularity) {
209                 stm = is_iftype_defined(rule->iftype) ?
210                         data_usage_chunks_iface : data_usage_chunks;
211
212                 if (sqlite3_bind_int64(stm, pos++, rule->granularity) !=
213                     SQLITE_OK) {
214                         result = RESOURCED_ERROR_DB_FAILED;
215                         goto out;
216                 }
217                 data.interval = &interval;
218         } else {
219                 stm = is_iftype_defined(rule->iftype)
220                     ? data_usage_for_period_iface : data_usage_for_period;
221         }
222
223         if (sqlite3_bind_int64(stm, pos++, rule->from) != SQLITE_OK) {
224                 result = RESOURCED_ERROR_DB_FAILED;
225                 goto out;
226         }
227         if (sqlite3_bind_int64(stm, pos++, rule->to) != SQLITE_OK) {
228                 result = RESOURCED_ERROR_DB_FAILED;
229                 goto out;
230         }
231
232         if (is_iftype_defined(rule->iftype)) {
233                 data.iftype = rule->iftype;
234                 if (sqlite3_bind_int
235                     (stm, pos++, rule->iftype) != SQLITE_OK) {
236                         result = RESOURCED_ERROR_DB_FAILED;
237                         goto out;
238                 }
239         }
240
241         do {
242                 rc = sqlite3_step(stm);
243                 switch (rc) {
244                 case SQLITE_ROW:
245                         data.app_id = (char *)sqlite3_column_text(stm, 0);
246                         data.hw_net_protocol_type = sqlite3_column_int(stm, 1);
247                         data.roaming = sqlite3_column_int(stm, 2);
248                         cnt->incoming_bytes = sqlite3_column_int64(stm, 3);
249                         cnt->outgoing_bytes = sqlite3_column_int64(stm, 4);
250                         if (rule->granularity) {
251                                 interval.from = sqlite3_column_int64(stm, 5);
252                                 interval.to = interval.from + rule->granularity;
253                         }
254
255                         if (info_cb(&data, user_data) == RESOURCED_CANCEL)
256                                 rc = SQLITE_DONE;/* emulate end of data */
257                         break;
258                 case SQLITE_DONE:
259                         break;
260                 case SQLITE_ERROR:
261                 default:
262                         result = RESOURCED_ERROR_DB_FAILED;
263                         break;
264                 }
265         } while (rc == SQLITE_ROW);
266  out:
267         sqlite3_reset(stm);
268         return result;
269 }
270
271 /* the following array is strictly ordered
272  * to find required statement the following code will be used:
273  * (iface ? 1 : 0) | (total ? 2 : 0) | (chunks ? 4 : 0)
274  */
275 static sqlite3_stmt **details_stms[] = {
276         &data_usage_app_details,
277         &data_usage_app_details_iface,
278         &data_usage_total,
279         &data_usage_total_iface,
280         &data_usage_chunks_app,
281         &data_usage_chunks_app_iface,
282         &data_usage_chunks_total,
283         &data_usage_chunks_total_iface
284 };
285
286 static sqlite3_stmt *select_statement(const char *app_id,
287         const data_usage_selection_rule *rule)
288 {
289         return *details_stms[is_iftype_defined(rule->iftype) |
290         (app_id ? 0 : 2) | (rule->granularity ? 4 : 0)];
291 }
292
293 API resourced_ret_c data_usage_details_foreach(const char *app_id,
294                                      data_usage_selection_rule *rule,
295                                      data_usage_info_cb info_cb, void *user_data)
296 {
297         data_usage_info data;
298         sqlite3_stmt *stm;
299         resourced_ret_c result = RESOURCED_ERROR_NONE;
300         resourced_counters *cnt = &data.foreground.cnt;
301         int rc;
302         int pos = 1;/* running through positions
303                  where to bind parameters in the query */
304         resourced_tm_interval interval;
305
306         libresourced_db_initialize_once();
307         if (init_datausage_foreach(resourced_get_database())!= SQLITE_OK) {
308                 _D("Failed to initialize data usage statements: %s\n",
309                    sqlite3_errmsg(resourced_get_database()));
310                 return RESOURCED_ERROR_DB_FAILED;
311         }
312         memset(&data, 0, sizeof(data));
313
314         if (!rule || !info_cb)
315                 return RESOURCED_ERROR_INVALID_PARAMETER;
316
317         /* pick a statement depending on parameters.
318                 See comment for details_stms */
319         stm = select_statement(app_id, rule);
320
321         if (rule->granularity) {
322                 if (sqlite3_bind_int64(stm, pos++, rule->granularity) !=
323                     SQLITE_OK) {
324                         result = RESOURCED_ERROR_DB_FAILED;
325                         goto out;
326                 }
327                 data.interval = &interval;
328         }
329
330         if (sqlite3_bind_int64(stm, pos++, rule->from) != SQLITE_OK) {
331                 result = RESOURCED_ERROR_DB_FAILED;
332                 goto out;
333         }
334         if (sqlite3_bind_int64(stm, pos++, rule->to) != SQLITE_OK) {
335                 result = RESOURCED_ERROR_DB_FAILED;
336                 goto out;
337         }
338
339         if (app_id) {
340                 if (sqlite3_bind_text(stm, pos++, app_id, -1, SQLITE_TRANSIENT)
341                     != SQLITE_OK) {
342                         result = RESOURCED_ERROR_DB_FAILED;
343                         goto out;
344                 }
345                 data.app_id = app_id;
346         }
347
348         if (is_iftype_defined(rule->iftype)) {
349                 if (sqlite3_bind_int
350                     (stm, pos++, rule->iftype) != SQLITE_OK) {
351                         result = RESOURCED_ERROR_DB_FAILED;
352                         goto out;
353                 }
354         }
355
356         do {
357                 rc = sqlite3_step(stm);
358                 switch (rc) {
359                 case SQLITE_ROW:
360                         data.iftype = sqlite3_column_int(stm, 0);
361                         data.hw_net_protocol_type = sqlite3_column_int(stm, 1);
362                         data.roaming = sqlite3_column_int(stm, 2);
363                         cnt->incoming_bytes = sqlite3_column_int64(stm, 3);
364                         cnt->outgoing_bytes = sqlite3_column_int64(stm, 4);
365                         data.ifname = (char *)sqlite3_column_text(stm, 5);
366
367                         if (rule->granularity) {
368                                 interval.from = sqlite3_column_int64(stm, 6);
369                                 interval.to = interval.from + rule->granularity;
370                         }
371                         data.app_id = (char *)sqlite3_column_text(stm, 0);
372
373
374                         if (info_cb(&data, user_data) == RESOURCED_CANCEL)
375                                 rc = SQLITE_DONE; /* emulate end of data */
376                         break;
377                 case SQLITE_DONE:
378                         break;
379                 case SQLITE_ERROR:
380                 default:
381                         result = RESOURCED_ERROR_DB_FAILED;
382                         break;
383                 }
384         } while (rc == SQLITE_ROW);
385  out:
386         sqlite3_reset(stm);
387         return result;
388 }