Added background restriction for data saver
[platform/core/connectivity/stc-manager.git] / src / stc-restriction.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 "stc-db.h"
18 #include "table-restrictions.h"
19 #include "stc-restriction.h"
20 #include "stc-manager-gdbus.h"
21 #include "stc-monitor.h"
22
23 #define RESTRICTION_DBUS_ERROR_NAME "net.stc.restriction.Error.Failed"
24
25 #define STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, err_num) \
26         g_dbus_method_invocation_return_dbus_error((invocation), \
27                                                    RESTRICTION_DBUS_ERROR_NAME, \
28                                                    stc_err_strs[-(err_num)])
29
30 static const gchar *stc_err_strs[] = {
31         "ERROR_NONE",
32         "FAIL",
33         "DB_FAILED",
34         "OUT_OF_MEMORY",
35         "INVALID_PARAMETER",
36         "NO_DATA",
37         "UNINITIALIZED",
38         "NOTIMPL"
39 };
40
41 void __initialize_rstn_rule(table_restrictions_info *rule)
42 {
43         rule->app_id = NULL;
44         rule->ifname = NULL;
45         rule->iftype = STC_IFACE_ALL;
46         rule->rst_state = STC_RESTRICTION_REMOVED;
47         rule->data_limit = 0;
48         rule->data_warn_limit = 0;
49         rule->roaming = STC_ROAMING_DISABLE;
50         rule->imsi = NULL;
51 }
52
53 gboolean __validate_rstn_rule(table_restrictions_info *rule,
54                               enum traffic_restriction_type rst_type)
55 {
56         __STC_LOG_FUNC_ENTER__;
57
58         if (rule == NULL) {
59                 __STC_LOG_FUNC_EXIT__;
60                 return FALSE;
61         }
62
63         if (rst_type <= RST_UNDEFINDED || rst_type >= RST_MAX_VALUE) {
64                 __STC_LOG_FUNC_EXIT__;
65                 return FALSE;
66         }
67
68         if (rule->iftype <= STC_IFACE_UNKNOWN ||
69             rule->iftype >= STC_IFACE_LAST_ELEM) {
70                 __STC_LOG_FUNC_EXIT__;
71                 return FALSE;
72         }
73
74         if (rule->roaming >= STC_ROAMING_LAST_ELEM) {
75                 __STC_LOG_FUNC_EXIT__;
76                 return FALSE;
77         }
78
79         if (rule->imsi == NULL) {
80                 __STC_LOG_FUNC_EXIT__;
81                 return FALSE;
82         }
83
84         if (rule->app_id == NULL) {
85                 __STC_LOG_FUNC_EXIT__;
86                 return FALSE;
87         }
88
89         __STC_LOG_FUNC_EXIT__;
90         return TRUE;
91 }
92
93 void __stc_restriction_app_info_builder_add(GVariantBuilder *builder,
94                                             const table_restrictions_info *info)
95 {
96         __STC_LOG_FUNC_ENTER__;
97
98         if (!builder || !info) {
99                 __STC_LOG_FUNC_EXIT__;
100                 return;
101         }
102
103         g_variant_builder_add(builder, "{sv}", "app_id",
104                               g_variant_new_string(info->app_id));
105
106         g_variant_builder_add(builder, "{sv}", "ifname",
107                               g_variant_new_string(info->ifname));
108
109         g_variant_builder_add(builder, "{sv}", "iftype",
110                               g_variant_new_uint16(info->iftype));
111
112         g_variant_builder_add(builder, "{sv}", "rst_state",
113                               g_variant_new_uint16(info->rst_state));
114
115         g_variant_builder_add(builder, "{sv}", "data_limit",
116                               g_variant_new_int64(info->data_limit));
117
118         g_variant_builder_add(builder, "{sv}", "data_warn_limit",
119                               g_variant_new_int64(info->data_warn_limit));
120
121         g_variant_builder_add(builder, "{sv}", "roaming",
122                               g_variant_new_uint16(info->roaming));
123
124         g_variant_builder_add(builder, "{sv}", "imsi",
125                               g_variant_new_string(info->imsi));
126
127         __STC_LOG_FUNC_EXIT__;
128 }
129
130 stc_cb_ret_e __table_restrictions_foreach_app_cb(const table_restrictions_info *info,
131                                                  void *user_data)
132 {
133         __STC_LOG_FUNC_ENTER__;
134         GVariantBuilder *builder = (GVariantBuilder *)user_data;
135         GVariantBuilder sub_builder;
136
137         if (!info || !builder) {
138                 __STC_LOG_FUNC_EXIT__;
139                 return STC_CANCEL;
140         }
141
142         g_variant_builder_init(&sub_builder, G_VARIANT_TYPE("a{sv}"));
143         __stc_restriction_app_info_builder_add(&sub_builder, info);
144
145         g_variant_builder_add_value(builder,
146                                     g_variant_builder_end(&sub_builder));
147
148         __STC_LOG_FUNC_EXIT__;
149         return STC_CONTINUE;
150 }
151
152 stc_cb_ret_e __table_restrictions_per_app_cb(const table_restrictions_info *info,
153                                              void *user_data)
154 {
155         __STC_LOG_FUNC_ENTER__;
156         GVariantBuilder *builder = (GVariantBuilder *)user_data;
157
158         if (!info || !builder) {
159                 __STC_LOG_FUNC_EXIT__;
160                 return STC_CANCEL;
161         }
162
163         __stc_restriction_app_info_builder_add(builder, info);
164
165         __STC_LOG_FUNC_EXIT__;
166         return STC_CONTINUE;
167 }
168
169 static void __stc_extract_restriction_rule(const char *key, GVariant *value,
170                                            void *user_data)
171 {
172         __STC_LOG_FUNC_ENTER__;
173
174         table_restrictions_info *rule =
175                 (table_restrictions_info *) user_data;
176         if (rule == NULL) {
177                 __STC_LOG_FUNC_EXIT__;
178                 return;
179         }
180
181         if (!g_strcmp0(key, "app_id")) {
182                 guint str_length;
183                 const gchar *str = g_variant_get_string(value, &str_length);
184                 rule->app_id = g_strdup(str);
185                 STC_LOGD("app_id: [%s]", (unsigned int) rule->app_id);
186
187         } else if (!g_strcmp0(key, "ifname")) {
188                 guint str_length;
189                 const gchar *str = g_variant_get_string(value, &str_length);
190                 rule->ifname = g_strdup(str);
191                 STC_LOGD("ifname: [%s]", rule->ifname);
192
193         } else if (!g_strcmp0(key, "iftype")) {
194                 rule->iftype = g_variant_get_uint16(value);
195                 STC_LOGD("iftype: [%u]", (unsigned int) rule->iftype);
196
197         } else if (!g_strcmp0(key, "data_limit")) {
198                 rule->data_limit = g_variant_get_int64(value);
199                 STC_LOGD("data_limit: [%lld]", rule->data_limit);
200
201         } else if (!g_strcmp0(key, "data_warn_limit")) {
202                 rule->data_warn_limit = g_variant_get_int64(value);
203                 STC_LOGD("data_warn_limit: [%lld]", rule->data_warn_limit);
204
205         } else if (!g_strcmp0(key, "roaming")) {
206                 rule->roaming = g_variant_get_uint16(value);
207                 STC_LOGD("roaming: [%u]", rule->roaming);
208
209         } else if (!g_strcmp0(key, "imsi")) {
210                 guint str_length;
211                 const gchar *str = g_variant_get_string(value, &str_length);
212                 rule->imsi = g_strdup(str);
213                 STC_LOGD("imsi: [%s]", rule->imsi);
214
215         } else {
216                 STC_LOGD("Unknown select rule");
217         }
218
219         __STC_LOG_FUNC_EXIT__;
220 }
221
222 gboolean handle_restriction_set(StcRestriction *object,
223                                 GDBusMethodInvocation *invocation,
224                                 GVariant *parameters,
225                                 void *user_data)
226 {
227         __STC_LOG_FUNC_ENTER__;
228         GVariantIter *iter = NULL;
229         table_restrictions_info rule;
230
231         memset(&rule, 0, sizeof(table_restrictions_info));
232         __initialize_rstn_rule(&rule);
233
234         g_variant_get(parameters, "a{sv}", &iter);
235         if (iter != NULL) {
236                 stc_manager_gdbus_dict_foreach(iter,
237                                                __stc_extract_restriction_rule,
238                                                &rule);
239                 g_variant_iter_free(iter);
240         }
241
242         rule.rst_state = STC_RESTRICTION_REMOVED;
243
244         if (__validate_rstn_rule(&rule, RST_SET) == FALSE) {
245                 STC_RESTRICTION_DBUS_REPLY_ERROR(invocation,
246                                                  STC_ERROR_INVALID_PARAMETER);
247                 __STC_LOG_FUNC_EXIT__;
248                 return TRUE;
249         }
250
251         table_restrictions_update(&rule);
252         /* update restriction rule in runtime structure */
253         stc_monitor_rstns_tree_add(&rule);
254
255         STC_DBUS_REPLY_ERROR_NONE(invocation);
256         __STC_LOG_FUNC_EXIT__;
257         return TRUE;
258 }
259
260 gboolean handle_restriction_exclude(StcRestriction *object,
261                                     GDBusMethodInvocation *invocation,
262                                     GVariant *parameters,
263                                     void *user_data)
264 {
265         __STC_LOG_FUNC_ENTER__;
266         GVariantIter *iter = NULL;
267         table_restrictions_info rule;
268
269         memset(&rule, 0, sizeof(table_restrictions_info));
270         __initialize_rstn_rule(&rule);
271
272         g_variant_get(parameters, "a{sv}", &iter);
273         if (iter != NULL) {
274                 stc_manager_gdbus_dict_foreach(iter,
275                                                __stc_extract_restriction_rule,
276                                                &rule);
277                 g_variant_iter_free(iter);
278         }
279
280         rule.rst_state = STC_RESTRICTION_EXCLUDED;
281
282         if (__validate_rstn_rule(&rule, RST_EXCLUDE) == FALSE) {
283                 STC_RESTRICTION_DBUS_REPLY_ERROR(invocation,
284                                                  STC_ERROR_INVALID_PARAMETER);
285                 __STC_LOG_FUNC_EXIT__;
286                 return TRUE;
287         }
288
289         table_restrictions_update(&rule);
290         /* update restriction rule in runtime structure */
291         stc_monitor_rstns_tree_add(&rule);
292
293         STC_DBUS_REPLY_ERROR_NONE(invocation);
294         __STC_LOG_FUNC_EXIT__;
295         return TRUE;
296 }
297
298 gboolean handle_restriction_unset(StcRestriction *object,
299                                    GDBusMethodInvocation *invocation,
300                                    GVariant *parameters,
301                                    void *user_data)
302 {
303         __STC_LOG_FUNC_ENTER__;
304         GVariantIter *iter = NULL;
305         table_restrictions_info rule;
306
307         memset(&rule, 0, sizeof(table_restrictions_info));
308         __initialize_rstn_rule(&rule);
309
310         g_variant_get(parameters, "a{sv}", &iter);
311         if (iter != NULL) {
312                 stc_manager_gdbus_dict_foreach(iter,
313                                                __stc_extract_restriction_rule,
314                                                &rule);
315                 g_variant_iter_free(iter);
316         }
317
318         if (__validate_rstn_rule(&rule, RST_UNSET) == FALSE) {
319                 STC_RESTRICTION_DBUS_REPLY_ERROR(invocation,
320                                                  STC_ERROR_INVALID_PARAMETER);
321                 __STC_LOG_FUNC_EXIT__;
322                 return TRUE;
323         }
324
325         table_restrictions_delete(rule.app_id, rule.iftype, rule.imsi);
326         /* remove restriction rule from runtime structure */
327         stc_monitor_rstns_tree_remove(&rule);
328
329         STC_DBUS_REPLY_ERROR_NONE(invocation);
330         __STC_LOG_FUNC_EXIT__;
331         return TRUE;
332 }
333
334 gboolean handle_restriction_get(StcRestriction *object,
335                                 GDBusMethodInvocation *invocation,
336                                 const gchar *app_id,
337                                 void *user_data)
338 {
339         __STC_LOG_FUNC_ENTER__;
340         GVariantBuilder *builder = NULL;
341         GVariant *return_parameters = NULL;
342         stc_error_e ret;
343
344         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
345
346         ret = table_restrictions_per_app(app_id,
347                                          __table_restrictions_per_app_cb,
348                                          builder);
349         if (ret < STC_ERROR_NONE) {
350                 g_variant_builder_unref(builder);
351                 STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, ret);
352                 __STC_LOG_FUNC_EXIT__;
353                 return TRUE;
354         }
355
356         return_parameters = g_variant_new("(ia{sv})", STC_ERROR_NONE, builder);
357         g_variant_builder_unref(builder);
358
359         DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters);
360         STC_DBUS_REPLY(invocation, return_parameters);
361         __STC_LOG_FUNC_EXIT__;
362         return TRUE;
363 }
364
365 gboolean handle_restriction_get_all(StcRestriction *object,
366                                     GDBusMethodInvocation *invocation,
367                                     void *user_data)
368 {
369         __STC_LOG_FUNC_ENTER__;
370         GVariantBuilder *builder = NULL;
371         GVariant *return_parameters = NULL;
372         stc_error_e ret;
373
374         builder = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}"));
375
376         ret = table_restrictions_foreach(__table_restrictions_foreach_app_cb,
377                                          builder);
378         if (ret < STC_ERROR_NONE) {
379                 g_variant_builder_unref(builder);
380                 STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, ret);
381                 __STC_LOG_FUNC_EXIT__;
382                 return TRUE;
383         }
384
385         return_parameters = g_variant_new("(iaa{sv})", STC_ERROR_NONE, builder);
386         g_variant_builder_unref(builder);
387
388         DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters);
389         STC_DBUS_REPLY(invocation, return_parameters);
390         __STC_LOG_FUNC_EXIT__;
391         return TRUE;
392 }
393
394 gboolean handle_restriction_get_state(StcRestriction *object,
395                                       GDBusMethodInvocation *invocation,
396                                       const gchar *app_id,
397                                       int iftype,
398                                       void *user_data)
399 {
400         __STC_LOG_FUNC_ENTER__;
401         GVariant *return_parameters = NULL;
402         stc_restriction_state_e state = STC_RESTRICTION_UNKNOWN;
403         stc_error_e ret;
404
405         ret = table_restrictions_get_restriction_state(app_id, iftype, &state);
406         if (ret < STC_ERROR_NONE) {
407                 STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, ret);
408                 __STC_LOG_FUNC_EXIT__;
409                 return TRUE;
410         }
411
412         return_parameters = g_variant_new("(ii)", STC_ERROR_NONE, state);
413         STC_DBUS_REPLY(invocation, return_parameters);
414         __STC_LOG_FUNC_EXIT__;
415         return TRUE;
416 }