Merge "Added logic to monitor and restrict data usage per interface" into tizen
[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_LOGI("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         ret = fwrite_uint(CUR_CLASSID_PATH, ++classid);
50         if (ret < 0)
51                 STC_LOGE("Can not write classid");
52
53         return classid;
54 }
55
56 static int __place_classid_to_cgroup(const char *cgroup, const char *subdir,
57                                      uint32_t *classid,
58                                      check_classid_used_cb cb)
59 {
60         char buf[MAX_PATH_LENGTH];
61         uint32_t result_classid = (classid && *classid) ? *classid :
62                 __produce_classid(cb);
63
64         /* set classid as out argument */
65         if (classid && !*classid)
66                 *classid = result_classid;
67
68         snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
69         return cgroup_write_node_uint32(buf, CLASSID_FILE_NAME, result_classid);
70 }
71
72 static uint32_t __get_classid_from_cgroup(const char *cgroup,
73                                           const char *subdir)
74 {
75         char buf[MAX_PATH_LENGTH];
76         uint32_t classid = STC_UNKNOWN_CLASSID;
77         snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
78
79         int ret = cgroup_read_node_uint32(buf, CLASSID_FILE_NAME, &classid);
80         if (ret < 0)
81                 STC_LOGE("Can't read classid from cgroup %s", buf);
82         return classid;
83 }
84
85 uint32_t get_classid_by_app_id(const char *app_id, int create)
86 {
87         int ret = 0;
88         bool exists;
89         uint32_t classid = STC_UNKNOWN_CLASSID;
90         const char *path_to_net_cgroup_dir = NULL;
91
92         if (app_id == NULL) {
93                 STC_LOGE("app_id  must be not empty");
94                 return STC_UNKNOWN_CLASSID;
95         }
96
97         if (!strcmp(app_id, STC_TOTAL_DATACALL))
98                 return STC_TOTAL_DATACALL_CLASSID;
99
100         if (!strcmp(app_id, STC_TOTAL_WIFI))
101                 return STC_TOTAL_WIFI_CLASSID;
102
103         if (!strcmp(app_id, STC_TOTAL_BLUETOOTH))
104                 return STC_TOTAL_BLUETOOTH_CLASSID;
105
106         if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
107                 path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
108         else
109                 path_to_net_cgroup_dir = FOREGROUND_CGROUP_NETWORK;
110
111         /* just read */
112         if (!create)
113                 classid = __get_classid_from_cgroup(path_to_net_cgroup_dir,
114                                                     app_id);
115
116         if (classid != STC_UNKNOWN_CLASSID)
117                 return classid;
118
119         ret = cgroup_make_subdir(path_to_net_cgroup_dir, (char *)app_id,
120                                  &exists);
121         if (ret)
122                 goto handle_error;
123
124         if (exists)
125                 classid = __get_classid_from_cgroup(path_to_net_cgroup_dir,
126                                                     app_id);
127         else
128                 ret = __place_classid_to_cgroup(path_to_net_cgroup_dir,
129                                                 (char *)app_id, &classid, NULL);
130         if (ret)
131                 goto handle_error;
132
133         return classid;
134
135 handle_error:
136
137         STC_LOGE("error_code: [%d]", ret);
138         return STC_UNKNOWN_CLASSID;
139 }
140
141 stc_error_e place_pids_to_net_cgroup(const int pid, const char *app_id)
142 {
143         char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
144         const char *path_to_net_cgroup_dir = NULL;
145
146         snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, pid, pid);
147
148         if (app_id == NULL) {
149                 STC_LOGE("package name must be not empty");
150                 return STC_ERROR_INVALID_PARAMETER;
151         }
152
153         if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
154                 path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
155         else
156                 path_to_net_cgroup_dir = FOREGROUND_CGROUP_NETWORK;
157
158         if (access(child_buf, F_OK)) {
159                 STC_LOGD("%s of %s is not existed", child_buf, app_id);
160                 return cgroup_write_pid(path_to_net_cgroup_dir, app_id, pid);
161         }
162
163         return cgroup_write_pidtree(path_to_net_cgroup_dir, app_id, pid);
164 }