Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_con / ecore_con_local.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <time.h>
9 #include <fcntl.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 #ifdef HAVE_ERRNO_H
14 # include <errno.h>
15 #endif
16
17 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
19 #endif
20
21 #ifdef HAVE_SYS_UN_H
22 # include <sys/un.h>
23 #endif
24
25 #ifdef HAVE_WS2TCPIP_H
26 # include <ws2tcpip.h>
27 #endif
28
29 #include <Ecore.h>
30 #include <ecore_private.h>
31
32 #include "Ecore_Con.h"
33 #include "ecore_con_private.h"
34
35 #define LENGTH_OF_SOCKADDR_UN(s)                (strlen((s)->sun_path) +                 \
36                                                  (size_t)(((struct sockaddr_un *)NULL)-> \
37                                                           sun_path))
38 #define LENGTH_OF_ABSTRACT_SOCKADDR_UN(s, path) (strlen(path) + 1 +            \
39                                                  (size_t)(((struct sockaddr_un \
40                                                             *)NULL)->sun_path))
41
42 static int _ecore_con_local_init_count = 0;
43
44 int
45 ecore_con_local_init(void)
46 {
47    if (++_ecore_con_local_init_count != 1)
48      return _ecore_con_local_init_count;
49
50    return _ecore_con_local_init_count;
51 }
52
53 int
54 ecore_con_local_shutdown(void)
55 {
56    if (--_ecore_con_local_init_count != 0)
57      return _ecore_con_local_init_count;
58
59    return _ecore_con_local_init_count;
60 }
61
62 int
63 ecore_con_local_connect(Ecore_Con_Server *svr,
64                         Eina_Bool (*cb_done)(void *data, Ecore_Fd_Handler *fd_handler),
65                         void *data __UNUSED__)
66 {
67 #ifndef HAVE_LOCAL_SOCKETS
68    return 0;
69 #else
70    char buf[4096];
71    struct sockaddr_un socket_unix;
72    int curstate = 0;
73    const char *homedir;
74    int socket_unix_len;
75
76    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
77      {
78         homedir = getenv("HOME");
79         if (!homedir)
80           homedir = getenv("TMP");
81
82         if (!homedir)
83           homedir = "/tmp";
84
85         snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name,
86                  svr->port);
87      }
88    else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
89      {
90         if (svr->port < 0)
91           {
92              if (svr->name[0] == '/')
93                strncpy(buf, svr->name, sizeof(buf));
94              else
95                snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", svr->name);
96           }
97         else
98           {
99              if (svr->name[0] ==
100                  '/')
101                snprintf(buf, sizeof(buf), "%s|%i", svr->name,
102                         svr->port);
103              else
104                snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i",
105                         svr->name,
106                         svr->port);
107           }
108      }
109    else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
110      strncpy(buf, svr->name,
111              sizeof(buf));
112
113    svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
114    if (svr->fd < 0)
115      return 0;
116
117    if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
118      return 0;
119
120    if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
121      return 0;
122
123    if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate,
124                   sizeof(curstate)) < 0)
125      return 0;
126
127    socket_unix.sun_family = AF_UNIX;
128
129    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
130      {
131 #ifdef HAVE_ABSTRACT_SOCKETS
132         /* copy name insto sun_path, prefixed by null to indicate abstract namespace */
133         snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s",
134                  svr->name);
135         socket_unix.sun_path[0] = '\0';
136         socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix,
137                                                          svr->name);
138 #else
139         WRN("Your system does not support abstract sockets!");
140         return 0;
141 #endif
142      }
143    else
144      {
145         strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
146         socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
147      }
148
149    if (connect(svr->fd, (struct sockaddr *)&socket_unix,
150                socket_unix_len) < 0)
151      {
152         ERR("local connection failed: %s", strerror(errno));
153         return 0;
154      }
155
156    svr->path = strdup(buf);
157    if (!svr->path)
158      return 0;
159
160    if (svr->type & ECORE_CON_SSL)
161      ecore_con_ssl_server_init(svr);
162
163    svr->fd_handler =
164      ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
165                                cb_done, svr, NULL, NULL);
166    if (!svr->fd_handler)
167      return 0;
168
169    if (!svr->delete_me) ecore_con_event_server_add(svr);
170
171    return 1;
172 #endif
173 }
174
175 int
176 ecore_con_local_listen(
177   Ecore_Con_Server *svr,
178   Eina_Bool         (*
179                      cb_listen)(void *data,
180                                 Ecore_Fd_Handler *
181                                 fd_handler),
182   void *data
183   __UNUSED__)
184 {
185 #ifdef HAVE_LOCAL_SOCKETS
186    char buf[4096];
187    struct sockaddr_un socket_unix;
188    struct linger lin;
189    mode_t pmode;
190    const char *homedir;
191    struct stat st;
192    mode_t mask;
193    int socket_unix_len;
194
195    mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
196
197    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
198      {
199         homedir = getenv("HOME");
200         if (!homedir)
201           homedir = getenv("TMP");
202
203         if (!homedir)
204           homedir = "/tmp";
205
206         mask = S_IRUSR | S_IWUSR | S_IXUSR;
207         snprintf(buf, sizeof(buf), "%s/.ecore", homedir);
208         if (stat(buf, &st) < 0)
209           mkdir(buf, mask);
210
211         snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, svr->name);
212         if (stat(buf, &st) < 0)
213           mkdir(buf, mask);
214
215         snprintf(buf,
216                  sizeof(buf),
217                  "%s/.ecore/%s/%i",
218                  homedir,
219                  svr->name,
220                  svr->port);
221         mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
222      }
223    else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
224      {
225         mask = 0;
226         if (svr->name[0] == '/')
227           {
228              if (svr->port >= 0)
229                snprintf(buf,
230                         sizeof(buf),
231                         "%s|%i",
232                         svr->name,
233                         svr->port);
234              else
235                snprintf(buf,
236                         sizeof(buf),
237                         "%s",
238                         svr->name);
239           }
240         else
241           snprintf(buf,
242                    sizeof(buf),
243                    "/tmp/.ecore_service|%s|%i",
244                    svr->name,
245                    svr->port);
246      }
247    else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
248      strncpy(buf, svr->name,
249              sizeof(buf));
250
251    pmode = umask(mask);
252 start:
253    svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
254    if (svr->fd < 0)
255      goto error_umask;
256
257    if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
258      goto error_umask;
259
260    if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
261      goto error_umask;
262
263    lin.l_onoff = 1;
264    lin.l_linger = 0;
265    if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
266                   sizeof(struct linger)) < 0)
267      goto error_umask;
268
269    socket_unix.sun_family = AF_UNIX;
270    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
271      {
272 #ifdef HAVE_ABSTRACT_SOCKETS
273         /* . is a placeholder */
274         snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s",
275                  svr->name);
276         /* first char null indicates abstract namespace */
277         socket_unix.sun_path[0] = '\0';
278         socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix,
279                                                          svr->name);
280 #else
281         ERR("Your system does not support abstract sockets!");
282         goto error_umask;
283 #endif
284      }
285    else
286      {
287         strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
288         socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
289      }
290
291    if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
292      {
293         if ((((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) ||
294              ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)) &&
295             (connect(svr->fd, (struct sockaddr *)&socket_unix,
296                      socket_unix_len) < 0) &&
297             (unlink(buf) >= 0))
298           goto start;
299         else
300           goto error_umask;
301      }
302
303    if (listen(svr->fd, 4096) < 0)
304      goto error_umask;
305
306    svr->path = strdup(buf);
307    if (!svr->path)
308      goto error_umask;
309
310    svr->fd_handler =
311      ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
312                                cb_listen, svr, NULL, NULL);
313    umask(pmode);
314    if (!svr->fd_handler)
315      goto error;
316
317    return 1;
318
319 error_umask:
320    umask(pmode);
321 error:
322 #endif /* HAVE_LOCAL_SOCKETS */
323    return 0;
324 }
325