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