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