cc2328e0494388b8975fdd666eeae30376a441ad
[platform/framework/web/wrt.git] / src / wrt-launchpad-daemon / src / app_sock.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/smack.h>
24 #include <errno.h>
25 #include <fcntl.h>
26
27 #include "app_sock.h"
28 #include "simple_util.h"
29
30 static int __connect_client_sock(int sockfd, const struct sockaddr *saptr, socklen_t salen,
31                    int nsec);
32
33
34 static inline void __set_sock_option(int fd, int cli)
35 {
36         int size;
37         struct timeval tv = { 3, 200 * 1000 };  /*  3.2 sec */
38
39         size = AUL_SOCK_MAXBUFF;
40         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
41         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
42         if (cli)
43                 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
44 }
45
46 int __create_server_sock(int pid)
47 {
48         struct sockaddr_un saddr;
49         struct sockaddr_un p_saddr;
50         int fd;
51         mode_t orig_mask;
52
53         /* Create basedir for our sockets */
54         orig_mask = umask(0);
55         mkdir(AUL_SOCK_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
56         umask(orig_mask);
57
58         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
59         /*  support above version 2.6.27*/
60         if (fd < 0) {
61                 if (errno == EINVAL) {
62                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
63                         if (fd < 0) {
64                                 _E("second chance - socket create error");
65                                 return -1;
66                         }
67                 } else {
68                         _E("socket error");
69                         return -1;
70                 }
71         }
72
73         bzero(&saddr, sizeof(saddr));
74         saddr.sun_family = AF_UNIX;
75         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, pid);
76         unlink(saddr.sun_path);
77
78         /* labeling to socket for SMACK */
79         if(getuid() == 0) {     // this is meaningful iff current user is ROOT
80                 if(smack_fsetlabel(fd, "@", SMACK_LABEL_IPOUT) != 0) {
81                         /* in case of unsupported filesystem on 'socket' */
82                         /* or permission error by using 'emulator', bypass*/
83                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
84                                 _E("labeling to socket(IPOUT) error");
85                                 return -1;
86                         }
87                 }
88                 if(smack_fsetlabel(fd, "*", SMACK_LABEL_IPIN) != 0) {
89                         /* in case of unsupported filesystem on 'socket' */
90                         /* or permission error by using 'emulator', bypass*/
91                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
92                                 _E("labeling to socket(IPIN) error");
93                                 return -1;
94                         }
95                 }
96         }
97
98         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
99                 _E("bind error");
100                 return -1;
101         }
102
103         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
104                 /* Flawfinder: ignore*/
105                 _E("failed to change the socket permission");
106                 return -1;
107         }
108
109         __set_sock_option(fd, 0);
110
111         if (listen(fd, 10) == -1) {
112                 _E("listen error");
113                 return -1;
114         }
115
116         /* support app launched by shell script */
117         if (pid != WRT_LAUNCHPAD_PID) {
118                 int pgid;
119                 pgid = getpgid(pid);
120                 if (pgid > 1) {
121                         snprintf(p_saddr.sun_path, UNIX_PATH_MAX, "%s/%d",
122                                  AUL_SOCK_PREFIX, pgid);
123                         if (link(saddr.sun_path, p_saddr.sun_path) < 0) {
124                                 if (errno == EEXIST)
125                                         _D("pg path - already exists");
126                                 else
127                                         _E("pg path - unknown create error");
128                         }
129                 }
130         }
131
132         return fd;
133 }
134
135 int __create_client_sock(int pid)
136 {
137         int fd = -1;
138         struct sockaddr_un saddr = { 0, };
139         int retry = 1;
140         int ret = -1;
141
142         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);    
143         /*  support above version 2.6.27*/
144         if (fd < 0) {
145                 if (errno == EINVAL) {
146                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
147                         if (fd < 0) {
148                                 _E("second chance - socket create error");
149                                 return -1;
150                         }
151                 } else {
152                         _E("socket error");
153                         return -1;
154                 }
155         }
156
157         saddr.sun_family = AF_UNIX;
158         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, pid);
159  retry_con:
160         ret = __connect_client_sock(fd, (struct sockaddr *)&saddr, sizeof(saddr),
161                         100 * 1000);
162         if (ret < -1) {
163                 _E("maybe peer not launched or peer daed\n");
164                 if (retry > 0) {
165                         usleep(100 * 1000);
166                         retry--;
167                         goto retry_con;
168                 }
169         }
170         if (ret < 0) {
171                 close(fd);
172                 return -1;
173         }
174
175         __set_sock_option(fd, 1);
176
177         return fd;
178 }
179
180 static int __connect_client_sock(int fd, const struct sockaddr *saptr, socklen_t salen,
181                    int nsec)
182 {
183         int flags;
184         int ret;
185         int error;
186         socklen_t len;
187         fd_set readfds;
188         fd_set writefds;
189         struct timeval timeout;
190
191         flags = fcntl(fd, F_GETFL, 0);
192         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
193
194         error = 0;
195         if ((ret = connect(fd, (struct sockaddr *)saptr, salen)) < 0) {
196                 if (errno != EAGAIN && errno != EINPROGRESS) {
197                         fcntl(fd, F_SETFL, flags);      
198                         return (-2);
199                 }
200         }
201
202         /* Do whatever we want while the connect is taking place. */
203         if (ret == 0)
204                 goto done;      /* connect completed immediately */
205
206         FD_ZERO(&readfds);
207         FD_SET(fd, &readfds);
208         writefds = readfds;
209         timeout.tv_sec = 0;
210         timeout.tv_usec = nsec;
211
212         if ((ret = select(fd + 1, &readfds, &writefds, NULL, 
213                         nsec ? &timeout : NULL)) == 0) {
214                 close(fd);      /* timeout */
215                 errno = ETIMEDOUT;
216                 return (-1);
217         }
218
219         if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
220                 len = sizeof(error);
221                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
222                         return (-1);    /* Solaris pending error */
223         } else
224                 return (-1);    /* select error: sockfd not set*/
225
226  done:
227         fcntl(fd, F_SETFL, flags);      
228         if (error) {
229                 close(fd);      
230                 errno = error;
231                 return (-1);
232         }
233         return (0);
234 }
235
236 /**
237  * @brief       Send data (in raw) to the process with 'pid' via socket
238  */
239 int __app_send_raw(int pid, int cmd, unsigned char *kb_data, int datalen)
240 {
241         int fd;
242         int len;
243         int res = 0;
244         app_pkt_t *pkt = NULL;
245
246         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
247                 _E("keybundle error\n");
248                 return -EINVAL;
249         }
250
251         fd = __create_client_sock(pid);
252         if (fd < 0)
253                 return -ECOMM;
254
255         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
256         if (NULL == pkt) {
257                 _E("Malloc Failed!");
258                 return -ENOMEM;
259         }
260         memset(pkt, 0, AUL_SOCK_MAXBUFF);
261
262         pkt->cmd = cmd;
263         pkt->len = datalen;
264         memcpy(pkt->data, kb_data, datalen);
265
266         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
267                 _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno);
268                 if (errno == EPIPE) {
269                         _E("pid:%d, fd:%d\n", pid, fd);
270                 }
271                 close(fd);
272                 if (pkt) {
273                         free(pkt);
274                         pkt = NULL;
275                 }
276                 return -ECOMM;
277         }
278         if (pkt) {
279                 free(pkt);
280                 pkt = NULL;
281         }
282
283         len = recv(fd, &res, sizeof(int), 0);
284         if (len == -1) {
285                 if (errno == EAGAIN) {
286                         _E("recv timeout \n");
287                         res = -EAGAIN;
288                 } else {
289                         _E("recv error\n");
290                         res = -ECOMM;
291                 }
292         }
293         close(fd);
294
295         return res;
296 }
297
298 app_pkt_t *__app_recv_raw(int fd, int *clifd, struct ucred *cr)
299 {
300         int len;
301         struct sockaddr_un aul_addr = { 0, };
302         int sun_size;
303         app_pkt_t *pkt = NULL;
304         int cl = sizeof(struct ucred);
305
306         sun_size = sizeof(struct sockaddr_un);
307
308         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
309                              (socklen_t *) &sun_size)) == -1) {
310                 if (errno != EINTR)
311                         _E("accept error");
312                 return NULL;
313         }
314
315         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
316                        (socklen_t *) &cl) < 0) {
317                 _E("peer information error");
318                 close(*clifd);
319                 return NULL;
320         }
321
322         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
323         if(pkt == NULL) {
324                 close(*clifd);
325                 return NULL;
326         }
327         memset(pkt, 0, AUL_SOCK_MAXBUFF);
328
329         __set_sock_option(*clifd, 1);
330
331  retry_recv:
332         /* receive single packet from socket */
333         len = recv(*clifd, pkt, AUL_SOCK_MAXBUFF, 0);
334         if (len < 0)
335                 if (errno == EINTR)
336                         goto retry_recv;
337
338         if ((len < 8) || (len != (pkt->len + 8))) {
339                 _E("recv error %d %d", len, pkt->len);
340                 free(pkt);
341                 close(*clifd);
342                 return NULL;
343         }
344
345         return pkt;
346 }
347
348 app_pkt_t *__app_send_cmd_with_result(int pid, int cmd)
349 {
350         int fd;
351         int len;
352         app_pkt_t *pkt = NULL;
353
354         fd = __create_client_sock(pid);
355         if (fd < 0)
356                 return NULL;
357
358         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
359         if (NULL == pkt) {
360                 _E("Malloc Failed!");
361                 return NULL;
362         }
363         memset(pkt, 0, AUL_SOCK_MAXBUFF);
364
365         pkt->cmd = cmd;
366         pkt->len = 0;
367
368         if ((len = send(fd, pkt, 8, 0)) != 8) {
369                 _E("sendto() failed - %d", len);
370                 if (errno == EPIPE) {
371                         _E("pid:%d, fd:%d\n", pid, fd);
372                 }
373                 close(fd);
374
375                 free(pkt);
376                 return NULL;
377         }
378
379 retry_recv:
380        /* receive single packet from socket */
381         len = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
382         if (len == -1) {
383                 if (errno == EAGAIN) {
384                         _E("recv timeout \n");
385                         free(pkt);
386                         return NULL;
387                 } else if (errno == EINTR) {
388                         goto retry_recv;
389                 } else {
390                         _E("recv error %s\n", strerror(errno));
391                         free(pkt);
392                         return NULL;
393                 }
394         } else
395                 _D("recv result  = %d", len);
396         close(fd);
397
398         return pkt;
399 }
400
401