c0575277a427800cb458ac2ca720ebc4603ff132
[platform/core/connectivity/stc-manager.git] / src / helper / helper-net-cls.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 <dirent.h>
18 #include <glib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include "helper-cgroup.h"
24 #include "counter.h"
25 #include "stc-db.h"
26 #include "helper-file.h"
27 #include "helper-net-cls.h"
28
29 #define CUR_CLASSID_PATH "/tmp/cur_classid"
30 #define CLASSID_FILE_NAME "net_cls.classid"
31
32 typedef GArray task_classid_array;
33
34 static uint32_t __produce_classid(check_classid_used_cb check_classid_cb)
35 {
36         uint32_t classid = STC_RESERVED_CLASSID_MAX;
37         int classid_test_count = 0;
38         int ret = fread_uint(CUR_CLASSID_PATH, &classid);
39         if (ret < 0)
40                 STC_LOGE("Can not read current classid");
41         classid += 1;
42         if (check_classid_cb)
43                 for (classid_test_count = 0; classid_test_count < INT32_MAX;
44                      ++classid) {
45                         if (!check_classid_cb(classid))
46                                 break;
47                 }
48
49         if (classid_test_count == INT32_MAX) {
50                 STC_LOGE("there is no available classid due to kernel limitation");
51                 return STC_UNKNOWN_CLASSID;
52         }
53
54         ret = fwrite_uint(CUR_CLASSID_PATH, ++classid);
55         if (ret < 0)
56                 STC_LOGE("Can not write classid");
57
58         return classid;
59 }
60
61 static int __place_classid_to_cgroup(const char *cgroup, const char *subdir,
62                                      uint32_t *classid,
63                                      check_classid_used_cb cb)
64 {
65         char buf[MAX_PATH_LENGTH];
66         uint32_t result_classid = (classid && *classid) ? *classid :
67                 __produce_classid(cb);
68
69         /* set classid as out argument */
70         if (classid && !*classid)
71                 *classid = result_classid;
72
73         snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
74         return cgroup_write_node_uint32(buf, CLASSID_FILE_NAME, result_classid);
75 }
76
77 static uint32_t __get_classid_from_cgroup(const char *cgroup,
78                                           const char *subdir)
79 {
80         char buf[MAX_PATH_LENGTH];
81         uint32_t classid = STC_UNKNOWN_CLASSID;
82         snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
83
84         int ret = cgroup_read_node_uint32(buf, CLASSID_FILE_NAME, &classid);
85         if (ret < 0)
86                 STC_LOGE("Can't read classid from cgroup %s", buf);
87         return classid;
88 }
89
90 /* TODO: background tasks update from list */
91 static void __add_background_apps(GSList *background_pid_list)
92 {
93         if (background_pid_list == NULL)
94                 return;
95
96         /* remove old list */
97         /* add new list */
98 }
99
100 static stc_error_e __make_net_cls_cgroup(const char *pkg_name, uint32_t classid,
101                                          check_classid_used_cb cb)
102 {
103         stc_error_e ret = STC_ERROR_NONE;
104         bool exists = false;
105
106         if (pkg_name == NULL) {
107                 STC_LOGE("package name must be not empty");
108                 return STC_ERROR_INVALID_PARAMETER;
109         }
110
111         ret = cgroup_make_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name,
112                                  &exists);
113         ret_value_if(ret < 0, STC_ERROR_FAIL);
114
115         if (!exists) {
116                 ret = __place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
117                                                 pkg_name,
118                                                 classid ? &classid : NULL, cb);
119                 ret_value_if(ret < 0, STC_ERROR_FAIL);
120         }
121         return ret;
122 }
123
124 uint32_t get_classid_by_app_id(const char *app_id, int create)
125 {
126         int ret = 0;
127         bool exists;
128         uint32_t classid = STC_UNKNOWN_CLASSID;
129
130         if (app_id == NULL) {
131                 STC_LOGE("app_id  must be not empty");
132                 return STC_UNKNOWN_CLASSID;
133         }
134
135         if (!strcmp(app_id, STC_ALL_APP))
136                 return STC_ALL_APP_CLASSID;
137
138         if (!strcmp(app_id, TETHERING_APP_NAME))
139                 return STC_TETHERING_APP_CLASSID;
140
141         if (!strcmp(app_id, STC_BACKGROUND_APP_NAME))
142                 return STC_BACKGROUND_APP_CLASSID;
143
144         if (!strcmp(app_id, NETWORK_RESTRICTION_APP_NAME))
145                 return STC_NETWORK_RESTRICTION_APP_CLASSID;
146
147         /* just read */
148         if (!create)
149                 classid = __get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
150                                                     app_id);
151
152         if (classid != STC_UNKNOWN_CLASSID)
153                 return classid;
154
155         ret = cgroup_make_subdir(PATH_TO_NET_CGROUP_DIR, (char *)app_id,
156                                  &exists);
157         if (ret)
158                 goto handle_error;
159
160         if (exists)
161                 classid = __get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
162                                                     app_id);
163         else
164                 ret = __place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
165                                                 (char *)app_id, &classid, NULL);
166         if (ret)
167                 goto handle_error;
168
169         return classid;
170
171 handle_error:
172
173         STC_LOGE("error_code: [%d]", ret);
174         return STC_UNKNOWN_CLASSID;
175 }
176
177 stc_error_e place_pids_to_net_cgroup(const int pid, const char *pkg_name)
178 {
179         char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
180         snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, pid, pid);
181
182         if (pkg_name == NULL) {
183                 STC_LOGE("package name must be not empty");
184                 return STC_ERROR_INVALID_PARAMETER;
185         }
186
187         if (access(child_buf, F_OK)) {
188                 STC_LOGD("%s of %s is not existed", child_buf, pkg_name);
189                 return cgroup_write_pid(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
190         }
191
192         return cgroup_write_pidtree(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
193 }
194
195 void create_net_background_cgroup(GSList *background_pid_list)
196 {
197         stc_error_e ret = __make_net_cls_cgroup(STC_BACKGROUND_APP_NAME,
198                                                 STC_BACKGROUND_APP_CLASSID,
199                                                 NULL);
200         if (ret == STC_ERROR_NONE)
201                 __add_background_apps(background_pid_list);
202         else
203                 STC_LOGD("Could not support quota for background applications");
204 }
205
206 void add_pid_to_background_cgroup(pid_t pid)
207 {
208         place_pids_to_net_cgroup(pid, STC_BACKGROUND_APP_NAME);
209 }
210
211 void remove_pid_from_background_cgroup(pid_t pid)
212 {
213         cgroup_remove_pid(PATH_TO_NET_CGROUP_DIR, STC_BACKGROUND_APP_NAME, pid);
214 }