version 1.7.3.2
[socat.git] / xio-unix.c
blob2e3c5a511580e71da601b156920a03a12a676d69
1 /* source: xio-unix.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses of UNIX socket type */
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
10 #include "xio-socket.h"
11 #include "xio-listen.h"
12 #include "xio-unix.h"
13 #include "xio-named.h"
16 #if WITH_UNIX
18 /* to avoid unneccessary "live" if () conditionals when no abstract support is
19 compiled in (or at least to give optimizing compilers a good chance) we need
20 a constant that can be used in C expressions */
21 #if WITH_ABSTRACT_UNIXSOCKET
22 # define ABSTRACT 1
23 #else
24 # define ABSTRACT 0
25 #endif
27 static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
28 static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
29 static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
30 static int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
31 static
32 int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
33 int xioflags, xiofile_t *xxfd, unsigned groups,
34 int abstract, int dummy2, int dummy3);
35 static
36 int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
38 /* the first free parameter is 0 for "normal" unix domain sockets, or 1 for
39 abstract unix sockets (Linux); the second and third free parameter are
40 unsused */
41 const struct addrdesc xioaddr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
42 #if WITH_LISTEN
43 const struct addrdesc xioaddr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
44 #endif /* WITH_LISTEN */
45 const struct addrdesc xioaddr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
46 const struct addrdesc xioaddr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, 0, 0, 0 HELP(":<filename>") };
47 const struct addrdesc xioaddr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
48 const struct addrdesc xioaddr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
49 #if WITH_ABSTRACT_UNIXSOCKET
50 const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
51 #if WITH_LISTEN
52 const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
53 #endif /* WITH_LISTEN */
54 const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
55 const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, 1, 0, 0 HELP(":<filename>") };
56 const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
57 const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_unix_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
58 #endif /* WITH_ABSTRACT_UNIXSOCKET */
60 const struct optdesc xioopt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_PREBIND, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.un.tight), XIO_SIZEOF(para.socket.un.tight) };
63 /* fills the socket address struct and returns its effective length.
64 abstract is usually 0; != 0 generates an abstract socket address on Linux.
65 tight!=0 calculates the resulting length from the path length, not from the
66 structures length; this is more common (see option unix-tightsocklen)
67 the struct need not be initialized when calling this function.
69 socklen_t
70 xiosetunix(int pf,
71 struct sockaddr_un *saun,
72 const char *path,
73 bool abstract,
74 bool tight) {
75 size_t pathlen;
76 socklen_t len;
78 socket_un_init(saun);
79 #ifdef WITH_ABSTRACT_UNIXSOCKET
80 if (abstract) {
81 if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) {
82 Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"",
83 pathlen+1, sizeof(saun->sun_path));
85 saun->sun_path[0] = '\0'; /* so it's abstract */
86 strncpy(saun->sun_path+1, path, sizeof(saun->sun_path)-1); /* ok */
87 if (tight) {
88 len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
89 MIN(pathlen+1, sizeof(saun->sun_path));
90 #if HAVE_STRUCT_SOCKADDR_SALEN
91 saun->sun_len = len;
92 #endif
93 } else {
94 len = sizeof(struct sockaddr_un);
96 return len;
98 #endif /* WITH_ABSTRACT_UNIXSOCKET */
100 if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
101 Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"",
102 pathlen, sizeof(saun->sun_path));
104 strncpy(saun->sun_path, path, sizeof(saun->sun_path)); /* ok */
105 if (tight) {
106 len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
107 MIN(pathlen, sizeof(saun->sun_path));
108 #if HAVE_STRUCT_SOCKADDR_SALEN
109 saun->sun_len = len;
110 #endif
111 } else {
112 len = sizeof(struct sockaddr_un);
114 return len;
117 #if WITH_LISTEN
118 static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
119 /* we expect the form: filename */
120 const char *name;
121 xiosingle_t *xfd = &xxfd->stream;
122 int pf = PF_UNIX;
123 int socktype = SOCK_STREAM;
124 int protocol = 0;
125 struct sockaddr_un us;
126 socklen_t uslen;
127 struct opt *opts0 = NULL;
128 pid_t pid = Getpid();
129 bool opt_unlink_early = false;
130 bool opt_unlink_close = true;
131 int result;
133 if (argc != 2) {
134 Error2("%s: wrong number of parameters (%d instead of 1)",
135 argv[0], argc-1);
136 return STAT_NORETRY;
138 name = argv[1];
140 xfd->para.socket.un.tight = true;
141 retropt_socket_pf(opts, &pf);
142 xfd->howtoend = END_SHUTDOWN;
144 if (!(ABSTRACT && abstract)) {
145 /* only for non abstract because abstract do not work in file system */
146 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
147 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
150 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
151 applyopts(-1, opts, PH_INIT);
152 applyopts_named(name, opts, PH_EARLY); /* umask! */
153 applyopts_offset(xfd, opts);
154 applyopts(-1, opts, PH_EARLY);
156 uslen = xiosetunix(pf, &us, name, abstract, xfd->para.socket.un.tight);
158 if (!(ABSTRACT && abstract)) {
159 if (opt_unlink_early) {
160 if (Unlink(name) < 0) {
161 if (errno == ENOENT) {
162 Warn2("unlink(\"%s\"): %s", name, strerror(errno));
163 } else {
164 Error2("unlink(\"%s\"): %s", name, strerror(errno));
167 } else {
168 struct stat buf;
169 if (Lstat(name, &buf) == 0) {
170 Error1("\"%s\" exists", name);
171 return STAT_RETRYLATER;
174 if (opt_unlink_close) {
175 if ((xfd->unlink_close = strdup(name)) == NULL) {
176 Error1("strdup(\"%s\"): out of memory", name);
178 xfd->opt_unlink_close = true;
181 /* trying to set user-early, perm-early etc. here is useless because
182 file system entry is available only past bind() call. */
185 opts0 = copyopts(opts, GROUP_ALL);
187 /* this may fork() */
188 if ((result =
189 xioopen_listen(xfd, xioflags,
190 (struct sockaddr *)&us, uslen,
191 opts, opts0, pf, socktype, protocol))
192 != 0)
193 return result;
195 if (!(ABSTRACT && abstract)) {
196 if (opt_unlink_close) {
197 if (pid != Getpid()) {
198 /* in a child process - do not unlink-close here! */
199 xfd->opt_unlink_close = false;
204 return 0;
206 #endif /* WITH_LISTEN */
209 static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
210 /* we expect the form: filename */
211 const char *name;
212 struct single *xfd = &xxfd->stream;
213 int pf = PF_UNIX;
214 int socktype = SOCK_STREAM;
215 int protocol = 0;
216 struct sockaddr_un them, us;
217 socklen_t themlen, uslen = sizeof(us);
218 bool needbind = false;
219 bool opt_unlink_close = false;
220 int result;
222 if (argc != 2) {
223 Error2("%s: wrong number of parameters (%d instead of 1)",
224 argv[0], argc-1);
225 return STAT_NORETRY;
227 name = argv[1];
229 xfd->para.socket.un.tight = true;
230 retropt_socket_pf(opts, &pf);
231 xfd->howtoend = END_SHUTDOWN;
232 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
233 applyopts(-1, opts, PH_INIT);
234 applyopts_offset(xfd, opts);
235 applyopts(-1, opts, PH_EARLY);
237 themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight);
238 if (!(ABSTRACT && abstract)) {
239 /* only for non abstract because abstract do not work in file system */
240 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
242 if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
243 (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) {
244 needbind = true;
247 if (opt_unlink_close) {
248 if ((xfd->unlink_close = strdup(name)) == NULL) {
249 Error1("strdup(\"%s\"): out of memory", name);
251 xfd->opt_unlink_close = true;
254 if ((result =
255 xioopen_connect(xfd,
256 needbind?(struct sockaddr *)&us:NULL, uslen,
257 (struct sockaddr *)&them, themlen,
258 opts, pf, socktype, protocol, false)) != 0) {
259 return result;
261 if ((result = _xio_openlate(xfd, opts)) < 0) {
262 return result;
264 return STAT_OK;
268 static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy, int dummy3) {
269 /* we expect the form: filename */
270 const char *name;
271 xiosingle_t *xfd = &xxfd->stream;
272 int pf = PF_UNIX;
273 int socktype = SOCK_DGRAM;
274 int protocol = 0;
275 union sockaddr_union us;
276 socklen_t uslen = sizeof(us);
277 bool needbind = false;
278 bool opt_unlink_close = false;
280 if (argc != 2) {
281 Error2("%s: wrong number of parameters (%d instead of 1)",
282 argv[0], argc-1);
283 return STAT_NORETRY;
285 name = argv[1];
287 xfd->para.socket.un.tight = true;
288 retropt_socket_pf(opts, &pf);
289 xfd->howtoend = END_SHUTDOWN;
290 applyopts_offset(xfd, opts);
292 xfd->salen = xiosetunix(pf, &xfd->peersa.un, name, abstract, xfd->para.socket.un.tight);
294 if (!(ABSTRACT && abstract)) {
295 /* only for non abstract because abstract do not work in file system */
296 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
299 xfd->dtype = XIODATA_RECVFROM;
301 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
302 (abstract<<1)| xfd->para.socket.un.tight, 0, 0) == STAT_OK) {
303 needbind = true;
306 if (opt_unlink_close) {
307 if ((xfd->unlink_close = strdup(name)) == NULL) {
308 Error1("strdup(\"%s\"): out of memory", name);
310 xfd->opt_unlink_close = true;
313 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
314 applyopts(-1, opts, PH_INIT);
316 return
317 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
318 opts, xioflags, xfd, groups,
319 pf, socktype, protocol);
323 static
324 int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
325 int xioflags, xiofile_t *xxfd, unsigned groups,
326 int abstract, int dummy2, int dummy3) {
327 /* we expect the form: filename */
328 const char *name;
329 xiosingle_t *xfd = &xxfd->stream;
330 int pf = PF_UNIX;
331 int socktype = SOCK_DGRAM;
332 int protocol = 0;
333 struct sockaddr_un us;
334 socklen_t uslen;
335 bool needbind = true;
336 bool opt_unlink_early = false;
337 bool opt_unlink_close = true;
339 if (argc != 2) {
340 Error2("%s: wrong number of parameters (%d instead of 1)",
341 argv[0], argc-1);
342 return STAT_NORETRY;
344 name = argv[1];
346 xfd->para.socket.un.tight = true;
347 retropt_socket_pf(opts, &pf);
348 xfd->howtoend = END_NONE;
349 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
350 applyopts(-1, opts, PH_INIT);
351 applyopts_named(name, opts, PH_EARLY); /* umask! */
352 applyopts_offset(xfd, opts);
354 if (!(ABSTRACT && abstract)) {
355 /* only for non abstract because abstract do not work in file system */
356 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
357 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
359 applyopts(-1, opts, PH_EARLY);
361 uslen = xiosetunix(pf, &us, name, abstract, xfd->para.socket.un.tight);
363 #if 0
364 if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
365 (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) {
367 #endif
369 if (!(ABSTRACT && abstract)) {
370 if (opt_unlink_early) {
371 if (Unlink(name) < 0) {
372 if (errno == ENOENT) {
373 Warn2("unlink(\"%s\"): %s", name, strerror(errno));
374 } else {
375 Error2("unlink(\"%s\"): %s", name, strerror(errno));
378 } else {
379 struct stat buf;
380 if (Lstat(name, &buf) == 0) {
381 Error1("\"%s\" exists", name);
382 return STAT_RETRYLATER;
385 if (opt_unlink_close) {
386 if ((xfd->unlink_close = strdup(name)) == NULL) {
387 Error1("strdup(\"%s\"): out of memory", name);
389 xfd->opt_unlink_close = true;
392 /* trying to set user-early, perm-early etc. here is useless because
393 file system entry is available only past bind() call. */
395 applyopts_named(name, opts, PH_EARLY); /* umask! */
397 xfd->para.socket.la.soa.sa_family = pf;
399 xfd->dtype = XIODATA_RECVFROM_ONE;
401 /* this may fork */
402 return
403 _xioopen_dgram_recvfrom(xfd, xioflags,
404 needbind?(struct sockaddr *)&us:NULL, uslen,
405 opts, pf, socktype, protocol, E_ERROR);
409 static
410 int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
411 int xioflags, xiofile_t *xxfd, unsigned groups,
412 int abstract, int dummy2, int dummy3) {
413 /* we expect the form: filename */
414 const char *name;
415 xiosingle_t *xfd = &xxfd->stream;
416 int pf = PF_UNIX;
417 int socktype = SOCK_DGRAM;
418 int protocol = 0;
419 union sockaddr_union us;
420 socklen_t uslen;
421 bool opt_unlink_early = false;
422 bool opt_unlink_close = true;
423 int result;
425 if (argc != 2) {
426 Error2("%s: wrong number of parameters (%d instead of 1)",
427 argv[0], argc-1);
428 return STAT_NORETRY;
430 name = argv[1];
432 xfd->para.socket.un.tight = true;
433 retropt_socket_pf(opts, &pf);
434 xfd->howtoend = END_SHUTDOWN;
435 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
436 applyopts(-1, opts, PH_INIT);
437 applyopts_named(name, opts, PH_EARLY); /* umask! */
438 applyopts_offset(xfd, opts);
440 if (!(ABSTRACT && abstract)) {
441 /* only for non abstract because abstract do not work in file system */
442 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
443 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
445 applyopts(-1, opts, PH_EARLY);
447 uslen = xiosetunix(pf, &us.un, name, abstract, xfd->para.socket.un.tight);
449 #if 0
450 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
451 (abstract<<1)|xfd->para.socket.un.tight, 0, 0)
452 == STAT_OK) {
454 #endif
456 if (!(ABSTRACT && abstract)) {
457 if (opt_unlink_early) {
458 if (Unlink(name) < 0) {
459 if (errno == ENOENT) {
460 Warn2("unlink(\"%s\"): %s", name, strerror(errno));
461 } else {
462 Error2("unlink(\"%s\"): %s", name, strerror(errno));
465 } else {
466 struct stat buf;
467 if (Lstat(name, &buf) == 0) {
468 Error1("\"%s\" exists", name);
469 return STAT_RETRYLATER;
472 if (opt_unlink_close) {
473 if ((xfd->unlink_close = strdup(name)) == NULL) {
474 Error1("strdup(\"%s\"): out of memory", name);
476 xfd->opt_unlink_close = true;
479 applyopts_named(name, opts, PH_EARLY); /* umask! */
481 xfd->para.socket.la.soa.sa_family = pf;
483 xfd->dtype = XIODATA_RECV;
484 result = _xioopen_dgram_recv(xfd, xioflags, &us.soa, uslen,
485 opts, pf, socktype, protocol, E_ERROR);
486 return result;
490 static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
491 /* we expect the form: filename */
492 if (argc != 2) {
493 Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
496 return
497 _xioopen_unix_client(&xxfd->stream, xioflags, groups, abstract, opts,
498 argv[1]);
501 /* establishes communication with an existing UNIX type socket. supports stream
502 and datagram socket types: first tries to connect(), but when this fails it
503 falls back to sendto().
504 applies and consumes the following option:
505 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND,
506 PH_CONNECTED, PH_LATE, ?PH_CONNECT
507 OFUNC_OFFSET,
508 OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND,
509 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
511 int
512 _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
513 int abstract, struct opt *opts, const char *name) {
514 int pf = PF_UNIX;
515 int socktype = 0; /* to be determined by server socket type */
516 int protocol = 0;
517 union sockaddr_union them, us;
518 socklen_t themlen, uslen = sizeof(us);
519 bool needbind = false;
520 bool opt_unlink_close = false;
521 struct opt *opts0;
522 int result;
524 xfd->para.socket.un.tight = true;
525 retropt_socket_pf(opts, &pf);
526 xfd->howtoend = END_SHUTDOWN;
527 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
528 applyopts(-1, opts, PH_INIT);
529 applyopts_offset(xfd, opts);
530 applyopts(-1, opts, PH_EARLY);
532 themlen = xiosetunix(pf, &them.un, name, abstract, xfd->para.socket.un.tight);
533 if (!(ABSTRACT && abstract)) {
534 /* only for non abstract because abstract do not work in file system */
535 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
537 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
538 (abstract<<1)|xfd->para.socket.un.tight, 0, 0)
539 != STAT_NOACTION) {
540 needbind = true;
543 if (opt_unlink_close) {
544 if ((xfd->unlink_close = strdup(name)) == NULL) {
545 Error1("strdup(\"%s\"): out of memory", name);
547 xfd->opt_unlink_close = true;
550 /* save options, because we might have to start again */
551 opts0 = copyopts(opts, GROUP_ALL);
553 /* xfd->dtype = DATA_STREAM; // is default */
554 if ((result =
555 xioopen_connect(xfd,
556 needbind?(struct sockaddr *)&us:NULL, uslen,
557 (struct sockaddr *)&them, themlen,
558 opts, pf, socktype?socktype:SOCK_STREAM, protocol,
559 false)) != 0) {
560 if (errno == EPROTOTYPE) {
561 if (needbind) {
562 Unlink(us.un.sun_path);
565 dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
567 xfd->peersa = them;
568 xfd->salen = sizeof(struct sockaddr_un);
569 if ((result =
570 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
571 opts, xioflags, xfd, groups,
572 pf, socktype?socktype:SOCK_DGRAM, protocol))
573 != 0) {
574 return result;
576 xfd->dtype = XIODATA_RECVFROM;
579 if ((result = _xio_openlate(xfd, opts)) < 0) {
580 return result;
582 return 0;
586 /* returns information that can be used for constructing an environment
587 variable describing the socket address.
588 if idx is 0, this function writes "ADDR" into namebuff and the path into
589 valuebuff, and returns 0 (which means that no more info is there).
590 if idx is != 0, it returns -1
591 namelen and valuelen contain the max. allowed length of output chars in the
592 respective buffer.
593 on error this function returns -1.
596 xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
597 char *valuebuff, size_t valuelen,
598 struct sockaddr_un *sa, socklen_t salen, int ipproto) {
599 if (idx != 0) {
600 return -1;
602 strcpy(namebuff, "ADDR");
603 sockaddr_unix_info(sa, salen, valuebuff, valuelen);
604 return 0;
607 #endif /* WITH_UNIX */