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