tizen 2.4 release
[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 #include <time.h>
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                         struct timespec time = {
143                                 .tv_sec = 0,
144                                 .tv_nsec = 1000 * 1000 * 100
145                         };
146
147                         nanosleep(&time, NULL);
148                         retry--;
149                         goto retry_con;
150                 }
151         }
152         if (ret < 0) {
153                 close(fd);
154                 return -1;
155         }
156
157         __set_sock_option(fd, 1);
158
159         return fd;
160 }
161
162 static int __connect_client_sock(int fd, const struct sockaddr *saptr, socklen_t salen,
163                    int nsec)
164 {
165         int flags;
166         int ret;
167         int error;
168         socklen_t len;
169         fd_set readfds;
170         fd_set writefds;
171         struct timeval timeout;
172
173         flags = fcntl(fd, F_GETFL, 0);
174         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
175
176         error = 0;
177         if ((ret = connect(fd, (struct sockaddr *)saptr, salen)) < 0) {
178                 if (errno != EAGAIN && errno != EINPROGRESS) {
179                         (void)fcntl(fd, F_SETFL, flags);        
180                         return (-2);
181                 }
182         }
183
184         /* Do whatever we want while the connect is taking place. */
185         if (ret == 0)
186                 goto done;      /* connect completed immediately */
187
188         FD_ZERO(&readfds);
189         FD_SET(fd, &readfds);
190         writefds = readfds;
191         timeout.tv_sec = 0;
192         timeout.tv_usec = nsec;
193
194         if ((ret = select(fd + 1, &readfds, &writefds, NULL, 
195                         nsec ? &timeout : NULL)) == 0) {
196                 close(fd);      /* timeout */
197                 errno = ETIMEDOUT;
198                 return (-1);
199         }
200
201         if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
202                 len = sizeof(error);
203                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
204                         return (-1);    /* Solaris pending error */
205         } else
206                 return (-1);    /* select error: sockfd not set*/
207
208  done:
209         (void)fcntl(fd, F_SETFL, flags);
210         if (error) {
211                 close(fd);      
212                 errno = error;
213                 return (-1);
214         }
215         return (0);
216 }
217
218 /**
219  * @brief       Send data (in raw) to the process with 'pid' via socket
220  */
221 int _app_send_raw(int cmd, unsigned char *data, int datalen)
222 {
223         int fd;
224         int len;
225         int res = 0;
226         ac_pkt_t *pkt = NULL;
227
228         if (data == NULL || datalen > AC_SOCK_MAXBUFF - 8) {
229                 _E("keybundle error\n");
230                 return -EINVAL;
231         }
232
233         fd = _create_client_sock();
234         if (fd < 0)
235                 return -ECOMM;
236
237         pkt = (ac_pkt_t *) malloc(sizeof(char) * AC_SOCK_MAXBUFF);
238         if (NULL == pkt) {
239                 _E("Malloc Failed!");
240                 return -ENOMEM;
241         }
242         memset(pkt, 0, AC_SOCK_MAXBUFF);
243
244         pkt->cmd = cmd;
245         pkt->len = datalen;
246         memcpy(pkt->data, data, datalen);
247
248         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
249                 _E("sendto() failed - %d %d", len, datalen + 8);
250                 if (errno == EPIPE) {
251                         _E("fd:%d\n", fd);
252                 }
253                 close(fd);
254                 if (pkt) {
255                         free(pkt);
256                         pkt = NULL;
257                 }
258                 return -ECOMM;
259         }
260         if (pkt) {
261                 free(pkt);
262                 pkt = NULL;
263         }
264
265         len = recv(fd, &res, sizeof(int), 0);
266         if (len == -1) {
267                 if (errno == EAGAIN) {
268                         _E("recv timeout \n");
269                         res = -EAGAIN;
270                 } else {
271                         _E("recv error\n");
272                         res = -ECOMM;
273                 }
274         } else
275                 _D("recv result  = %d (%d)", res, len);
276         close(fd);
277
278         return res;
279 }
280
281 ac_pkt_t *_app_recv_raw(int fd, int *clifd, struct ucred *cr)
282 {
283         int len;
284         struct sockaddr_un aul_addr = { 0, };
285         int sun_size;
286         ac_pkt_t *pkt = NULL;
287         int cl = sizeof(struct ucred);
288
289         sun_size = sizeof(struct sockaddr_un);
290
291         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
292                              (socklen_t *) &sun_size)) == -1) {
293                 if (errno != EINTR)
294                         _E("accept error");
295                 return NULL;
296         }
297
298         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
299                        (socklen_t *) &cl) < 0) {
300                 _E("peer information error");
301                 close(*clifd);
302                 return NULL;
303         }
304
305         pkt = (ac_pkt_t *) malloc(sizeof(char) * AC_SOCK_MAXBUFF);
306         if(pkt == NULL) {
307                 close(*clifd);
308                 return NULL;
309         }
310         memset(pkt, 0, AC_SOCK_MAXBUFF);
311
312         __set_sock_option(*clifd, 1);
313
314  retry_recv:
315         /* receive single packet from socket */
316         len = recv(*clifd, pkt, AC_SOCK_MAXBUFF, 0);
317         if (len < 0)
318                 if (errno == EINTR)
319                         goto retry_recv;
320
321         if ((len < 8) || (len != (pkt->len + 8))) {
322                 _E("recv error %d %d", len, pkt->len);
323                 free(pkt);
324                 close(*clifd);
325                 return NULL;
326         }
327
328         return pkt;
329 }
330
331 int _send_result_to_server(int fd, int res)
332 {
333         if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
334                 if (errno == EPIPE)
335                         _E("send failed due to EPIPE.\n");
336                 _E("send fail to client");
337         }
338         close(fd);
339         return 0;
340 }