2bbfcaa6c343611261fc3d31b7cc450e5eac4d67
[framework/appfw/aul-1.git] / src / app_sock.c
1 /*
2  *  aul
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #define _GNU_SOURCE
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/smack.h>
30 #include <errno.h>
31 #include <fcntl.h>
32
33 #include "app_sock.h"
34 #include "simple_util.h"
35
36 static int __connect_client_sock(int sockfd, const struct sockaddr *saptr, socklen_t salen,
37                    int nsec);
38
39 char *_socket_prefix = NULL;
40 char *_root_path = NULL;
41 char *_cur_zone = NULL;
42 int _pid_offset = 0;
43
44 const char* _get_sock_prefix()
45 {
46         if (_socket_prefix == NULL)
47                 return "/tmp/alaunch";
48
49         return _socket_prefix;
50 }
51
52 const char* _get_root_path()
53 {
54         if (_root_path == NULL)
55                 return "/";
56
57         return _root_path;
58 }
59
60 static inline void __set_sock_option(int fd, int cli)
61 {
62         int size;
63         struct timeval tv = { 5, 200 * 1000 };  /*  5.2 sec */
64
65         size = AUL_SOCK_MAXBUFF;
66         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
67         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
68         if (cli)
69                 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
70 }
71
72 int __create_server_sock(int pid)
73 {
74         struct sockaddr_un saddr;
75         struct sockaddr_un p_saddr;
76         int fd;
77         mode_t orig_mask;
78
79         /* Create basedir for our sockets */
80         orig_mask = umask(0);
81         (void) mkdir(AUL_SOCK_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
82         umask(orig_mask);
83
84         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
85         /*  support above version 2.6.27*/
86         if (fd < 0) {
87                 if (errno == EINVAL) {
88                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
89                         if (fd < 0) {
90                                 _E("second chance - socket create error: %d", errno);
91                                 return -1;
92                         }
93                 } else {
94                         _E("socket error: %d", errno);
95                         return -1;
96                 }
97         }
98
99         memset(&saddr, 0, sizeof(saddr));
100         saddr.sun_family = AF_UNIX;
101         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, pid);
102         unlink(saddr.sun_path);
103
104         /* labeling to socket for SMACK */
105         if(getuid() == 0) {     // this is meaningful iff current user is ROOT
106                 if(smack_fsetlabel(fd, "@", SMACK_LABEL_IPOUT) != 0) {
107                         /* in case of unsupported filesystem on 'socket' */
108                         /* or permission error by using 'emulator', bypass*/
109                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
110                                 _E("labeling to socket(IPOUT) error");
111                                 close(fd);
112                                 return -1;
113                         }
114                 }
115                 if(smack_fsetlabel(fd, "*", SMACK_LABEL_IPIN) != 0) {
116                         /* in case of unsupported filesystem on 'socket' */
117                         /* or permission error by using 'emulator', bypass*/
118                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
119                                 _E("labeling to socket(IPIN) error");
120                                 close(fd);
121                                 return -1;
122                         }
123                 }
124         }
125
126         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
127                 _E("bind error: %d", errno);
128                 close(fd);
129                 return -1;
130         }
131
132         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
133                 /* Flawfinder: ignore*/
134                 _E("failed to change the socket permission");
135                 close(fd);
136                 return -1;
137         }
138
139         __set_sock_option(fd, 0);
140
141         if (listen(fd, 128) == -1) {
142                 _E("listen error: %d", errno);
143                 close(fd);
144                 return -1;
145         }
146
147         /* support app launched by shell script */
148         if (pid > 0 || pid == WEB_LAUNCHPAD_PID) {
149                 int pgid;
150                 pgid = getpgid(pid);
151                 if (pgid > 1) {
152                         snprintf(p_saddr.sun_path, UNIX_PATH_MAX, "%s/%d",
153                                  AUL_SOCK_PREFIX, pgid);
154                         if (link(saddr.sun_path, p_saddr.sun_path) < 0) {
155                                 if (errno == EEXIST)
156                                         _D("pg path - already exists");
157                                 else
158                                         _E("pg path - unknown create error");
159                         }
160                 }
161         }
162
163         return fd;
164 }
165
166 int __create_client_sock(int pid)
167 {
168         int fd = -1;
169         struct sockaddr_un saddr = { 0, };
170         int retry = 2;
171         int ret = -1;
172
173         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
174         /*  support above version 2.6.27*/
175         if (fd < 0) {
176                 if (errno == EINVAL) {
177                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
178                         if (fd < 0) {
179                                 _E("second chance - socket create error: %d", errno);
180                                 return -1;
181                         }
182                 } else {
183                         _E("socket error: %d", errno);
184                         return -1;
185                 }
186         }
187
188         saddr.sun_family = AF_UNIX;
189         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, pid);
190  retry_con:
191         ret = __connect_client_sock(fd, (struct sockaddr *)&saddr, sizeof(saddr),
192                         100 * 1000);
193         if (ret < -1) {
194                 _E("cannot connect the client socket: %d", errno);
195                 if (retry > 0) {
196                         usleep((1+2*(2-retry))*100 * 1000);
197                         retry--;
198                         goto retry_con;
199                 }
200         }
201         if (ret < 0) {
202                 close(fd);
203                 return -1;
204         }
205
206         __set_sock_option(fd, 1);
207
208         return fd;
209 }
210
211 static int __connect_client_sock(int fd, const struct sockaddr *saptr, socklen_t salen,
212                    int nsec)
213 {
214         int flags;
215         int ret;
216         int error;
217         socklen_t len;
218         fd_set readfds;
219         fd_set writefds;
220         struct timeval timeout;
221
222         flags = fcntl(fd, F_GETFL, 0);
223         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
224
225         error = 0;
226         if ((ret = connect(fd, (struct sockaddr *)saptr, salen)) < 0) {
227                 if (errno != EAGAIN && errno != EINPROGRESS) {
228                         _E("connect error: %d", errno);
229                         fcntl(fd, F_SETFL, flags);
230                         return (-2);
231                 }
232         }
233
234         /* Do whatever we want while the connect is taking place. */
235         if (ret == 0)
236                 goto done;      /* connect completed immediately */
237
238         FD_ZERO(&readfds);
239         FD_SET(fd, &readfds);
240         writefds = readfds;
241         timeout.tv_sec = 0;
242         timeout.tv_usec = nsec;
243
244         if ((ret = select(fd + 1, &readfds, &writefds, NULL,
245                         nsec ? &timeout : NULL)) == 0) {
246                 _E("select timeout");
247                 close(fd);      /* timeout */
248                 errno = ETIMEDOUT;
249                 return (-1);
250         }
251
252         if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
253                 len = sizeof(error);
254                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
255                         return (-1);    /* Solaris pending error */
256         } else
257                 return (-1);    /* select error: sockfd not set*/
258
259  done:
260         (void) fcntl(fd, F_SETFL, flags);
261         if (error) {
262                 close(fd);
263                 errno = error;
264                 return (-1);
265         }
266         return (0);
267 }
268
269 /**
270  * @brief       Send data (in raw) to the process with 'pid' via socket
271  */
272 int __app_send_raw(int pid, int cmd, unsigned char *kb_data, int datalen)
273 {
274         int fd;
275         int len;
276         int ret;
277         int res = 0;
278         app_pkt_t *pkt = NULL;
279
280         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
281                 _E("keybundle error\n");
282                 return -EINVAL;
283         }
284
285         _D("pid(%d) : cmd(%d)", pid, cmd);
286
287         fd = __create_client_sock(pid);
288         if (fd < 0) {
289                 _E("cannot create a client socket: %d", fd);
290                 return -ECOMM;
291         }
292
293         /* aul_app_is_running timeout : 25sec */
294         if(cmd == APP_IS_RUNNING) {
295                 struct timeval tv = { 25, 0 };
296                 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
297                 if ( ret < 0 ) {
298                         _E("setsockopt error");
299                 }
300         }
301
302         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
303         if (NULL == pkt) {
304                 _E("Malloc Failed!");
305                 return -ENOMEM;
306         }
307         memset(pkt, 0, AUL_SOCK_MAXBUFF);
308
309         pkt->cmd = cmd;
310         pkt->len = datalen;
311         memcpy(pkt->data, kb_data, datalen);
312
313         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
314                 _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno);
315                 if(len > 0) {
316                         while (len != datalen + 8) {
317                                 ret = send(fd, &pkt->data[len-8], datalen + 8 - len, 0);
318                                 if (ret < 0) {
319                                         _E("second send() failed - %d %d (errno: %d)", ret, datalen + 8, errno);
320                                         if (errno == EPIPE) {
321                                                 _E("pid:%d, fd:%d\n", pid, fd);
322                                         }
323                                         close(fd);
324                                         if (pkt) {
325                                                 free(pkt);
326                                                 pkt = NULL;
327                                         }
328                                         return -ECOMM;
329                                 }
330                                 len += ret;
331                                 _D("send() len - %d %d", len, datalen + 8);
332                         }
333                 } else {
334                         if (errno == EPIPE) {
335                                 _E("pid:%d, fd:%d\n", pid, fd);
336                         }
337                         close(fd);
338                         if (pkt) {
339                                 free(pkt);
340                                 pkt = NULL;
341                         }
342
343                         _E("send() failed: %d %s", errno, strerror(errno));
344                         return -ECOMM;
345                 }
346         }
347         if (pkt) {
348                 free(pkt);
349                 pkt = NULL;
350         }
351
352 retry_recv:
353         len = recv(fd, &res, sizeof(int), 0);
354         if (len == -1) {
355                 if (errno == EAGAIN) {
356                         _E("recv timeout : cmd(%d) %s", cmd, strerror(errno));
357                         res = -EAGAIN;
358                 } else if (errno == EINTR) {
359                         _D("recv : %s", strerror(errno));
360                         goto retry_recv;
361                 } else {
362                         _E("recv error : %s", strerror(errno));
363                         res = -ECOMM;
364                 }
365         }
366         close(fd);
367
368         return res;
369 }
370
371 int __app_send_raw_with_noreply(int pid, int cmd, unsigned char *kb_data, int datalen)
372 {
373         int fd;
374         int len;
375         int ret;
376         int res = 0;
377         app_pkt_t *pkt = NULL;
378
379         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
380                 _E("keybundle error\n");
381                 return -EINVAL;
382         }
383
384         _D("pid(%d) : cmd(%d)", pid, cmd);
385
386         fd = __create_client_sock(pid);
387         if (fd < 0)
388                 return -ECOMM;
389
390         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
391         if (NULL == pkt) {
392                 _E("Malloc Failed!");
393                 return -ENOMEM;
394         }
395         memset(pkt, 0, AUL_SOCK_MAXBUFF);
396
397         pkt->cmd = cmd;
398         pkt->len = datalen;
399         memcpy(pkt->data, kb_data, datalen);
400
401         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
402                 _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno);
403                 if(len > 0) {
404                         while (len != datalen + 8) {
405                                 ret = send(fd, &pkt->data[len-8], datalen + 8 - len, 0);
406                                 if (ret < 0) {
407                                         _E("second sendto() failed - %d %d (errno %d)", ret, datalen + 8, errno);
408                                         if (errno == EPIPE) {
409                                                 _E("pid:%d, fd:%d\n", pid, fd);
410                                         }
411                                         close(fd);
412                                         if (pkt) {
413                                                 free(pkt);
414                                                 pkt = NULL;
415                                         }
416                                         return -ECOMM;
417                                 }
418                                 len += ret;
419                                 _D("sendto() len - %d %d", len, datalen + 8);
420                         }
421                 } else {
422                         if (errno == EPIPE) {
423                                 _E("pid:%d, fd:%d\n", pid, fd);
424                         }
425                         close(fd);
426                         if (pkt) {
427                                 free(pkt);
428                                 pkt = NULL;
429                         }
430                         return -ECOMM;
431                 }
432         }
433         if (pkt) {
434                 free(pkt);
435                 pkt = NULL;
436         }
437
438         close(fd);
439
440         return res;
441 }
442
443 int __app_send_raw_with_delay_reply(int pid, int cmd, unsigned char *kb_data, int datalen)
444 {
445         int fd;
446         int len;
447         int ret;
448         app_pkt_t *pkt = NULL;
449
450         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
451                 _E("keybundle error\n");
452                 return -EINVAL;
453         }
454
455         _D("pid(%d) : cmd(%d)", pid, cmd);
456
457         fd = __create_client_sock(pid);
458         if (fd < 0)
459                 return -ECOMM;
460
461         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
462         if (NULL == pkt) {
463                 _E("Malloc Failed!");
464                 return -ENOMEM;
465         }
466         memset(pkt, 0, AUL_SOCK_MAXBUFF);
467
468         pkt->cmd = cmd;
469         pkt->len = datalen;
470         memcpy(pkt->data, kb_data, datalen);
471
472         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
473                 _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno);
474                 if(len > 0) {
475                         while (len != datalen + 8) {
476                                 ret = send(fd, &pkt->data[len-8], datalen + 8 - len, 0);
477                                 if (ret < 0) {
478                                         _E("second sendto() failed - %d %d (errno %d)", ret, datalen + 8, errno);
479                                         if (errno == EPIPE) {
480                                                 _E("pid:%d, fd:%d\n", pid, fd);
481                                         }
482                                         close(fd);
483                                         if (pkt) {
484                                                 free(pkt);
485                                                 pkt = NULL;
486                                         }
487                                         return -ECOMM;
488                                 }
489                                 len += ret;
490                                 _D("sendto() len - %d %d", len, datalen + 8);
491                         }
492                 } else {
493                         if (errno == EPIPE) {
494                                 _E("pid:%d, fd:%d\n", pid, fd);
495                         }
496                         close(fd);
497                         if (pkt) {
498                                 free(pkt);
499                                 pkt = NULL;
500                         }
501                         return -ECOMM;
502                 }
503         }
504         if (pkt) {
505                 free(pkt);
506                 pkt = NULL;
507         }
508
509         return fd;
510 }
511
512 app_pkt_t *__app_recv_raw(int fd, int *clifd, struct ucred *cr)
513 {
514         int len;
515         int ret;
516         struct sockaddr_un aul_addr = { 0, };
517         int sun_size;
518         app_pkt_t *pkt = NULL;
519         int pkt_header_size = offsetof(app_pkt_t, data);
520         int cl = sizeof(struct ucred);
521
522         sun_size = sizeof(struct sockaddr_un);
523
524         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
525                              (socklen_t *) &sun_size)) == -1) {
526                 if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
527                         _E("accept error: %d", errno);
528                 return NULL;
529         }
530
531         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
532                        (socklen_t *) &cl) < 0) {
533                 _E("peer information error");
534                 close(*clifd);
535                 *clifd = -1;
536                 return NULL;
537         }
538
539         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
540         if(pkt == NULL) {
541                 close(*clifd);
542                 *clifd = -1;
543                 return NULL;
544         }
545         memset(pkt, 0, AUL_SOCK_MAXBUFF);
546
547         __set_sock_option(*clifd, 1);
548
549  retry_recv:
550         /* receive single packet from socket */
551         len = recv(*clifd, pkt, AUL_SOCK_MAXBUFF, 0);
552         if (len < 0) {
553                 _E("recv error: %d", errno);
554                 if (errno == EINTR)
555                         goto retry_recv;
556         }
557
558         if (len < pkt_header_size) {
559                 _E("recv error %d %d", len, pkt->len);
560                 free(pkt);
561                 close(*clifd);
562                 *clifd = -1;
563                 return NULL;
564         }
565
566         if (pkt->len < 0 || pkt->len > (AUL_SOCK_MAXBUFF - pkt_header_size)) {
567                 _E("package length error (%d)", pkt->len);
568                 free(pkt);
569                 close(*clifd);
570                 *clifd = -1;
571                 return NULL;
572         }
573
574         while (len < (pkt->len + pkt_header_size)) {
575                 ret = recv(*clifd, &pkt->data[len - pkt_header_size],
576                         (pkt->len + pkt_header_size) - len, 0);
577                 if (ret < 0) {
578                         _E("recv error: %d %d %d", errno, len, pkt->len);
579                         free(pkt);
580                         close(*clifd);
581                         *clifd = -1;
582                         return NULL;
583                 }
584                 len += ret;
585                 _D("recv len %d %d", len, pkt->len);
586         }
587
588         return pkt;
589 }
590
591 app_pkt_t *__app_send_cmd_with_result(int pid, int cmd, unsigned char *kb_data, int datalen)
592 {
593         int fd;
594         int len;
595         app_pkt_t *pkt = NULL;
596
597         fd = __create_client_sock(pid);
598         if (fd < 0)
599                 return NULL;
600
601         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
602         if (NULL == pkt) {
603                 _E("Malloc Failed!");
604                 return NULL;
605         }
606         memset(pkt, 0, AUL_SOCK_MAXBUFF);
607
608         pkt->cmd = cmd;
609         pkt->len = datalen;
610         if(kb_data) {
611                 memcpy(pkt->data, kb_data, datalen);
612         }
613
614         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
615                 _E("send() failed: %d len: %d", errno, len);
616                 if (errno == EPIPE) {
617                         _E("pid:%d, fd:%d\n", pid, fd);
618                 }
619                 close(fd);
620
621                 free(pkt);
622                 return NULL;
623         }
624
625 retry_recv:
626        /* receive single packet from socket */
627         len = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
628         if (len == -1) {
629                 if (errno == EAGAIN) {
630                         _E("recv timeout \n");
631                         free(pkt);
632                         close(fd);
633                         return NULL;
634                 } else if (errno == EINTR) {
635                         goto retry_recv;
636                 } else {
637                         _E("recv error %d %s", errno, strerror(errno));
638                         free(pkt);
639                         close(fd);
640                         return NULL;
641                 }
642         } else
643                 _D("recv result  = %d", len);
644         close(fd);
645
646         return pkt;
647 }
648
649