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