Git init
[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         struct timeval tv = { 1, 200 * 1000 };  /*  1.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         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         bzero(&saddr, 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((fsetxattr(fd, "security.SMACK64IPOUT", "@", 2, 0)) < 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                                 return -1;
91                         }
92                 }
93                 if((fsetxattr(fd, "security.SMACK64IPIN", "*", 2, 0)) < 0) {
94                         /* in case of unsupported filesystem on 'socket' */
95                         /* or permission error by using 'emulator', bypass*/
96                         if((errno != EOPNOTSUPP) && (errno != EPERM)) {
97                                 _E("labeling to socket(IPIN) error");
98                                 return -1;
99                         }
100                 }
101         }
102
103         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
104                 _E("bind error");
105                 return -1;
106         }
107
108         if (chmod(saddr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
109                 /* Flawfinder: ignore*/
110                 _E("failed to change the socket permission");
111                 return -1;
112         }
113
114         __set_sock_option(fd, 0);
115
116         if (listen(fd, 10) == -1) {
117                 _E("listen error");
118                 return -1;
119         }
120
121         /* support app launched by shell script */
122         if (pid != LAUNCHPAD_PID) {
123                 int pgid;
124                 pgid = getpgid(pid);
125                 if (pgid > 1) {
126                         snprintf(p_saddr.sun_path, UNIX_PATH_MAX, "%s/%d",
127                                  AUL_SOCK_PREFIX, pgid);
128                         if (link(saddr.sun_path, p_saddr.sun_path) < 0) {
129                                 if (errno == EEXIST)
130                                         _D("pg path - already exists");
131                                 else
132                                         _E("pg path - unknown create error");
133                         }
134                 }
135         }
136
137         return fd;
138 }
139
140 int __create_client_sock(int pid)
141 {
142         int fd = -1;
143         struct sockaddr_un saddr = { 0, };
144         int retry = 1;
145         int ret = -1;
146
147         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);    
148         /*  support above version 2.6.27*/
149         if (fd < 0) {
150                 if (errno == EINVAL) {
151                         fd = socket(AF_UNIX, SOCK_STREAM, 0);
152                         if (fd < 0) {
153                                 _E("second chance - socket create error");
154                                 return -1;
155                         }
156                 } else {
157                         _E("socket error");
158                         return -1;
159                 }
160         }
161
162         saddr.sun_family = AF_UNIX;
163         snprintf(saddr.sun_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, pid);
164  retry_con:
165         ret = __connect_client_sock(fd, (struct sockaddr *)&saddr, sizeof(saddr),
166                         100 * 1000);
167         if (ret < -1) {
168                 _E("maybe peer not launched or peer daed\n");
169                 if (retry > 0) {
170                         usleep(100 * 1000);
171                         retry--;
172                         goto retry_con;
173                 }
174         }
175         if (ret < 0) {
176                 close(fd);
177                 return -1;
178         }
179
180         __set_sock_option(fd, 1);
181
182         return fd;
183 }
184
185 static int __connect_client_sock(int fd, const struct sockaddr *saptr, socklen_t salen,
186                    int nsec)
187 {
188         int flags;
189         int ret;
190         int error;
191         socklen_t len;
192         fd_set readfds;
193         fd_set writefds;
194         struct timeval timeout;
195
196         flags = fcntl(fd, F_GETFL, 0);
197         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
198
199         error = 0;
200         if ((ret = connect(fd, (struct sockaddr *)saptr, salen)) < 0) {
201                 if (errno != EAGAIN && errno != EINPROGRESS) {
202                         fcntl(fd, F_SETFL, flags);      
203                         return (-2);
204                 }
205         }
206
207         /* Do whatever we want while the connect is taking place. */
208         if (ret == 0)
209                 goto done;      /* connect completed immediately */
210
211         FD_ZERO(&readfds);
212         FD_SET(fd, &readfds);
213         writefds = readfds;
214         timeout.tv_sec = 0;
215         timeout.tv_usec = nsec;
216
217         if ((ret = select(fd + 1, &readfds, &writefds, NULL, 
218                         nsec ? &timeout : NULL)) == 0) {
219                 close(fd);      /* timeout */
220                 errno = ETIMEDOUT;
221                 return (-1);
222         }
223
224         if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
225                 len = sizeof(error);
226                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
227                         return (-1);    /* Solaris pending error */
228         } else
229                 return (-1);    /* select error: sockfd not set*/
230
231  done:
232         fcntl(fd, F_SETFL, flags);      
233         if (error) {
234                 close(fd);      
235                 errno = error;
236                 return (-1);
237         }
238         return (0);
239 }
240
241 /**
242  * @brief       Send data (in raw) to the process with 'pid' via socket
243  */
244 int __app_send_raw(int pid, int cmd, unsigned char *kb_data, int datalen)
245 {
246         int fd;
247         int len;
248         int res = 0;
249         app_pkt_t *pkt = NULL;
250
251         if (kb_data == NULL || datalen > AUL_SOCK_MAXBUFF - 8) {
252                 _E("keybundle error\n");
253                 return -EINVAL;
254         }
255
256         fd = __create_client_sock(pid);
257         if (fd < 0)
258                 return -ECOMM;
259
260         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
261         if (NULL == pkt) {
262                 _E("Malloc Failed!");
263                 return -ENOMEM;
264         }
265         memset(pkt, 0, AUL_SOCK_MAXBUFF);
266
267         pkt->cmd = cmd;
268         pkt->len = datalen;
269         memcpy(pkt->data, kb_data, datalen);
270
271         if ((len = send(fd, pkt, datalen + 8, 0)) != datalen + 8) {
272                 _E("sendto() failed - %d %d", len, datalen + 8);
273                 if (errno == EPIPE) {
274                         _E("pid:%d, fd:%d\n", pid, fd);
275                 }
276                 close(fd);
277                 if (pkt) {
278                         free(pkt);
279                         pkt = NULL;
280                 }
281                 return -ECOMM;
282         }
283         if (pkt) {
284                 free(pkt);
285                 pkt = NULL;
286         }
287
288         len = recv(fd, &res, sizeof(int), 0);
289         if (len == -1) {
290                 if (errno == EAGAIN) {
291                         _E("recv timeout \n");
292                         res = -EAGAIN;
293                 } else {
294                         _E("recv error\n");
295                         res = -ECOMM;
296                 }
297         } else
298                 _D("recv result  = %d (%d)", res, len);
299         close(fd);
300
301         return res;
302 }
303
304 app_pkt_t *__app_recv_raw(int fd, int *clifd, struct ucred *cr)
305 {
306         int len;
307         struct sockaddr_un aul_addr = { 0, };
308         int sun_size;
309         app_pkt_t *pkt = NULL;
310         int cl = sizeof(struct ucred);
311
312         sun_size = sizeof(struct sockaddr_un);
313
314         if ((*clifd = accept(fd, (struct sockaddr *)&aul_addr,
315                              (socklen_t *) &sun_size)) == -1) {
316                 if (errno != EINTR)
317                         _E("accept error");
318                 return NULL;
319         }
320
321         if (getsockopt(*clifd, SOL_SOCKET, SO_PEERCRED, cr,
322                        (socklen_t *) &cl) < 0) {
323                 _E("peer information error");
324                 close(*clifd);
325                 return NULL;
326         }
327
328         pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
329         if(pkt == NULL) {
330                 close(*clifd);
331                 return NULL;
332         }
333         memset(pkt, 0, AUL_SOCK_MAXBUFF);
334
335         __set_sock_option(*clifd, 1);
336
337  retry_recv:
338         /* receive single packet from socket */
339         len = recv(*clifd, pkt, AUL_SOCK_MAXBUFF, 0);
340         if (len < 0)
341                 if (errno == EINTR)
342                         goto retry_recv;
343
344         if ((len < 8) || (len != (pkt->len + 8))) {
345                 _E("recv error %d %d", len, pkt->len);
346                 free(pkt);
347                 close(*clifd);
348                 return NULL;
349         }
350
351         return pkt;
352 }
353