svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore_con / ecore_con_local.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <time.h>
13 #include <fcntl.h>
14 #include <sys/stat.h>
15
16 #ifdef HAVE_SYS_SOCKET_H
17 # include <sys/socket.h>
18 #endif
19
20 #ifdef HAVE_SYS_UN_H
21 # include <sys/un.h>
22 #endif
23
24 #ifdef HAVE_WS2TCPIP_H
25 # include <ws2tcpip.h>
26 #endif
27
28 #ifdef HAVE_EVIL
29 # include <Evil.h>
30 #endif
31
32 #include <Ecore.h>
33 #include <ecore_private.h>
34
35 #include "Ecore_Con.h"
36 #include "ecore_con_private.h"
37
38
39 #define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
40 #define LENGTH_OF_ABSTRACT_SOCKADDR_UN(s, path) (strlen(path) + 1 + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
41
42
43 static int _ecore_con_local_init_count = 0;
44
45 int
46 ecore_con_local_init(void)
47 {
48    if (++_ecore_con_local_init_count != 1)
49      return _ecore_con_local_init_count;
50
51    return _ecore_con_local_init_count;
52 }
53
54 int
55 ecore_con_local_shutdown(void)
56 {
57    if (--_ecore_con_local_init_count != 0)
58      return _ecore_con_local_init_count;
59
60    return _ecore_con_local_init_count;
61 }
62
63 int
64 ecore_con_local_connect(Ecore_Con_Server *svr,
65                         int (*cb_done)(void *data, Ecore_Fd_Handler *fd_handler),
66                         void *data __UNUSED__,
67                         void (*cb_free)(void *data, void *ev))
68 {
69    char               buf[4096];
70    struct sockaddr_un socket_unix;
71    int                curstate = 0;
72    const char        *homedir;
73    int                socket_unix_len;
74
75    if (svr->type == ECORE_CON_LOCAL_USER)
76      {
77         homedir = getenv("HOME");
78         if (!homedir) homedir = getenv("TMP");
79         if (!homedir) homedir = "/tmp";
80         snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name, svr->port);
81      }
82    else if (svr->type == ECORE_CON_LOCAL_SYSTEM)
83      {
84         if (svr->port < 0)
85           {
86              if (svr->name[0] == '/')
87                strncpy(buf, svr->name, sizeof(buf));
88              else
89                snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", svr->name);
90           }
91         else
92           {
93              if (svr->name[0] == '/')
94                snprintf(buf, sizeof(buf), "%s|%i", svr->name, svr->port);
95              else
96                snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", svr->name, svr->port);
97           }
98      }
99    else if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
100      strncpy(buf, svr->name, sizeof(buf));
101
102    svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
103    if (svr->fd < 0) return 0;
104    if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) return 0;
105    if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) return 0;
106    if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0) return 0;
107    socket_unix.sun_family = AF_UNIX;
108
109    if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
110      {
111 #ifdef HAVE_ABSTRACT_SOCKETS
112         /* copy name insto sun_path, prefixed by null to indicate abstract namespace */
113         snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", svr->name);
114         socket_unix.sun_path[0] = '\0';
115         socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, svr->name);
116 #else
117         WRN("Your system does not support abstract sockets!");
118         return 0;
119 #endif
120      }
121    else
122      {
123         strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
124         socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
125      }
126
127    if (connect(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
128      return 0;
129    svr->path = strdup(buf);
130    if (!svr->path) return 0;
131
132    if (svr->type & ECORE_CON_SSL)
133      ecore_con_ssl_server_init(svr);
134
135    svr->fd_handler =
136      ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
137                                cb_done, svr, NULL, NULL);
138    if (!svr->fd_handler) return 0;
139
140    if (!svr->delete_me)
141      {
142         /* we got our server! */
143         Ecore_Con_Event_Server_Add *e;
144
145         e = calloc(1, sizeof(Ecore_Con_Event_Server_Add));
146         if (e)
147           {
148              svr->event_count++;
149              e->server = svr;
150              ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e,
151                              cb_free, NULL);
152           }
153      }
154
155    return 1;
156 }
157
158 int
159 ecore_con_local_listen(Ecore_Con_Server *svr,
160                        int (*cb_listen)(void *data, Ecore_Fd_Handler *fd_handler),
161                        void *data __UNUSED__)
162 {
163    char               buf[4096];
164    struct sockaddr_un socket_unix;
165    struct linger      lin;
166    mode_t             pmode;
167    const char        *homedir;
168    struct stat        st;
169    mode_t             mask;
170    int                socket_unix_len;
171
172    mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
173
174    if (svr->type == ECORE_CON_LOCAL_USER)
175      {
176         homedir = getenv("HOME");
177         if (!homedir) homedir = getenv("TMP");
178         if (!homedir) homedir = "/tmp";
179         mask = S_IRUSR | S_IWUSR | S_IXUSR;
180         snprintf(buf, sizeof(buf), "%s/.ecore", homedir);
181         if (stat(buf, &st) < 0) mkdir(buf, mask);
182         snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, svr->name);
183         if (stat(buf, &st) < 0) mkdir(buf, mask);
184         snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name, svr->port);
185         mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
186      }
187    else if (svr->type == ECORE_CON_LOCAL_SYSTEM)
188      {
189         mask = 0;
190         if (svr->name[0] == '/')
191           {
192              if (svr->port >= 0)
193                snprintf(buf, sizeof(buf), "%s|%i", svr->name, svr->port);
194              else
195                snprintf(buf, sizeof(buf), "%s", svr->name);
196           }
197         else
198           snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", svr->name, svr->port);
199      }
200    else if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
201      strncpy(buf, svr->name, sizeof(buf));
202    pmode = umask(mask);
203  start:
204    svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
205    if (svr->fd < 0) goto error_umask;
206    if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error_umask;
207    if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error_umask;
208    lin.l_onoff = 1;
209    lin.l_linger = 0;
210    if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, sizeof(struct linger)) < 0) goto error_umask;
211    socket_unix.sun_family = AF_UNIX;
212    if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
213      {
214 #ifdef HAVE_ABSTRACT_SOCKETS
215         /* . is a placeholder */
216         snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", svr->name);
217         /* first char null indicates abstract namespace */
218         socket_unix.sun_path[0] = '\0';
219         socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, svr->name);
220 #else
221         ERR("Your system does not support abstract sockets!");
222         goto error_umask;
223 #endif
224      }
225    else
226      {
227         strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
228         socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
229      }
230    if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
231      {
232         if (((svr->type == ECORE_CON_LOCAL_USER) || (svr->type == ECORE_CON_LOCAL_SYSTEM)) &&
233             (connect(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) &&
234             (unlink(buf) >= 0))
235           goto start;
236         else
237           goto error_umask;
238      }
239    if (listen(svr->fd, 4096) < 0) goto error_umask;
240    svr->path = strdup(buf);
241    if (!svr->path) goto error_umask;
242    svr->fd_handler =
243      ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
244                                cb_listen, svr, NULL, NULL);
245    umask(pmode);
246    if (!svr->fd_handler) goto error;
247
248    return 1;
249
250    error_umask:
251    umask(pmode);
252    error:
253    return 0;
254 }