diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore_con/ecore_con_local.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_con/ecore_con_local.c b/libraries/ecore/src/lib/ecore_con/ecore_con_local.c new file mode 100644 index 0000000..f02cc1f --- /dev/null +++ b/libraries/ecore/src/lib/ecore_con/ecore_con_local.c | |||
@@ -0,0 +1,317 @@ | |||
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, Ecore_Fd_Handler *fd_handler), | ||
60 | void *data __UNUSED__) | ||
61 | { | ||
62 | #ifndef HAVE_LOCAL_SOCKETS | ||
63 | return 0; | ||
64 | #else | ||
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) ecore_con_event_server_add(svr); | ||
162 | |||
163 | return 1; | ||
164 | #endif | ||
165 | } | ||
166 | |||
167 | int | ||
168 | ecore_con_local_listen( | ||
169 | Ecore_Con_Server *svr, | ||
170 | Eina_Bool (* | ||
171 | cb_listen)(void *data, | ||
172 | Ecore_Fd_Handler * | ||
173 | fd_handler), | ||
174 | void *data | ||
175 | __UNUSED__) | ||
176 | { | ||
177 | #ifdef HAVE_LOCAL_SOCKETS | ||
178 | char buf[4096]; | ||
179 | struct sockaddr_un socket_unix; | ||
180 | struct linger lin; | ||
181 | mode_t pmode; | ||
182 | const char *homedir; | ||
183 | struct stat st; | ||
184 | mode_t mask; | ||
185 | int socket_unix_len; | ||
186 | |||
187 | mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; | ||
188 | |||
189 | if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) | ||
190 | { | ||
191 | homedir = getenv("HOME"); | ||
192 | if (!homedir) | ||
193 | homedir = getenv("TMP"); | ||
194 | |||
195 | if (!homedir) | ||
196 | homedir = "/tmp"; | ||
197 | |||
198 | mask = S_IRUSR | S_IWUSR | S_IXUSR; | ||
199 | snprintf(buf, sizeof(buf), "%s/.ecore", homedir); | ||
200 | if (stat(buf, &st) < 0) | ||
201 | mkdir(buf, mask); | ||
202 | |||
203 | snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, svr->name); | ||
204 | if (stat(buf, &st) < 0) | ||
205 | mkdir(buf, mask); | ||
206 | |||
207 | snprintf(buf, | ||
208 | sizeof(buf), | ||
209 | "%s/.ecore/%s/%i", | ||
210 | homedir, | ||
211 | svr->name, | ||
212 | svr->port); | ||
213 | mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; | ||
214 | } | ||
215 | else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) | ||
216 | { | ||
217 | mask = 0; | ||
218 | if (svr->name[0] == '/') | ||
219 | { | ||
220 | if (svr->port >= 0) | ||
221 | snprintf(buf, | ||
222 | sizeof(buf), | ||
223 | "%s|%i", | ||
224 | svr->name, | ||
225 | svr->port); | ||
226 | else | ||
227 | snprintf(buf, | ||
228 | sizeof(buf), | ||
229 | "%s", | ||
230 | svr->name); | ||
231 | } | ||
232 | else | ||
233 | snprintf(buf, | ||
234 | sizeof(buf), | ||
235 | "/tmp/.ecore_service|%s|%i", | ||
236 | svr->name, | ||
237 | svr->port); | ||
238 | } | ||
239 | else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) | ||
240 | strncpy(buf, svr->name, | ||
241 | sizeof(buf)); | ||
242 | |||
243 | pmode = umask(mask); | ||
244 | start: | ||
245 | svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); | ||
246 | if (svr->fd < 0) | ||
247 | goto error_umask; | ||
248 | |||
249 | if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) | ||
250 | goto error_umask; | ||
251 | |||
252 | if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) | ||
253 | goto error_umask; | ||
254 | |||
255 | lin.l_onoff = 1; | ||
256 | lin.l_linger = 0; | ||
257 | if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, | ||
258 | sizeof(struct linger)) < 0) | ||
259 | goto error_umask; | ||
260 | |||
261 | socket_unix.sun_family = AF_UNIX; | ||
262 | if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) | ||
263 | { | ||
264 | #ifdef HAVE_ABSTRACT_SOCKETS | ||
265 | /* . is a placeholder */ | ||
266 | snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", | ||
267 | svr->name); | ||
268 | /* first char null indicates abstract namespace */ | ||
269 | socket_unix.sun_path[0] = '\0'; | ||
270 | socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, | ||
271 | svr->name); | ||
272 | #else | ||
273 | ERR("Your system does not support abstract sockets!"); | ||
274 | goto error_umask; | ||
275 | #endif | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path)); | ||
280 | socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); | ||
281 | } | ||
282 | |||
283 | if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) | ||
284 | { | ||
285 | if ((((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) || | ||
286 | ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)) && | ||
287 | (connect(svr->fd, (struct sockaddr *)&socket_unix, | ||
288 | socket_unix_len) < 0) && | ||
289 | (unlink(buf) >= 0)) | ||
290 | goto start; | ||
291 | else | ||
292 | goto error_umask; | ||
293 | } | ||
294 | |||
295 | if (listen(svr->fd, 4096) < 0) | ||
296 | goto error_umask; | ||
297 | |||
298 | svr->path = strdup(buf); | ||
299 | if (!svr->path) | ||
300 | goto error_umask; | ||
301 | |||
302 | svr->fd_handler = | ||
303 | ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, | ||
304 | cb_listen, svr, NULL, NULL); | ||
305 | umask(pmode); | ||
306 | if (!svr->fd_handler) | ||
307 | goto error; | ||
308 | |||
309 | return 1; | ||
310 | |||
311 | error_umask: | ||
312 | umask(pmode); | ||
313 | error: | ||
314 | #endif /* HAVE_LOCAL_SOCKETS */ | ||
315 | return 0; | ||
316 | } | ||
317 | |||