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