Tizen 2.0 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 = { 3, 200 * 1000 };  /*  3.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");
70                                 return -1;
71                         }
72                 } else {
73                         _E("socket error");
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");
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, 10) == -1) {
121                 _E("listen error");
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 = 1;
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");
159                                 return -1;
160                         }
161                 } else {
162                         _E("socket error");
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("maybe peer not launched or peer daed\n");
174                 if (retry > 0) {
175                         usleep(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                         fcntl(fd, F_SETFL, flags);      
208                         return (-2);
209                 }
210         }
211
212         /* Do whatever we want while the connect is taking place. */
213         if (ret == 0)
214                 goto done;      /* connect completed immediately */
215
216         FD_ZERO(&readfds);
217         FD_SET(fd, &readfds);
218         writefds = readfds;
219         timeout.tv_sec = 0;
220         timeout.tv_usec = nsec;
221
222         if ((ret = select(fd + 1, &readfds, &writefds, NULL, 
223                         nsec ? &timeout : NULL)) == 0) {
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         } else
234                 return (-1);    /* select error: sockfd not set*/
235
236  done:
237         (void) fcntl(fd, F_SETFL, flags);
238         if (error) {
239                 close(fd);
240                 errno = error;
241                 return (-1);
242         }
243         return (0);
244 }
245
246 /**
247  * @brief       Send data (in raw) to the process with 'pid' via socket
248  */
249 int __app_send_raw(int pid, int cmd, unsigned char *kb_data, int datalen)
250 {
251         int fd;
252         int len;
253         int res = 0;
254         app_pkt_t *pkt = NULL;
255
256         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
257                 _E("keybundle error\n");
258                 return -EINVAL;
259         }
260
261         fd = __create_client_sock(pid);
262         if (fd < 0)
263                 return -ECOMM;
264
265         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
266         if (NULL == pkt) {
267                 _E("Malloc Failed!");
268                 return -ENOMEM;
269         }
270         memset(pkt, 0, AUL_SOCK_MAXBUFF);
271
272         pkt->cmd = cmd;
273         pkt->len = datalen;
274         memcpy(pkt->data, kb_data, datalen);
275
276         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
277                 _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno);
278                 if (errno == EPIPE) {
279                         _E("pid:%d, fd:%d\n", pid, fd);
280                 }
281                 close(fd);
282                 if (pkt) {
283                         free(pkt);
284                         pkt = NULL;
285                 }
286                 return -ECOMM;
287         }
288         if (pkt) {
289                 free(pkt);
290                 pkt = NULL;
291         }
292
293         len = recv(fd, &res, sizeof(int), 0);
294         if (len == -1) {
295                 if (errno == EAGAIN) {
296                         _E("recv timeout \n");
297                         res = -EAGAIN;
298                 } else {
299                         _E("recv error\n");
300                         res = -ECOMM;
301                 }
302         }
303         close(fd);
304
305         return res;
306 }
307
308 app_pkt_t *__app_recv_raw(int fd, int *clifd, struct ucred *cr)
309 {
310         int len;
311         struct sockaddr_un aul_addr = { 0, };
312         int sun_size;
313         app_pkt_t *pkt = NULL;
314         int cl = sizeof(struct ucred);
315
316         sun_size = sizeof(struct sockaddr_un);
317
318         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
319                              (socklen_t *) &sun_size)) == -1) {
320                 if (errno != EINTR)
321                         _E("accept error");
322                 return NULL;
323         }
324
325         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
326                        (socklen_t *) &cl) < 0) {
327                 _E("peer information error");
328                 close(*clifd);
329                 return NULL;
330         }
331
332         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
333         if(pkt == NULL) {
334                 close(*clifd);
335                 return NULL;
336         }
337         memset(pkt, 0, AUL_SOCK_MAXBUFF);
338
339         __set_sock_option(*clifd, 1);
340
341  retry_recv:
342         /* receive single packet from socket */
343         len = recv(*clifd, pkt, AUL_SOCK_MAXBUFF, 0);
344         if (len < 0)
345                 if (errno == EINTR)
346                         goto retry_recv;
347
348         if ((len < 8) || (len != (pkt->len + 8))) {
349                 _E("recv error %d %d", len, pkt->len);
350                 free(pkt);
351                 close(*clifd);
352                 return NULL;
353         }
354
355         return pkt;
356 }
357
358 app_pkt_t *__app_send_cmd_with_result(int pid, int cmd)
359 {
360         int fd;
361         int len;
362         app_pkt_t *pkt = NULL;
363
364         fd = __create_client_sock(pid);
365         if (fd < 0)
366                 return NULL;
367
368         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
369         if (NULL == pkt) {
370                 _E("Malloc Failed!");
371                 return NULL;
372         }
373         memset(pkt, 0, AUL_SOCK_MAXBUFF);
374
375         pkt->cmd = cmd;
376         pkt->len = 0;
377
378         if ((len = send(fd, pkt, 8, 0)) != 8) {
379                 _E("sendto() failed - %d", len);
380                 if (errno == EPIPE) {
381                         _E("pid:%d, fd:%d\n", pid, fd);
382                 }
383                 close(fd);
384
385                 free(pkt);
386                 return NULL;
387         }
388
389 retry_recv:
390        /* receive single packet from socket */
391         len = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
392         if (len == -1) {
393                 if (errno == EAGAIN) {
394                         _E("recv timeout \n");
395                         free(pkt);
396                         return NULL;
397                 } else if (errno == EINTR) {
398                         goto retry_recv;
399                 } else {
400                         _E("recv error %s\n", strerror(errno));
401                         free(pkt);
402                         return NULL;
403                 }
404         } else
405                 _D("recv result  = %d", len);
406         close(fd);
407
408         return pkt;
409 }
410
411