4a8011eb7333fce329241174ac09f5e214d2e58a
[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/xattr.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 #ifdef __i386__
43         struct timeval tv = { 5, 200 * 1000 };  /*  5.2 sec */
44         _D("time out : 5.2 sec");
45 #else
46         struct timeval tv = { 1, 200 * 1000 };  /*  1.2 sec */
47         _D("time out : 1.2 sec");
48 #endif
49
50         size = AUL_SOCK_MAXBUFF;
51         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
52         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
53         if (cli)
54                 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
55 }
56
57 int __create_server_sock(int pid)
58 {
59         struct sockaddr_un saddr;
60         struct sockaddr_un p_saddr;
61         int fd;
62         mode_t orig_mask;
63
64         /* Create basedir for our sockets */
65         orig_mask = umask(0);
66         mkdir(AUL_SOCK_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
67         umask(orig_mask);
68
69         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
70         /*  support above version 2.6.27*/
71         if (fd < 0) {
72                 if (errno == EINVAL) {
73                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
74                         if (fd < 0) {
75                                 _E("second chance - socket create error");
76                                 return -1;
77                         }
78                 } else {
79                         _E("socket error");
80                         return -1;
81                 }
82         }
83
84         bzero(&saddr, sizeof(saddr));
85         saddr.sun_family = AF_UNIX;
86         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, pid);
87         unlink(saddr.sun_path);
88
89         /* labeling to socket for SMACK */
90         if(getuid() == 0) {     // this is meaningful iff current user is ROOT
91                 if((fsetxattr(fd, "security.SMACK64IPOUT", "@", 2, 0)) < 0) {
92                         /* in case of unsupported filesystem on 'socket' */
93                         /* or permission error by using 'emulator', bypass*/
94                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
95                                 _E("labeling to socket(IPOUT) error");
96                                 return -1;
97                         }
98                 }
99                 if((fsetxattr(fd, "security.SMACK64IPIN", "*", 2, 0)) < 0) {
100                         /* in case of unsupported filesystem on 'socket' */
101                         /* or permission error by using 'emulator', bypass*/
102                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
103                                 _E("labeling to socket(IPIN) error");
104                                 return -1;
105                         }
106                 }
107         }
108
109         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
110                 _E("bind error");
111                 return -1;
112         }
113
114         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
115                 /* Flawfinder: ignore*/
116                 _E("failed to change the socket permission");
117                 return -1;
118         }
119
120         __set_sock_option(fd, 0);
121
122         if (listen(fd, 10) == -1) {
123                 _E("listen error");
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 = 1;
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");
160                                 return -1;
161                         }
162                 } else {
163                         _E("socket error");
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("maybe peer not launched or peer daed\n");
175                 if (retry > 0) {
176                         usleep(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                         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                 close(fd);      /* timeout */
226                 errno = ETIMEDOUT;
227                 return (-1);
228         }
229
230         if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
231                 len = sizeof(error);
232                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
233                         return (-1);    /* Solaris pending error */
234         } else
235                 return (-1);    /* select error: sockfd not set*/
236
237  done:
238         fcntl(fd, F_SETFL, flags);      
239         if (error) {
240                 close(fd);      
241                 errno = error;
242                 return (-1);
243         }
244         return (0);
245 }
246
247 /**
248  * @brief       Send data (in raw) to the process with 'pid' via socket
249  */
250 int __app_send_raw(int pid, int cmd, unsigned char *kb_data, int datalen)
251 {
252         int fd;
253         int len;
254         int res = 0;
255         app_pkt_t *pkt = NULL;
256
257         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
258                 _E("keybundle error\n");
259                 return -EINVAL;
260         }
261
262         fd = __create_client_sock(pid);
263         if (fd < 0)
264                 return -ECOMM;
265
266         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
267         if (NULL == pkt) {
268                 _E("Malloc Failed!");
269                 return -ENOMEM;
270         }
271         memset(pkt, 0, AUL_SOCK_MAXBUFF);
272
273         pkt->cmd = cmd;
274         pkt->len = datalen;
275         memcpy(pkt->data, kb_data, datalen);
276
277         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
278                 _E("sendto() failed - %d %d", len, datalen + 8);
279                 if (errno == EPIPE) {
280                         _E("pid:%d, fd:%d\n", pid, fd);
281                 }
282                 close(fd);
283                 if (pkt) {
284                         free(pkt);
285                         pkt = NULL;
286                 }
287                 return -ECOMM;
288         }
289         if (pkt) {
290                 free(pkt);
291                 pkt = NULL;
292         }
293
294         len = recv(fd, &res, sizeof(int), 0);
295         if (len == -1) {
296                 if (errno == EAGAIN) {
297                         _E("recv timeout \n");
298                         res = -EAGAIN;
299                 } else {
300                         _E("recv error\n");
301                         res = -ECOMM;
302                 }
303         } else
304                 _D("recv result  = %d (%d)", res, len);
305         close(fd);
306
307         return res;
308 }
309
310 app_pkt_t *__app_recv_raw(int fd, int *clifd, struct ucred *cr)
311 {
312         int len;
313         struct sockaddr_un aul_addr = { 0, };
314         int sun_size;
315         app_pkt_t *pkt = NULL;
316         int cl = sizeof(struct ucred);
317
318         sun_size = sizeof(struct sockaddr_un);
319
320         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
321                              (socklen_t *) &sun_size)) == -1) {
322                 if (errno != EINTR)
323                         _E("accept error");
324                 return NULL;
325         }
326
327         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
328                        (socklen_t *) &cl) < 0) {
329                 _E("peer information error");
330                 close(*clifd);
331                 return NULL;
332         }
333
334         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
335         if(pkt == NULL) {
336                 close(*clifd);
337                 return NULL;
338         }
339         memset(pkt, 0, AUL_SOCK_MAXBUFF);
340
341         __set_sock_option(*clifd, 1);
342
343  retry_recv:
344         /* receive single packet from socket */
345         len = recv(*clifd, pkt, AUL_SOCK_MAXBUFF, 0);
346         if (len < 0)
347                 if (errno == EINTR)
348                         goto retry_recv;
349
350         if ((len < 8) || (len != (pkt->len + 8))) {
351                 _E("recv error %d %d", len, pkt->len);
352                 free(pkt);
353                 close(*clifd);
354                 return NULL;
355         }
356
357         return pkt;
358 }
359
360 app_pkt_t *__app_send_cmd_with_result(int pid, int cmd)
361 {
362         int fd;
363         int len;
364         app_pkt_t *pkt = NULL;
365
366         fd = __create_client_sock(pid);
367         if (fd < 0)
368                 return NULL;
369
370         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
371         if (NULL == pkt) {
372                 _E("Malloc Failed!");
373                 return NULL;
374         }
375         memset(pkt, 0, AUL_SOCK_MAXBUFF);
376
377         pkt->cmd = cmd;
378         pkt->len = 0;
379
380         if ((len = send(fd, pkt, 8, 0)) != 8) {
381                 _E("sendto() failed - %d", len);
382                 if (errno == EPIPE) {
383                         _E("pid:%d, fd:%d\n", pid, fd);
384                 }
385                 close(fd);
386
387                 free(pkt);
388                 return NULL;
389         }
390
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 {
398                         _E("recv error\n");
399                         free(pkt);
400                         return NULL;
401                 }
402         } else
403                 _D("recv result  = %d", len);
404         close(fd);
405
406         return pkt;
407 }
408
409