1 /*
2
3 Copyright (c) 2017 Martin Sustrik
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom
10 the Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 IN THE SOFTWARE.
22
23 */
24
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/un.h>
29 #include <unistd.h>
30
31 #define DILL_DISABLE_RAW_NAMES
32 #include "libdillimpl.h"
33 #include "fd.h"
34 #include "utils.h"
35
36 static int dill_ipc_resolve(const char *addr, struct sockaddr_un *su);
37
38 dill_unique_id(dill_ipc_listener_type);
39 dill_unique_id(dill_ipc_type);
40
41 /******************************************************************************/
42 /* UNIX connection socket */
43 /******************************************************************************/
44
45 static void *dill_ipc_hquery(struct dill_hvfs *hvfs, const void *type);
46 static void dill_ipc_hclose(struct dill_hvfs *hvfs);
47 static int dill_ipc_bsendl(struct dill_bsock_vfs *bvfs,
48 struct dill_iolist *first, struct dill_iolist *last, int64_t deadline);
49 static int dill_ipc_brecvl(struct dill_bsock_vfs *bvfs,
50 struct dill_iolist *first, struct dill_iolist *last, int64_t deadline);
51
52 struct dill_ipc_conn {
53 struct dill_hvfs hvfs;
54 struct dill_bsock_vfs bvfs;
55 int fd;
56 struct dill_fd_rxbuf rxbuf;
57 unsigned int scm_rights : 1;
58 unsigned int rbusy : 1;
59 unsigned int sbusy : 1;
60 unsigned int indone : 1;
61 unsigned int outdone : 1;
62 unsigned int inerr : 1;
63 unsigned int outerr : 1;
64 unsigned int mem : 1;
65 };
66
DILL_CHECK_STORAGE(dill_ipc_conn,dill_ipc_storage)67 DILL_CHECK_STORAGE(dill_ipc_conn, dill_ipc_storage)
68
69 static int dill_ipc_makeconn(int fd, void *mem) {
70 /* Create the object. */
71 struct dill_ipc_conn *self = (struct dill_ipc_conn*)mem;
72 self->hvfs.query = dill_ipc_hquery;
73 self->hvfs.close = dill_ipc_hclose;
74 self->bvfs.bsendl = dill_ipc_bsendl;
75 self->bvfs.brecvl = dill_ipc_brecvl;
76 self->fd = fd;
77 dill_fd_initrxbuf(&self->rxbuf);
78 self->scm_rights = 1;
79 self->rbusy = 0;
80 self->sbusy = 0;
81 self->indone = 0;
82 self->outdone = 0;
83 self->inerr = 0;
84 self->outerr = 0;
85 self->mem = 1;
86 /* Create the handle. */
87 return dill_hmake(&self->hvfs);
88 }
89
dill_ipc_hquery(struct dill_hvfs * hvfs,const void * type)90 static void *dill_ipc_hquery(struct dill_hvfs *hvfs, const void *type) {
91 struct dill_ipc_conn *self = (struct dill_ipc_conn*)hvfs;
92 if(type == dill_bsock_type) return &self->bvfs;
93 if(type == dill_ipc_type) return self;
94 errno = ENOTSUP;
95 return NULL;
96 }
97
dill_ipc_fromfd_mem(int fd,struct dill_ipc_storage * mem)98 int dill_ipc_fromfd_mem(int fd, struct dill_ipc_storage *mem) {
99 int err;
100 if(dill_slow(!mem || fd < 0)) {err = EINVAL; goto error1;}
101 /* Make sure that the supplied file descriptor is of correct type. */
102 int rc = dill_fd_check(fd, SOCK_STREAM, AF_UNIX, -1, 0);
103 if(dill_slow(rc < 0)) {err = errno; goto error1;}
104 /* Take ownership of the file descriptor. */
105 fd = dill_fd_own(fd);
106 if(dill_slow(fd < 0)) {err = errno; goto error1;}
107 /* Set the socket to non-blocking mode */
108 rc = dill_fd_unblock(fd);
109 if(dill_slow(rc < 0)) {err = errno; goto error1;}
110 /* Create the handle */
111 int h = dill_ipc_makeconn(fd, mem);
112 if(dill_slow(h < 0)) {err = errno; goto error1;}
113 /* Return the handle */
114 return h;
115 error1:
116 errno = err;
117 return -1;
118 }
119
dill_ipc_fromfd(int fd)120 int dill_ipc_fromfd(int fd) {
121 int err;
122 struct dill_ipc_conn *obj = malloc(sizeof(struct dill_ipc_conn));
123 if(dill_slow(!obj)) {err = ENOMEM; goto error1;}
124 int s = dill_ipc_fromfd_mem(fd, (struct dill_ipc_storage*)obj);
125 if (dill_slow(s < 0)) {err = errno; goto error2;}
126 obj->mem = 0;
127 return s;
128 error2:
129 free(obj);
130 error1:
131 errno = err;
132 return -1;
133 }
134
dill_ipc_connect_mem(const char * addr,struct dill_ipc_storage * mem,int64_t deadline)135 int dill_ipc_connect_mem(const char *addr, struct dill_ipc_storage *mem,
136 int64_t deadline) {
137 int err;
138 if(dill_slow(!mem)) {err = EINVAL; goto error1;}
139 /* Create a UNIX address out of the address string. */
140 struct sockaddr_un su;
141 int rc = dill_ipc_resolve(addr, &su);
142 if(rc < 0) {err = errno; goto error1;}
143 /* Open a socket. */
144 int s = socket(AF_UNIX, SOCK_STREAM, 0);
145 if(dill_slow(s < 0)) {err = errno; goto error1;}
146 /* Set it to non-blocking mode. */
147 rc = dill_fd_unblock(s);
148 if(dill_slow(rc < 0)) {err = errno; goto error2;}
149 /* Connect to the remote endpoint. */
150 rc = dill_fd_connect(s, (struct sockaddr*)&su, sizeof(su), deadline);
151 if(dill_slow(rc < 0)) {err = errno; goto error2;}
152 /* Create the handle. */
153 int h = dill_ipc_makeconn(s, mem);
154 if(dill_slow(h < 0)) {err = errno; goto error2;}
155 return h;
156 error2:
157 dill_fd_close(s);
158 error1:
159 errno = err;
160 return -1;
161 }
162
dill_ipc_connect(const char * addr,int64_t deadline)163 int dill_ipc_connect(const char *addr, int64_t deadline) {
164 int err;
165 struct dill_ipc_conn *obj = malloc(sizeof(struct dill_ipc_conn));
166 if(dill_slow(!obj)) {err = ENOMEM; goto error1;}
167 int s = dill_ipc_connect_mem(addr, (struct dill_ipc_storage*)obj, deadline);
168 if(dill_slow(s < 0)) {err = errno; goto error2;}
169 obj->mem = 0;
170 return s;
171 error2:
172 free(obj);
173 error1:
174 errno = err;
175 return -1;
176 }
177
dill_ipc_bsendl(struct dill_bsock_vfs * bvfs,struct dill_iolist * first,struct dill_iolist * last,int64_t deadline)178 static int dill_ipc_bsendl(struct dill_bsock_vfs *bvfs,
179 struct dill_iolist *first, struct dill_iolist *last, int64_t deadline) {
180 struct dill_ipc_conn *self = dill_cont(bvfs, struct dill_ipc_conn, bvfs);
181 if(dill_slow(self->sbusy)) {errno = EBUSY; return -1;}
182 if(dill_slow(self->outdone)) {errno = EPIPE; return -1;}
183 if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;}
184 self->sbusy = 1;
185 ssize_t sz = dill_fd_send(self->fd, first, last, deadline);
186 self->sbusy = 0;
187 if(dill_fast(sz >= 0)) return sz;
188 self->outerr = 1;
189 return -1;
190 }
191
dill_ipc_brecvl(struct dill_bsock_vfs * bvfs,struct dill_iolist * first,struct dill_iolist * last,int64_t deadline)192 static int dill_ipc_brecvl(struct dill_bsock_vfs *bvfs,
193 struct dill_iolist *first, struct dill_iolist *last, int64_t deadline) {
194 struct dill_ipc_conn *self = dill_cont(bvfs, struct dill_ipc_conn, bvfs);
195 if(dill_slow(self->rbusy)) {errno = EBUSY; return -1;}
196 if(dill_slow(self->indone)) {errno = EPIPE; return -1;}
197 if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;}
198 self->rbusy = 1;
199 /* If we want to use SCM_RIGHTS we can't do rx buffering. */
200 int rc = dill_fd_recv(self->fd, self->scm_rights ? NULL : &self->rxbuf,
201 first, last, deadline);
202 self->rbusy = 0;
203 if(dill_fast(rc == 0)) return 0;
204 if(errno == EPIPE) self->indone = 1;
205 else self->inerr = 1;
206 return -1;
207 }
208
dill_ipc_sendfd(int s,int fd,int64_t deadline)209 int dill_ipc_sendfd(int s, int fd, int64_t deadline) {
210 struct dill_ipc_conn *self = dill_hquery(s, dill_ipc_type);
211 if(dill_slow(!self)) return -1;
212 if(dill_slow(!self->scm_rights)) {errno = ENOTSUP; return -1;}
213 if(dill_slow(fd < 0)) {errno = EINVAL; return -1;}
214 if(dill_slow(self->sbusy)) {errno = EBUSY; return -1;}
215 if(dill_slow(self->outdone)) {errno = EPIPE; return -1;}
216 if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;}
217 struct iovec iov;
218 unsigned char buf[] = {0xcc};
219 iov.iov_base = buf;
220 iov.iov_len = 1;
221 struct msghdr msg;
222 memset(&msg, 0, sizeof (msg));
223 msg.msg_iov = &iov;
224 msg.msg_iovlen = 1;
225 char control [sizeof(struct cmsghdr) + 10];
226 msg.msg_control = control;
227 msg.msg_controllen = sizeof(control);
228 struct cmsghdr *cmsg;
229 cmsg = CMSG_FIRSTHDR(&msg);
230 cmsg->cmsg_level = SOL_SOCKET;
231 cmsg->cmsg_type = SCM_RIGHTS;
232 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
233 *((int*)CMSG_DATA(cmsg)) = fd;
234 msg.msg_controllen = cmsg->cmsg_len;
235 int rc = dill_fdout(self->fd, deadline);
236 if(dill_slow(rc < 0)) return -1;
237 ssize_t sz = sendmsg(self->fd, &msg, 0);
238 if(dill_slow(sz == 0)) {self->outdone = 1; errno = EPIPE; return -1;}
239 if(dill_slow(sz < 0)) {
240 if(errno == ECONNRESET) {self->outerr = 1; return -1;}
241 dill_assert(0);
242 }
243 return 0;
244 }
245
dill_ipc_recvfd(int s,int64_t deadline)246 int dill_ipc_recvfd(int s, int64_t deadline) {
247 struct dill_ipc_conn *self = dill_hquery(s, dill_ipc_type);
248 if(dill_slow(!self)) return -1;
249 if(dill_slow(!self->scm_rights)) {errno = ENOTSUP; return -1;}
250 if(dill_slow(self->rbusy)) {errno = EBUSY; return -1;}
251 if(dill_slow(self->indone)) {errno = EPIPE; return -1;}
252 if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;}
253 char buf[1];
254 struct iovec iov;
255 iov.iov_base = buf;
256 iov.iov_len = sizeof(buf);
257 struct msghdr msg;
258 memset(&msg, 0, sizeof(msg));
259 msg.msg_iov = &iov;
260 msg.msg_iovlen = 1;
261 unsigned char control[1024];
262 msg.msg_control = control;
263 msg.msg_controllen = sizeof(control);
264 int rc = dill_fdin(self->fd, deadline);
265 if(dill_slow(rc < 0)) return -1;
266 ssize_t sz = recvmsg(self->fd, &msg, 0);
267 if(dill_slow(sz == 0)) {self->indone = 1; errno = EPIPE; return -1;}
268 if(dill_slow(sz < 0)) {
269 if(errno == ECONNRESET) {self->outerr = 1; return -1;}
270 dill_assert(0);
271 }
272 /* Loop over the auxiliary data to find the embedded file descriptor. */
273 int fd = -1;
274 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
275 while(cmsg) {
276 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
277 fd = *(int*)CMSG_DATA(cmsg);
278 break;
279 }
280 cmsg = CMSG_NXTHDR(&msg, cmsg);
281 }
282 if(dill_slow(fd < 0)) {self->inerr = 1; errno = EPROTO; return -1;}
283 return fd;
284 }
285
dill_ipc_done(int s,int64_t deadline)286 int dill_ipc_done(int s, int64_t deadline) {
287 struct dill_ipc_conn *self = dill_hquery(s, dill_ipc_type);
288 if(dill_slow(!self)) return -1;
289 if(dill_slow(self->outdone)) {errno = EPIPE; return -1;}
290 if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;}
291 /* Shutdown is done asynchronously on kernel level.
292 No need to use the deadline. */
293 int rc = shutdown(self->fd, SHUT_WR);
294 if(dill_slow(rc < 0)) {
295 if(errno == ENOTCONN) {self->outerr = 1; errno = ECONNRESET; return -1;}
296 if(errno == ENOBUFS) {self->outerr = 1; errno = ENOMEM; return -1;}
297 dill_assert(0);
298 }
299 self->outdone = 1;
300 return 0;
301 }
302
dill_ipc_close(int s,int64_t deadline)303 int dill_ipc_close(int s, int64_t deadline) {
304 int err;
305 /* Listener socket needs no special treatment. */
306 if(dill_hquery(s, dill_ipc_listener_type)) {
307 return dill_hclose(s);
308 }
309 struct dill_ipc_conn *self = dill_hquery(s, dill_ipc_type);
310 if(dill_slow(!self)) return -1;
311 if(dill_slow(self->inerr || self->outerr)) {err = ECONNRESET; goto error;}
312 /* If not done already, flush the outbound data and start the terminal
313 handshake. */
314 if(!self->outdone) {
315 int rc = dill_ipc_done(s, deadline);
316 if(dill_slow(rc < 0)) {err = errno; goto error;}
317 }
318 /* Now we are going to read all the inbound data until we reach end of the
319 stream. That way we can be sure that the peer either received all our
320 data or consciously closed the connection without reading all of it. */
321 int rc = dill_ipc_brecvl(&self->bvfs, NULL, NULL, deadline);
322 dill_assert(rc < 0);
323 if(dill_slow(errno != EPIPE)) {err = errno; goto error;}
324 dill_ipc_hclose(&self->hvfs);
325 return 0;
326 error:
327 dill_ipc_hclose(&self->hvfs);
328 errno = err;
329 return -1;
330 }
331
dill_ipc_hclose(struct dill_hvfs * hvfs)332 static void dill_ipc_hclose(struct dill_hvfs *hvfs) {
333 struct dill_ipc_conn *self = (struct dill_ipc_conn*)hvfs;
334 dill_fd_close(self->fd);
335 dill_fd_termrxbuf(&self->rxbuf);
336 if(!self->mem) free(self);
337 }
338
339 /******************************************************************************/
340 /* UNIX listener socket */
341 /******************************************************************************/
342
343 static void *dill_ipc_listener_hquery(struct dill_hvfs *hvfs, const void *type);
344 static void dill_ipc_listener_hclose(struct dill_hvfs *hvfs);
345
346 struct dill_ipc_listener {
347 struct dill_hvfs hvfs;
348 int fd;
349 unsigned int mem : 1;
350 };
351
DILL_CHECK_STORAGE(dill_ipc_listener,dill_ipc_listener_storage)352 DILL_CHECK_STORAGE(dill_ipc_listener, dill_ipc_listener_storage)
353
354 static void *dill_ipc_listener_hquery(struct dill_hvfs *hvfs,
355 const void *type) {
356 struct dill_ipc_listener *self = (struct dill_ipc_listener*)hvfs;
357 if(type == dill_ipc_listener_type) return self;
358 errno = ENOTSUP;
359 return NULL;
360 }
361
dill_ipc_makelistener(int fd,struct dill_ipc_listener_storage * mem)362 static int dill_ipc_makelistener(int fd,
363 struct dill_ipc_listener_storage *mem) {
364 /* Create the object. */
365 struct dill_ipc_listener *self = (struct dill_ipc_listener*)mem;
366 self->hvfs.query = dill_ipc_listener_hquery;
367 self->hvfs.close = dill_ipc_listener_hclose;
368 self->fd = fd;
369 self->mem = 1;
370 /* Create the handle. */
371 return dill_hmake(&self->hvfs);
372 }
373
dill_ipc_listener_fromfd(int fd)374 int dill_ipc_listener_fromfd(int fd) {
375 int err;
376 struct dill_ipc_listener *obj = malloc(sizeof(struct dill_ipc_listener));
377 if(dill_slow(!obj)) {err = ENOMEM; goto error1;}
378 int s = dill_ipc_listener_fromfd_mem(fd,
379 (struct dill_ipc_listener_storage*)obj);
380 if (dill_slow(s < 0)) {err = errno; goto error2;}
381 obj->mem = 0;
382 return s;
383 error2:
384 free(obj);
385 error1:
386 errno = err;
387 return -1;
388 }
389
dill_ipc_listener_fromfd_mem(int fd,struct dill_ipc_listener_storage * mem)390 int dill_ipc_listener_fromfd_mem(int fd,
391 struct dill_ipc_listener_storage *mem) {
392 int err;
393 if(dill_slow(!mem || fd < 0)) {err = EINVAL; goto error1;}
394 /* Make sure that the supplied file descriptor is of correct type. */
395 int rc = dill_fd_check(fd, SOCK_STREAM, AF_UNIX, -1, 1);
396 if(dill_slow(rc < 0)) {err = errno; goto error1;}
397 /* Take ownership of the file descriptor. */
398 fd = dill_fd_own(fd);
399 if(dill_slow(fd < 0)) {err = errno; goto error1;}
400 /* Set the socket to non-blocking mode */
401 rc = dill_fd_unblock(fd);
402 if(dill_slow(rc < 0)) {err = errno; goto error1;}
403 /* Create the handle */
404 int h = dill_ipc_makelistener(fd, mem);
405 if(dill_slow(h < 0)) {err = errno; goto error1;}
406 /* Return the handle */
407 return h;
408 error1:
409 errno = err;
410 return -1;
411 }
412
dill_ipc_listen_mem(const char * addr,int backlog,struct dill_ipc_listener_storage * mem)413 int dill_ipc_listen_mem(const char *addr, int backlog,
414 struct dill_ipc_listener_storage *mem) {
415 int err;
416 /* Create a UNIX address out of the address string. */
417 struct sockaddr_un su;
418 int rc = dill_ipc_resolve(addr, &su);
419 if(rc < 0) {err = errno; goto error1;}
420 /* Open the listening socket. */
421 int s = socket(AF_UNIX, SOCK_STREAM, 0);
422 if(dill_slow(s < 0)) {err = errno; goto error1;}
423 /* Set it to non-blocking mode. */
424 rc = dill_fd_unblock(s);
425 if(dill_slow(rc < 0)) {err = errno; goto error2;}
426 /* Start listening for incoming connections. */
427 rc = bind(s, (struct sockaddr*)&su, sizeof(su));
428 if(dill_slow(rc < 0)) {err = errno; goto error2;}
429 rc = listen(s, backlog);
430 if(dill_slow(rc < 0)) {err = errno; goto error2;}
431 int h = dill_ipc_makelistener(s, mem);
432 if(dill_slow(h < 0)) {err = errno; goto error2;}
433 return h;
434 error2:
435 close(s);
436 error1:
437 errno = err;
438 return -1;
439 }
440
dill_ipc_listen(const char * addr,int backlog)441 int dill_ipc_listen(const char *addr, int backlog) {
442 int err;
443 struct dill_ipc_listener *obj = malloc(sizeof(struct dill_ipc_listener));
444 if(dill_slow(!obj)) {err = ENOMEM; goto error1;}
445 int ls = dill_ipc_listen_mem(addr, backlog,
446 (struct dill_ipc_listener_storage*)obj);
447 if(dill_slow(ls < 0)) {err = errno; goto error2;}
448 obj->mem = 0;
449 return ls;
450 error2:
451 free(obj);
452 error1:
453 errno = err;
454 return -1;
455 }
456
dill_ipc_accept_mem(int s,struct dill_ipc_storage * mem,int64_t deadline)457 int dill_ipc_accept_mem(int s, struct dill_ipc_storage *mem, int64_t deadline) {
458 int err;
459 if(dill_slow(!mem)) {err = EINVAL; goto error1;}
460 /* Retrieve the listener object. */
461 struct dill_ipc_listener *lst = dill_hquery(s, dill_ipc_listener_type);
462 if(dill_slow(!lst)) {err = errno; goto error1;}
463 /* Try to get new connection in a non-blocking way. */
464 int as = dill_fd_accept(lst->fd, NULL, NULL, deadline);
465 if(dill_slow(as < 0)) {err = errno; goto error1;}
466 /* Set it to non-blocking mode. */
467 int rc = dill_fd_unblock(as);
468 if(dill_slow(rc < 0)) {err = errno; goto error2;}
469 /* Create the handle. */
470 int h = dill_ipc_makeconn(as, (struct dill_ipc_conn*)mem);
471 if(dill_slow(h < 0)) {err = errno; goto error2;}
472 return h;
473 error2:
474 dill_fd_close(as);
475 error1:
476 errno = err;
477 return -1;
478 }
479
dill_ipc_accept(int s,int64_t deadline)480 int dill_ipc_accept(int s, int64_t deadline) {
481 int err;
482 struct dill_ipc_conn *obj = malloc(sizeof(struct dill_ipc_conn));
483 if(dill_slow(!obj)) {err = ENOMEM; goto error1;}
484 int as = dill_ipc_accept_mem(s, (struct dill_ipc_storage*)obj, deadline);
485 if(dill_slow(as < 0)) {err = errno; goto error2;}
486 obj->mem = 0;
487 return as;
488 error2:
489 free(obj);
490 error1:
491 errno = err;
492 return -1;
493 }
494
dill_ipc_listener_hclose(struct dill_hvfs * hvfs)495 static void dill_ipc_listener_hclose(struct dill_hvfs *hvfs) {
496 struct dill_ipc_listener *self = (struct dill_ipc_listener*)hvfs;
497 dill_fd_close(self->fd);
498 if(!self->mem) free(self);
499 }
500
501 /******************************************************************************/
502 /* UNIX pair */
503 /******************************************************************************/
504
dill_ipc_pair_mem(struct dill_ipc_pair_storage * mem,int s[2])505 int dill_ipc_pair_mem(struct dill_ipc_pair_storage *mem, int s[2]) {
506 int err;
507 if(dill_slow(!mem)) {err = EINVAL; goto error1;}
508 /* Create the pair. */
509 int fds[2];
510 int rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
511 if(rc < 0) {err = errno; goto error1;}
512 /* Set the sockets to non-blocking mode. */
513 rc = dill_fd_unblock(fds[0]);
514 if(dill_slow(rc < 0)) {err = errno; goto error3;}
515 rc = dill_fd_unblock(fds[1]);
516 if(dill_slow(rc < 0)) {err = errno; goto error3;}
517 /* Create the handles. */
518 struct dill_ipc_conn *conns = (struct dill_ipc_conn*)mem;
519 s[0] = dill_ipc_makeconn(fds[0], &conns[0]);
520 if(dill_slow(s[0] < 0)) {err = errno; goto error3;}
521 s[1] = dill_ipc_makeconn(fds[1], &conns[1]);
522 if(dill_slow(s[1] < 0)) {err = errno; goto error4;}
523 return 0;
524 error4:
525 rc = dill_hclose(s[0]);
526 goto error2;
527 error3:
528 dill_fd_close(fds[0]);
529 error2:
530 dill_fd_close(fds[1]);
531 error1:
532 errno = err;
533 return -1;
534 }
535
dill_ipc_pair(int s[2])536 int dill_ipc_pair(int s[2]) {
537 int err;
538 /* Create the pair. */
539 int fds[2];
540 int rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
541 if(rc < 0) {err = errno; goto error1;}
542 /* Set the sockets to non-blocking mode. */
543 rc = dill_fd_unblock(fds[0]);
544 if(dill_slow(rc < 0)) {err = errno; goto error3;}
545 rc = dill_fd_unblock(fds[1]);
546 if(dill_slow(rc < 0)) {err = errno; goto error3;}
547 /* Allocate the memory. */
548 struct dill_ipc_conn *conn0 = malloc(sizeof(struct dill_ipc_conn));
549 if(dill_slow(!conn0)) {err = ENOMEM; goto error3;}
550 struct dill_ipc_conn *conn1 = malloc(sizeof(struct dill_ipc_conn));
551 if(dill_slow(!conn1)) {err = ENOMEM; goto error4;}
552 /* Create the handles. */
553 s[0] = dill_ipc_makeconn(fds[0], conn0);
554 if(dill_slow(s[0] < 0)) {err = errno; goto error5;}
555 conn0->mem = 0;
556 s[1] = dill_ipc_makeconn(fds[1], conn1);
557 if(dill_slow(s[1] < 0)) {err = errno; goto error6;}
558 conn1->mem = 0;
559 return 0;
560 error6:
561 rc = dill_hclose(s[0]);
562 goto error2;
563 error5:
564 free(conn1);
565 error4:
566 free(conn0);
567 error3:
568 dill_fd_close(fds[0]);
569 error2:
570 dill_fd_close(fds[1]);
571 error1:
572 errno = err;
573 return -1;
574 }
575
576 /******************************************************************************/
577 /* Helpers */
578 /******************************************************************************/
579
dill_ipc_resolve(const char * addr,struct sockaddr_un * su)580 static int dill_ipc_resolve(const char *addr, struct sockaddr_un *su) {
581 dill_assert(su);
582 if(strlen(addr) >= sizeof(su->sun_path)) {errno = ENAMETOOLONG; return -1;}
583 su->sun_family = AF_UNIX;
584 strncpy(su->sun_path, addr, sizeof(su->sun_path));
585 return 0;
586 }
587
588