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