tizen 2.3 release
[kernel/api/system-resource.git] / src / network / restriction-local.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 2013 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 set-restriction.c
22  * @desc Implementation of the set network restriction body
23  */
24
25 #include <sqlite3.h>
26 #include <stdbool.h>
27 #include <resourced.h>
28
29 #include "const.h"
30 #include "database.h"
31 #include "macro.h"
32 #include "module-data.h"
33 #include "net-cls-cgroup.h"
34 #include "netlink-restriction.h"
35 #include "init.h"
36 #include "restriction-helper.h"
37 #include "datausage-restriction.h"
38 #include "roaming.h"
39 #include "storage.h"
40 #include "trace.h"
41 #include "tethering-restriction.h"
42
43 #define SET_NET_RESTRICTIONS "REPLACE INTO restrictions "     \
44         "(binpath, rcv_limit, send_limit, iftype, rst_state, "\
45         " quota_id, roaming) " \
46         "VALUES (?, ?, ?, ?, ?, ?, ?)"
47
48 #define GET_NET_RESTRICTION "SELECT rcv_limit, send_limit, " \
49         " rst_state, quota_id FROM restrictions " \
50         "WHERE binpath = ? AND iftype = ?"
51
52 #define RESET_RESTRICTIONS "DELETE FROM restrictions "  \
53         "WHERE binpath=? AND iftype=?"
54
55 static sqlite3_stmt *update_rst_stm;
56 static sqlite3_stmt *reset_rst_stm;
57
58 static resourced_ret_c init_reset_rst(void)
59 {
60         resourced_ret_c error_code = RESOURCED_ERROR_NONE;
61         if (reset_rst_stm)
62                 return error_code;
63
64         DB_ACTION(sqlite3_prepare_v2
65                   (resourced_get_database(), RESET_RESTRICTIONS, -1,
66                 &reset_rst_stm, NULL));
67
68         return error_code;
69
70 handle_error:
71         _E("Failed to initialize %s", RESET_RESTRICTIONS);
72         return error_code;
73 }
74
75 static resourced_ret_c reset_restriction_db(const char *app_id,
76                                             const resourced_iface_type iftype)
77 {
78         resourced_ret_c error_code = init_reset_rst();
79
80         ret_value_if(error_code != RESOURCED_ERROR_NONE, error_code);
81
82         DB_ACTION(sqlite3_bind_text(reset_rst_stm, 1, app_id, -1, SQLITE_TRANSIENT));
83         DB_ACTION(sqlite3_bind_int(reset_rst_stm, 2, iftype));
84
85         if (sqlite3_step(reset_rst_stm) != SQLITE_DONE)
86                 error_code = RESOURCED_ERROR_DB_FAILED;
87
88 handle_error:
89
90         sqlite3_reset(reset_rst_stm);
91         if (error_code == RESOURCED_ERROR_DB_FAILED)
92                 _E("Failed to remove restrictions by network interface %s\n",
93                    sqlite3_errmsg(resourced_get_database()));
94
95         return error_code;
96 }
97
98 static resourced_ret_c init_update_rest_stmt(void)
99 {
100         resourced_ret_c error_code = RESOURCED_ERROR_NONE;
101         if (update_rst_stm)
102                 return error_code;
103
104         DB_ACTION(sqlite3_prepare_v2
105           (resourced_get_database(), SET_NET_RESTRICTIONS, -1,
106                 &update_rst_stm, NULL));
107         return error_code;
108
109 handle_error:
110         _E("Failed to initialize %s", SET_NET_RESTRICTIONS);
111         return error_code;
112 }
113
114 resourced_ret_c update_restriction_db(
115         const char *app_id, const resourced_iface_type iftype,
116         const int rcv_limit, const int snd_limit,
117         const resourced_restriction_state rst_state,
118         const int quota_id,
119         const resourced_roaming_type roaming)
120 {
121         resourced_ret_c error_code = RESOURCED_ERROR_NONE;
122
123         if (rst_state == RESOURCED_RESTRICTION_REMOVED)
124                 return reset_restriction_db(app_id, iftype);
125
126         error_code = init_update_rest_stmt();
127         ret_value_if(error_code != RESOURCED_ERROR_NONE, error_code);
128
129         DB_ACTION(sqlite3_bind_text(update_rst_stm, 1, app_id, -1, SQLITE_TRANSIENT));
130         DB_ACTION(sqlite3_bind_int64(update_rst_stm, 2, rcv_limit));
131         DB_ACTION(sqlite3_bind_int64(update_rst_stm, 3, snd_limit));
132         DB_ACTION(sqlite3_bind_int(update_rst_stm, 4, iftype));
133         DB_ACTION(sqlite3_bind_int(update_rst_stm, 5, rst_state));
134         DB_ACTION(sqlite3_bind_int(update_rst_stm, 6, quota_id));
135         DB_ACTION(sqlite3_bind_int(update_rst_stm, 7, roaming));
136
137         if (sqlite3_step(update_rst_stm) != SQLITE_DONE)
138                 error_code = RESOURCED_ERROR_DB_FAILED;
139
140 handle_error:
141
142         sqlite3_reset(update_rst_stm);
143         if (error_code == RESOURCED_ERROR_DB_FAILED)
144                 _E("Failed to set network restriction: %s\n",
145                         sqlite3_errmsg(resourced_get_database()));
146
147         return error_code;
148 }
149
150 resourced_ret_c get_restriction_info(const char *app_id,
151                                  const resourced_iface_type iftype,
152                                 resourced_restriction_info *rst)
153 {
154         int rc;
155         resourced_ret_c error_code = RESOURCED_ERROR_NONE;
156         int quota_id = 0;
157         sqlite3_stmt *stm = NULL;
158
159         ret_value_msg_if(rst == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
160                 "Please provide valid restriction argument!");
161
162         ret_value_msg_if(app_id == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
163                 "Please provide valid app_id argument!");
164
165         _SD("%s, %d", app_id, iftype);
166
167         DB_ACTION(sqlite3_prepare_v2
168                   (resourced_get_database(), GET_NET_RESTRICTION, -1, &stm, NULL));
169
170         DB_ACTION(sqlite3_bind_text(stm, 1, app_id, -1, SQLITE_TRANSIENT));
171         DB_ACTION(sqlite3_bind_int(stm, 2, iftype));
172
173         do {
174                 rc = sqlite3_step(stm);
175                 switch (rc) {
176                 case SQLITE_ROW:
177                         rst->rcv_limit = sqlite3_column_int(stm, 0);
178                         rst->send_limit = sqlite3_column_int64(stm, 1);
179                         rst->rst_state = sqlite3_column_int(stm, 2);
180                         rst->quota_id = sqlite3_column_int(stm, 3);
181
182                         break;
183                 case SQLITE_DONE:
184                         break;
185                 case SQLITE_ERROR:
186                 default:
187                         error_code = RESOURCED_ERROR_DB_FAILED;
188                         goto handle_error;
189                 }
190         } while (rc == SQLITE_ROW);
191
192         _D("%d", quota_id);
193
194 handle_error:
195
196         if (stm)
197                 sqlite3_finalize(stm);
198
199         if (error_code == RESOURCED_ERROR_DB_FAILED)
200                 _E("Failed to get network restriction's quota id: %s\n",
201                         sqlite3_errmsg(resourced_get_database()));
202
203         return quota_id;
204 }
205
206 static bool check_roaming(const resourced_net_restrictions *rst)
207 {
208         resourced_roaming_type roaming;
209         ret_value_msg_if(rst == NULL, false,
210                 "Invalid net_restriction pointer, please provide valid argument");
211
212         roaming = get_roaming();
213         _D("roaming %d rst->roaming %d", roaming, rst->roaming);
214         if (roaming == RESOURCED_ROAMING_UNKNOWN ||
215                 rst->roaming == RESOURCED_ROAMING_UNKNOWN) {
216                 return false;
217         }
218         return rst->roaming != roaming;
219 }
220
221 static void process_net_block_state(const enum
222         traffic_restriction_type rst_type)
223 {
224         struct shared_modules_data *m_data = get_shared_modules_data();
225
226         if (m_data)
227                 set_daemon_net_block_state(rst_type, m_data->carg);
228         else
229                 _E("shared modules data is empty");
230 }
231
232 resourced_ret_c process_kernel_restriction(
233         const u_int32_t classid,
234         const resourced_net_restrictions *rst,
235         const enum traffic_restriction_type rst_type)
236 {
237         int ret = RESOURCED_ERROR_NONE;
238
239         ret_value_secure_msg_if(!classid, RESOURCED_ERROR_INVALID_PARAMETER,
240                          "Can not determine classid for package %u.\n"
241                          "Probably package was not joined to performance "
242                          "monitoring\n", classid);
243
244         if (rst_type == RST_EXCLUDE && check_roaming(rst)) {
245                 _D("Restriction not applied: rst->roaming %d", rst->roaming);
246                 return RESOURCED_ERROR_NONE;
247         }
248
249         /* TODO check, and think how to implement it
250          * in unified way, maybe also block FORWARD chain in
251          * send_net_restriction */
252         if (classid == RESOURCED_ALL_APP_CLASSID ||
253             classid == RESOURCED_TETHERING_APP_CLASSID)
254                 ret = apply_tethering_restriction(rst_type);
255         if (classid != RESOURCED_TETHERING_APP_CLASSID &&
256             ret == RESOURCED_ERROR_NONE)
257                 ret = send_net_restriction(rst_type, classid,
258                                                   rst->iftype,
259                                                   rst->send_limit,
260                                                   rst->rcv_limit,
261                                                   rst->snd_warning_limit,
262                                                   rst->rcv_warning_limit);
263         ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
264                          "Restriction, type %d falied, return code %d\n",
265                          rst_type, ret);
266
267         return RESOURCED_ERROR_NONE;
268 }
269
270 resourced_ret_c proc_keep_restriction(
271         const char *app_id, const int quota_id,
272         const resourced_net_restrictions *rst,
273         const enum traffic_restriction_type rst_type)
274 {
275         u_int32_t app_classid = 0;
276         resourced_iface_type store_iftype;
277         resourced_restriction_state rst_state;
278         int ret = check_restriction_arguments(app_id, rst, rst_type);
279         ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
280                          RESOURCED_ERROR_INVALID_PARAMETER,
281                          "Invalid restriction arguments\n");
282
283         app_classid = get_classid_by_app_id(app_id, rst_type != RST_UNSET);
284         ret = process_kernel_restriction(app_classid, rst, rst_type);
285         ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
286                 "Can't keep restriction.");
287
288         store_iftype = get_store_iftype(app_classid, rst->iftype);
289         rst_state = convert_to_restriction_state(rst_type);
290         _SD("restriction: app_id %s, iftype %d, state %d, type %d\n", app_id,
291             store_iftype, rst_state, rst_type);
292
293         if (!strcmp(app_id, RESOURCED_ALL_APP) &&
294                 rst->iftype == RESOURCED_IFACE_ALL)
295                 process_net_block_state(rst_type);
296
297         return update_restriction_db(app_id, store_iftype,
298                                            rst->rcv_limit, rst->send_limit,
299                                            rst_state, quota_id, rst->roaming);
300 }
301
302 resourced_ret_c remove_restriction_local(const char *app_id,
303                                          const resourced_iface_type iftype)
304 {
305         resourced_net_restrictions rst = { 0 };
306
307         rst.iftype = iftype;
308         return proc_keep_restriction(app_id, NONE_QUOTA_ID, &rst,
309                                          RST_UNSET);
310 }
311
312 resourced_ret_c exclude_restriction_local(const char *app_id,
313                                           const int quota_id,
314                                           const resourced_iface_type iftype)
315 {
316         resourced_net_restrictions rst = { 0 };
317
318         rst.iftype = iftype;
319         return proc_keep_restriction(app_id, quota_id, &rst, RST_EXCLUDE);
320 }