c57d8b62cd3349f50706a793cd9afe0b13cc57de
[framework/appfw/app-checker.git] / src / ac_sock.c
1 /*
2  *  app-checker
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29 #include <fcntl.h>
30
31
32 #include "ac_sock.h"
33 #include "internal.h"
34
35 static int __connect_client_sock(int sockfd, const struct sockaddr *saptr, socklen_t salen,
36                    int nsec);
37
38 static inline void __set_sock_option(int fd, int cli)
39 {
40         int ret;
41         int size;
42         struct timeval tv = { 5, 200 * 1000 };  /*  5.2 sec */
43
44         size = AC_SOCK_MAXBUFF;
45         ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
46         if ( ret < 0 ) {
47                 _E("setsockopt error");
48         }
49
50         ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
51         if ( ret < 0 ) {
52                 _E("setsockopt error");
53         }
54
55         if (cli) {
56                 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
57                 if ( ret < 0 ) {
58                         _E("setsockopt error");
59                 }
60         }
61 }
62
63 int _create_server_sock()
64 {
65         struct sockaddr_un saddr;
66         int fd;
67
68         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
69         /*  support above version 2.6.27*/
70         if (fd < 0) {
71                 if(errno == EINVAL) {
72                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
73                         if(fd < 0) {
74                                 _E("second chance - socket create error");
75                                 return -1;
76                         }
77                 } else {
78                         _E("socket error");
79                         return -1;
80                 }
81         }
82
83         memset(&saddr, 0, sizeof(saddr));
84         saddr.sun_family = AF_UNIX;
85         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s",AC_SOCK_NAME);
86         unlink(saddr.sun_path);
87         
88         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
89                 _E("bind error");
90                 close(fd);
91                 return -1;
92         }
93
94         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
95                 /* Flawfinder: ignore*/
96                 _E("failed to change the socket permission");
97                 close(fd);
98                 return -1;
99         }
100
101         __set_sock_option(fd, 0);
102
103         if (listen(fd, 10) == -1) {
104                 _E("listen error");
105                 close(fd);
106                 return -1;
107         }       
108
109         return fd;
110 }
111
112 int _create_client_sock()
113 {
114         int fd = -1;
115         struct sockaddr_un saddr = { 0, };
116         int retry = 1;
117         int ret = -1;
118
119         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);    
120         /*  support above version 2.6.27*/
121         if (fd < 0) {
122                 if (errno == EINVAL) {
123                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
124                         if (fd < 0) {
125                                 _E("second chance - socket create error");
126                                 return -1;
127                         }
128                 } else {
129                         _E("socket error");
130                         return -1;
131                 }
132         }
133
134         saddr.sun_family = AF_UNIX;
135         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s", AC_SOCK_NAME);
136  retry_con:
137         ret = __connect_client_sock(fd, (struct sockaddr *)&saddr, sizeof(saddr),
138                         100 * 1000);
139         if (ret < -1) {
140                 _E("maybe peer not launched or peer daed\n");
141                 if (retry > 0) {
142                         usleep(100 * 1000);
143                         retry--;
144                         goto retry_con;
145                 }
146         }
147         if (ret < 0) {
148                 close(fd);
149                 return -1;
150         }
151
152         __set_sock_option(fd, 1);
153
154         return fd;
155 }
156
157 static int __connect_client_sock(int fd, const struct sockaddr *saptr, socklen_t salen,
158                    int nsec)
159 {
160         int flags;
161         int ret;
162         int error;
163         socklen_t len;
164         fd_set readfds;
165         fd_set writefds;
166         struct timeval timeout;
167
168         flags = fcntl(fd, F_GETFL, 0);
169         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
170
171         error = 0;
172         if ((ret = connect(fd, (struct sockaddr *)saptr, salen)) < 0) {
173                 if (errno != EAGAIN && errno != EINPROGRESS) {
174                         (void)fcntl(fd, F_SETFL, flags);        
175                         return (-2);
176                 }
177         }
178
179         /* Do whatever we want while the connect is taking place. */
180         if (ret == 0)
181                 goto done;      /* connect completed immediately */
182
183         FD_ZERO(&readfds);
184         FD_SET(fd, &readfds);
185         writefds = readfds;
186         timeout.tv_sec = 0;
187         timeout.tv_usec = nsec;
188
189         if ((ret = select(fd + 1, &readfds, &writefds, NULL, 
190                         nsec ? &timeout : NULL)) == 0) {
191                 close(fd);      /* timeout */
192                 errno = ETIMEDOUT;
193                 return (-1);
194         }
195
196         if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
197                 len = sizeof(error);
198                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
199                         return (-1);    /* Solaris pending error */
200         } else
201                 return (-1);    /* select error: sockfd not set*/
202
203  done:
204         (void)fcntl(fd, F_SETFL, flags);
205         if (error) {
206                 close(fd);      
207                 errno = error;
208                 return (-1);
209         }
210         return (0);
211 }
212
213 /**
214  * @brief       Send data (in raw) to the process with 'pid' via socket
215  */
216 int _app_send_raw(int cmd, unsigned char *data, int datalen)
217 {
218         int fd;
219         int len;
220         int res = 0;
221         ac_pkt_t *pkt = NULL;
222
223         if (data == NULL || datalen > AC_SOCK_MAXBUFF - 8) {
224                 _E("keybundle error\n");
225                 return -EINVAL;
226         }
227
228         fd = _create_client_sock();
229         if (fd < 0)
230                 return -ECOMM;
231
232         pkt = (ac_pkt_t *) malloc(sizeof(char) * AC_SOCK_MAXBUFF);
233         if (NULL == pkt) {
234                 _E("Malloc Failed!");
235                 return -ENOMEM;
236         }
237         memset(pkt, 0, AC_SOCK_MAXBUFF);
238
239         pkt->cmd = cmd;
240         pkt->len = datalen;
241         memcpy(pkt->data, data, datalen);
242
243         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
244                 _E("sendto() failed - %d %d", len, datalen + 8);
245                 if (errno == EPIPE) {
246                         _E("fd:%d\n", fd);
247                 }
248                 close(fd);
249                 if (pkt) {
250                         free(pkt);
251                         pkt = NULL;
252                 }
253                 return -ECOMM;
254         }
255         if (pkt) {
256                 free(pkt);
257                 pkt = NULL;
258         }
259
260         len = recv(fd, &res, sizeof(int), 0);
261         if (len == -1) {
262                 if (errno == EAGAIN) {
263                         _E("recv timeout \n");
264                         res = -EAGAIN;
265                 } else {
266                         _E("recv error\n");
267                         res = -ECOMM;
268                 }
269         } else
270                 _D("recv result  = %d (%d)", res, len);
271         close(fd);
272
273         return res;
274 }
275
276 ac_pkt_t *_app_recv_raw(int fd, int *clifd, struct ucred *cr)
277 {
278         int len;
279         struct sockaddr_un aul_addr = { 0, };
280         int sun_size;
281         ac_pkt_t *pkt = NULL;
282         int cl = sizeof(struct ucred);
283
284         sun_size = sizeof(struct sockaddr_un);
285
286         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
287                              (socklen_t *) &sun_size)) == -1) {
288                 if (errno != EINTR)
289                         _E("accept error");
290                 return NULL;
291         }
292
293         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
294                        (socklen_t *) &cl) < 0) {
295                 _E("peer information error");
296                 close(*clifd);
297                 return NULL;
298         }
299
300         pkt = (ac_pkt_t *) malloc(sizeof(char) * AC_SOCK_MAXBUFF);
301         if(pkt == NULL) {
302                 close(*clifd);
303                 return NULL;
304         }
305         memset(pkt, 0, AC_SOCK_MAXBUFF);
306
307         __set_sock_option(*clifd, 1);
308
309  retry_recv:
310         /* receive single packet from socket */
311         len = recv(*clifd, pkt, AC_SOCK_MAXBUFF, 0);
312         if (len < 0)
313                 if (errno == EINTR)
314                         goto retry_recv;
315
316         if ((len < 8) || (len != (pkt->len + 8))) {
317                 _E("recv error %d %d", len, pkt->len);
318                 free(pkt);
319                 close(*clifd);
320                 return NULL;
321         }
322
323         return pkt;
324 }
325
326 int _send_result_to_server(int fd, int res)
327 {
328         if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
329                 if (errno == EPIPE)
330                         _E("send failed due to EPIPE.\n");
331                 _E("send fail to client");
332         }
333         close(fd);
334         return 0;
335 }