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