Add some chains to separate monitoring and restriction
[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   "/var/lib/stc/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 ret = fread_uint(CUR_CLASSID_PATH, &classid);
38         if (ret < 0)
39                 STC_LOGI("Can not read current classid"); //LCOV_EXCL_LINE
40
41         classid += 1;
42
43         if (check_classid_cb) {
44                 int classid_test_count = 0;
45                 for (classid_test_count = 0; classid_test_count < INT32_MAX;
46                      ++classid) {
47                         if (!check_classid_cb(classid))
48                                 break;
49                 }
50         }
51
52         ret = fwrite_uint(CUR_CLASSID_PATH, ++classid);
53         if (ret < 0)
54                 STC_LOGE("Can not write classid"); //LCOV_EXCL_LINE
55
56         return classid;
57 }
58
59 static int __place_classid_to_cgroup(const char *cgroup, const char *subdir,
60                                      uint32_t *classid,
61                                      check_classid_used_cb cb)
62 {
63         char buf[MAX_PATH_LENGTH];
64         uint32_t result_classid = (classid && *classid) ? *classid :
65                 __produce_classid(cb);
66
67         /* set classid as out argument */
68         if (classid && !*classid)
69                 *classid = result_classid;
70
71         snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
72         return cgroup_write_node_uint32(buf, CLASSID_FILE_NAME, result_classid);
73 }
74
75 static stc_error_e __get_classid_from_cgroup(const char *cgroup,
76                                           const char *subdir, uint32_t *classid)
77 {
78         char buf[MAX_PATH_LENGTH];
79         snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
80
81         int ret = cgroup_read_node_uint32(buf, CLASSID_FILE_NAME, classid);
82         if (ret < 0) {
83                 STC_LOGE("Can't read classid from cgroup %s", buf); //LCOV_EXCL_LINE
84                 *classid = STC_UNKNOWN_CLASSID;
85                 return STC_ERROR_NO_DATA;
86         }
87
88         return STC_ERROR_NONE;
89 }
90
91 stc_error_e init_current_classid(void)
92 {
93         int ret = 0;
94         struct stat stat_buf;
95
96         if (stat(STC_CGROUP_NETWORK, &stat_buf) != 0) {
97                 uint32_t classid = STC_RESERVED_CLASSID_MAX;
98                 ret = fwrite_uint(CUR_CLASSID_PATH, classid);
99                 if (ret < 0) {
100                         STC_LOGE("Can not init current classid"); //LCOV_EXCL_LINE
101                         return STC_ERROR_FAIL; //LCOV_EXCL_LINE
102                 }
103         }
104
105         return STC_ERROR_NONE;
106 }
107
108 API uint32_t get_classid_by_app_id(const char *app_id, int create)
109 {
110         bool exists;
111         int ret = STC_ERROR_NONE;
112         uint32_t classid = STC_UNKNOWN_CLASSID;
113         const char *path_to_net_cgroup_dir = NULL;
114
115         if (app_id == NULL) {
116                 STC_LOGE("app_id must be not empty"); //LCOV_EXCL_LINE
117                 return STC_UNKNOWN_CLASSID; //LCOV_EXCL_LINE
118         }
119
120         if (!strcmp(app_id, STC_TOTAL_BACKGROUND))
121                 return STC_BACKGROUND_APP_CLASSID;
122
123         if (!strcmp(app_id, STC_TOTAL_DATACALL))
124                 return STC_TOTAL_DATACALL_CLASSID;
125
126         if (!strcmp(app_id, STC_TOTAL_WIFI))
127                 return STC_TOTAL_WIFI_CLASSID;
128
129         if (!strcmp(app_id, STC_TOTAL_BLUETOOTH))
130                 return STC_TOTAL_BLUETOOTH_CLASSID;
131
132         if (!strcmp(app_id, STC_TOTAL_IPV4))
133                 return STC_TOTAL_IPV4_CLASSID;
134
135         if (!strcmp(app_id, STC_TOTAL_IPV6))
136                 return STC_TOTAL_IPV6_CLASSID;
137
138         if (!strcmp(app_id, STC_TOTAL_TETHERING))
139                 return STC_TETHERING_APP_CLASSID;
140
141         if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
142                 path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
143         else if (strstr(app_id, STC_TETHERING_APP_SUFFIX))
144                 path_to_net_cgroup_dir = TETHERING_CGROUP_NETWORK;
145         else
146                 path_to_net_cgroup_dir = FOREGROUND_CGROUP_NETWORK;
147
148         /* just read */
149         if (!create)
150                 ret = __get_classid_from_cgroup(path_to_net_cgroup_dir, //LCOV_EXCL_LINE
151                                                         app_id, &classid);
152
153         if (ret != STC_ERROR_NONE)
154                 return STC_UNKNOWN_CLASSID;
155
156         if (classid != STC_UNKNOWN_CLASSID)
157                 return classid;
158
159         ret = cgroup_make_subdir(path_to_net_cgroup_dir, (char *)app_id,
160                                  &exists);
161         if (ret)
162                 goto handle_error;
163
164         if (exists)
165                 ret = __get_classid_from_cgroup(path_to_net_cgroup_dir,
166                                                     app_id, &classid);
167         else
168                 ret = __place_classid_to_cgroup(path_to_net_cgroup_dir,
169                                                 (char *)app_id, &classid, NULL);
170         if (ret)
171                 goto handle_error; //LCOV_EXCL_LINE
172
173         return classid;
174
175 handle_error:
176
177         STC_LOGE("error_code: [%d]", ret); //LCOV_EXCL_LINE
178         return STC_UNKNOWN_CLASSID; //LCOV_EXCL_LINE
179 }
180
181 stc_error_e place_pids_to_net_cgroup(const int pid, const char *app_id)
182 {
183         char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int) + 1];
184         const char *path_to_net_cgroup_dir = NULL;
185
186         snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, pid, pid);
187
188         if (app_id == NULL) {
189                 STC_LOGE("package name must be not empty"); //LCOV_EXCL_LINE
190                 return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
191         }
192
193         if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
194                 path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
195         else if (strstr(app_id, STC_TETHERING_APP_SUFFIX))
196                 path_to_net_cgroup_dir = TETHERING_CGROUP_NETWORK;
197         else
198                 path_to_net_cgroup_dir = FOREGROUND_CGROUP_NETWORK; //LCOV_EXCL_LINE
199
200         if (access(child_buf, F_OK))
201                 return cgroup_write_pid(path_to_net_cgroup_dir, app_id, pid);
202
203         return cgroup_write_pidtree(path_to_net_cgroup_dir, app_id, pid); //LCOV_EXCL_LINE
204 }