tizen 2.3.1 release
[kernel/api/system-resource.git] / src / network / net-activity.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2014 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  *  @file: net_activity.h
21  *
22  *  @desc Handler which get data from generic netlink (NET_ACTIVITY) family
23  */
24
25 #include "const.h"
26 #include "net-cls-cgroup.h"
27 #include "generic-netlink.h"
28 #include "iface.h"
29 #include "macro.h"
30 #include "trace.h"
31
32 #include <data_usage.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36
37 #define NET_ACTIVITY_LISTEN_TIMEOUT 10
38
39 static pthread_t net_activity_worker;
40
41 struct net_activity_context {
42         net_activity_cb cb;
43         uint32_t group_family_id;
44         uint32_t family_id;
45         int sock;
46 };
47
48 static void set_socket_option(int sock)
49 {
50         int ret;
51         int opts = fcntl(sock, F_GETFL);
52
53         ret_msg_if(opts < 0, "fcntl error");
54         opts = (opts | O_NONBLOCK);
55
56         ret = fcntl(sock, F_SETFL, opts);
57         ret_msg_if(ret < 0, "fcntl error");
58 }
59
60 /**
61  * Convert the netlink multicast group id into a bit map
62  * (e.g. 4 => 16, 5 => 32)
63  */
64 static uint32_t convert_mcast_group_id(uint32_t group_id)
65 {
66         if (group_id > 31) {
67                 _E("Netlink: Use setsockopt for this group: %u\n", group_id);
68                 return 0;
69         }
70         return group_id ? (1 << (group_id - 1)) : 0;
71 }
72
73 static void *net_activity_func(void *user_data)
74 {
75         int ret, max_fd;
76         struct net_activity_context *context =
77                 (struct net_activity_context *)user_data;
78         struct net_activity_info activity_info;
79         struct timeval timeout = {0};
80
81         fd_set rfd;
82         max_fd = context->sock + 1;
83
84         while (1) {
85                 timeout.tv_sec = NET_ACTIVITY_LISTEN_TIMEOUT;
86                 FD_ZERO(&rfd);
87                 FD_SET(context->sock, &rfd);
88
89                 ret = select(max_fd, &rfd, NULL, NULL, &timeout);
90
91                 if (ret < 0) {
92                         _E("Failed to select on generic netlink socket");
93                         goto stop_net_activity;
94                 }
95
96                 if (ret == 0) {
97                         _D("timeout");
98                         continue;
99                 }
100
101                 ret = recv_net_activity(context->sock, &activity_info,
102                         context->family_id);
103
104                 if (ret == RESOURCED_NET_ACTIVITY_STOP)
105                         goto stop_net_activity;
106                 else if (ret == RESOURCED_NET_ACTIVITY_CONTINUE)
107                         continue;
108
109                 if (context->cb(&activity_info) == RESOURCED_CANCEL)
110                         goto stop_net_activity;
111         }
112
113 stop_net_activity:
114         stop_net_activity();
115         close(context->sock);
116         free(context);
117         return NULL;
118
119 }
120
121 API resourced_ret_c register_net_activity_cb(net_activity_cb activity_cb)
122 {
123         int ret;
124         struct net_activity_context *context;
125         pid_t pid;
126
127         ret_value_msg_if(!activity_cb, RESOURCED_ERROR_INVALID_PARAMETER,
128                 "Please provide valid callback function!");
129
130         context = (struct net_activity_context *)malloc(
131                 sizeof(struct net_activity_context));
132
133         ret_value_if(!context, RESOURCED_ERROR_OUT_OF_MEMORY);
134
135         context->cb = activity_cb;
136         ret = update_classids();
137         if (ret != RESOURCED_ERROR_NONE) {
138                 _E("Failed to update appid!");
139                 goto free_context;
140         }
141
142         context->sock = create_netlink(NETLINK_GENERIC, 0);
143
144         if (context->sock < 0) {
145                 _E("Cant create socket");
146                 goto free_context;
147         }
148
149         set_socket_option(context->sock);
150         pid = getpid();
151         /* Initialize family id to communicate with NET_ACTIVITY chanel */
152         context->group_family_id = get_family_group_id(context->sock,
153                 pid, "NET_ACTIVITY", "NET_ACT_MCAST", &context->family_id);
154
155         start_net_activity();
156
157         if (context->family_id == 0 || context->group_family_id == 0) {
158                 _E("Cant get family id");
159                 goto close_socket;
160         }
161
162         /* this one is no more needed */
163         close(context->sock);
164
165         /* New one subscribed to group_family_id */
166         context->sock = create_netlink(NETLINK_GENERIC,
167                 convert_mcast_group_id(context->group_family_id));
168
169         if (context->sock < 0) {
170                 _E("Failed to create multicast socket!");
171                 goto free_context;
172         }
173
174         /* start thread */
175         pthread_create(&net_activity_worker, NULL, net_activity_func,
176                 (void *)context);
177
178         return RESOURCED_ERROR_NONE;
179
180 close_socket:
181         close(context->sock);
182
183 free_context:
184         free(context);
185
186         stop_net_activity();
187         return RESOURCED_ERROR_FAIL;
188 }