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"
10 #include "xio-socket.h"
11 #include "xio-listen.h"
13 #include "xio-named.h"
18 /* to avoid unneccessary runtime 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
27 static int xioopen_unix_connect(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
, const struct addrdesc
*addrdesc
);
28 static int xioopen_unix_listen(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
, const struct addrdesc
*addrdesc
);
29 static int xioopen_unix_sendto(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
, const struct addrdesc
*addrdesc
);
30 static int xioopen_unix_recvfrom(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
, const struct addrdesc
*addrdesc
);
31 static int xioopen_unix_recv(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
, const struct addrdesc
*addrdesc
);
32 static int xioopen_unix_client(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xxfd
, const struct addrdesc
*addrdesc
);
34 /* the first free parameter is 0 for "normal" unix domain sockets, or 1 for
35 abstract unix sockets (Linux); the second and third free parameter are
37 const struct addrdesc xioaddr_unix_connect
= { "UNIX-CONNECT", 1+XIO_RDWR
, xioopen_unix_connect
, GROUP_FD
|GROUP_NAMED
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 0, 0, 0 HELP(":<filename>") };
39 const struct addrdesc xioaddr_unix_listen
= { "UNIX-LISTEN", 1+XIO_RDWR
, xioopen_unix_listen
, GROUP_FD
|GROUP_NAMED
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_LISTEN
|GROUP_CHILD
|GROUP_RETRY
, 0, 0, 0 HELP(":<filename>") };
40 #endif /* WITH_LISTEN */
41 const struct addrdesc xioaddr_unix_sendto
= { "UNIX-SENDTO", 1+XIO_RDWR
, xioopen_unix_sendto
, GROUP_FD
|GROUP_NAMED
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 0, 0, 0 HELP(":<filename>") };
42 const struct addrdesc xioaddr_unix_recvfrom
= { "UNIX-RECVFROM", 1+XIO_RDWR
, xioopen_unix_recvfrom
, GROUP_FD
|GROUP_NAMED
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
|GROUP_CHILD
, 0, 0, 0 HELP(":<filename>") };
43 const struct addrdesc xioaddr_unix_recv
= { "UNIX-RECV", 1+XIO_RDONLY
, xioopen_unix_recv
, GROUP_FD
|GROUP_NAMED
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 0, 0, 0 HELP(":<filename>") };
44 const struct addrdesc xioaddr_unix_client
= { "UNIX-CLIENT", 1+XIO_RDWR
, xioopen_unix_client
, GROUP_FD
|GROUP_NAMED
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 0, 0, 0 HELP(":<filename>") };
45 #if WITH_ABSTRACT_UNIXSOCKET
46 const struct addrdesc xioaddr_abstract_connect
= { "ABSTRACT-CONNECT", 1+XIO_RDWR
, xioopen_unix_connect
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 1, 0, 0 HELP(":<filename>") };
48 const struct addrdesc xioaddr_abstract_listen
= { "ABSTRACT-LISTEN", 1+XIO_RDWR
, xioopen_unix_listen
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_LISTEN
|GROUP_CHILD
|GROUP_RETRY
, 1, 0, 0 HELP(":<filename>") };
49 #endif /* WITH_LISTEN */
50 const struct addrdesc xioaddr_abstract_sendto
= { "ABSTRACT-SENDTO", 1+XIO_RDWR
, xioopen_unix_sendto
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 1, 0, 0 HELP(":<filename>") };
51 const struct addrdesc xioaddr_abstract_recvfrom
= { "ABSTRACT-RECVFROM", 1+XIO_RDWR
, xioopen_unix_recvfrom
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
|GROUP_CHILD
, 1, 0, 0 HELP(":<filename>") };
52 const struct addrdesc xioaddr_abstract_recv
= { "ABSTRACT-RECV", 1+XIO_RDONLY
, xioopen_unix_recv
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 1, 0, 0 HELP(":<filename>") };
53 const struct addrdesc xioaddr_abstract_client
= { "ABSTRACT-CLIENT", 1+XIO_RDWR
, xioopen_unix_client
, GROUP_FD
|GROUP_SOCKET
|GROUP_SOCK_UNIX
|GROUP_RETRY
, 1, 0, 0 HELP(":<filename>") };
54 #endif /* WITH_ABSTRACT_UNIXSOCKET */
56 const struct optdesc xioopt_unix_bind_tempname
= { "unix-bind-tempname", "bind-tempname", OPT_UNIX_BIND_TEMPNAME
, GROUP_SOCK_UNIX
, PH_PREOPEN
, TYPE_STRING_NULL
, OFUNC_SPEC
};
57 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
) };
60 /* fills the socket address struct and returns its effective length.
61 abstract is usually 0; != 0 generates an abstract socket address on Linux.
62 tight!=0 calculates the resulting length from the path length, not from the
63 structures length; this is more common (see option unix-tightsocklen)
64 the struct need not be initialized when calling this function.
68 struct sockaddr_un
*saun
,
76 #ifdef WITH_ABSTRACT_UNIXSOCKET
78 if ((pathlen
= strlen(path
)) >= sizeof(saun
->sun_path
)) {
79 Warn2("socket address "F_Zu
" characters long, truncating to "F_Zu
"",
80 pathlen
+1, sizeof(saun
->sun_path
));
82 saun
->sun_path
[0] = '\0'; /* so it's abstract */
83 strncpy(saun
->sun_path
+1, path
, sizeof(saun
->sun_path
)-1); /* ok */
85 len
= sizeof(struct sockaddr_un
)-sizeof(saun
->sun_path
)+
86 MIN(pathlen
+1, sizeof(saun
->sun_path
));
87 #if HAVE_STRUCT_SOCKADDR_SALEN
91 len
= sizeof(struct sockaddr_un
);
95 #endif /* WITH_ABSTRACT_UNIXSOCKET */
97 if ((pathlen
= strlen(path
)) > sizeof(saun
->sun_path
)) {
98 Warn2("unix socket address "F_Zu
" characters long, truncating to "F_Zu
"",
99 pathlen
, sizeof(saun
->sun_path
));
101 strncpy(saun
->sun_path
, path
, sizeof(saun
->sun_path
)); /* ok */
103 len
= sizeof(struct sockaddr_un
)-sizeof(saun
->sun_path
)+
104 MIN(pathlen
, sizeof(saun
->sun_path
));
105 #if HAVE_STRUCT_SOCKADDR_SALEN
109 len
= sizeof(struct sockaddr_un
);
115 static int xioopen_unix_listen(
121 const struct addrdesc
*addrdesc
)
123 /* we expect the form: filename */
125 xiosingle_t
*sfd
= &xxfd
->stream
;
127 int socktype
= SOCK_STREAM
;
129 struct sockaddr_un us
;
131 struct opt
*opts0
= NULL
;
132 pid_t pid
= Getpid();
133 bool opt_unlink_early
= false;
134 bool opt_unlink_close
= (addrdesc
->arg1
/*abstract*/ != 1);
138 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
143 sfd
->para
.socket
.un
.tight
= UNIX_TIGHTSOCKLEN
;
144 retropt_socket_pf(opts
, &pf
);
145 if (sfd
->howtoend
== END_UNSPEC
)
146 sfd
->howtoend
= END_SHUTDOWN
;
148 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
149 /* only for non abstract because abstract do not work in file system */
150 retropt_bool(opts
, OPT_UNLINK_EARLY
, &opt_unlink_early
);
151 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
154 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
155 applyopts(sfd
, -1, opts
, PH_INIT
);
156 applyopts_named(name
, opts
, PH_EARLY
); /* umask! */
157 applyopts_offset(sfd
, opts
);
158 applyopts(sfd
, -1, opts
, PH_EARLY
);
160 uslen
= xiosetunix(pf
, &us
, name
, addrdesc
->arg1
/*abstract*/,
161 sfd
->para
.socket
.un
.tight
);
163 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
164 if (opt_unlink_early
) {
165 xio_unlink(name
, E_ERROR
);
168 if (Lstat(name
, &buf
) == 0) {
169 Error1("\"%s\" exists", name
);
170 return STAT_RETRYLATER
;
173 if (opt_unlink_close
) {
174 if ((sfd
->unlink_close
= strdup(name
)) == NULL
) {
175 Error1("strdup(\"%s\"): out of memory", name
);
177 sfd
->opt_unlink_close
= true;
180 /* trying to set user-early, perm-early etc. here is useless because
181 file system entry is available only past bind() call. */
184 opts0
= copyopts(opts
, GROUP_ALL
);
186 /* this may fork() */
188 xioopen_listen(sfd
, xioflags
,
189 (struct sockaddr
*)&us
, uslen
,
190 opts
, opts0
, pf
, socktype
, protocol
))
194 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
195 if (opt_unlink_close
) {
196 if (pid
!= Getpid()) {
197 /* in a child process - do not unlink-close here! */
198 sfd
->opt_unlink_close
= false;
205 #endif /* WITH_LISTEN */
208 static int xioopen_unix_connect(
214 const struct addrdesc
*addrdesc
)
216 /* we expect the form: filename */
218 struct single
*sfd
= &xxfd
->stream
;
219 const struct opt
*namedopt
;
221 int socktype
= SOCK_STREAM
;
223 struct sockaddr_un them
, us
;
224 socklen_t themlen
, uslen
= sizeof(us
);
225 bool needbind
= false;
226 bool needtemp
= false;
227 bool opt_unlink_close
= (addrdesc
->arg1
/*abstract*/ != 1);
232 char *opt_bind_tempname
= NULL
;
236 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
241 sfd
->para
.socket
.un
.tight
= UNIX_TIGHTSOCKLEN
;
242 retropt_socket_pf(opts
, &pf
);
243 if (sfd
->howtoend
== END_UNSPEC
)
244 sfd
->howtoend
= END_SHUTDOWN
;
245 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
246 applyopts(sfd
, -1, opts
, PH_INIT
);
247 applyopts_offset(sfd
, opts
);
248 applyopts(sfd
, -1, opts
, PH_EARLY
);
250 themlen
= xiosetunix(pf
, &them
, name
, addrdesc
->arg1
/*abstract*/,
251 sfd
->para
.socket
.un
.tight
);
253 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
254 /* Only for non abstract because abstract do not work in file system */
255 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
258 if (retropt_bind(opts
, pf
, socktype
, protocol
, (struct sockaddr
*)&us
, &uslen
,
259 (addrdesc
->arg1
/*abstract*/<<1)|sfd
->para
.socket
.un
.tight
,
260 sfd
->para
.socket
.ip
.ai_flags
)
265 if (retropt_string(opts
, OPT_UNIX_BIND_TEMPNAME
, &opt_bind_tempname
) == 0) {
267 Error("do not use both options bind and unix-bind-tempnam");
272 xiosetunix(pf
, &us
, opt_bind_tempname
?opt_bind_tempname
:"",
273 addrdesc
->arg1
/*abstract*/, sfd
->para
.socket
.un
.tight
);
274 if (opt_bind_tempname
== NULL
&& !addrdesc
->arg1
/*abstract*/) {
275 us
.sun_path
[0] = 0x01; /* mark as non abstract */
280 (namedopt
= searchopt(opts
, GROUP_NAMED
, 0, 0, 0))) {
281 Error1("Option \"%s\" only with bind option", namedopt
->desc
->defname
);
284 retropt_bool(opts
, OPT_FORK
, &dofork
);
286 opts0
= copyopts(opts
, GROUP_ALL
);
288 Notice1("opening connection to %s",
289 sockaddr_info((struct sockaddr
*)&them
, themlen
, infobuff
, sizeof(infobuff
)));
291 do { /* loop over retries and forks */
294 if (sfd
->forever
|| sfd
->retry
) {
297 #endif /* WITH_RETRY */
301 _xioopen_connect(sfd
,
302 needbind
?(union sockaddr_union
*)&us
:NULL
, uslen
,
303 (struct sockaddr
*)&them
, themlen
,
304 opts
, pf
, socktype
, protocol
, needtemp
, level
);
307 /* we caller must handle this */
308 Msg3(level
, "connect(, %s, "F_socklen
"): %s",
309 sockaddr_info((struct sockaddr
*)&them
, themlen
, infobuff
, sizeof(infobuff
)),
310 themlen
, strerror(errno
));
315 case STAT_RETRYLATER
:
316 if (sfd
->forever
|| sfd
->retry
) {
318 if (result
== STAT_RETRYLATER
) {
319 Nanosleep(&sfd
->intervall
, NULL
);
321 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
325 #endif /* WITH_RETRY */
331 xiosetchilddied(); /* set SIGCHLD handler */
338 if (sfd
->forever
|| sfd
->retry
) {
339 level
= E_WARN
; /* most users won't expect a problem here,
340 so Notice is too weak */
343 while ((pid
= xio_fork(false, level
, sfd
->shutup
)) < 0) {
345 if (sfd
->forever
|| sfd
->retry
) {
346 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
347 Nanosleep(&sfd
->intervall
, NULL
); continue;
349 return STAT_RETRYLATER
;
352 if (pid
== 0) { /* child process */
358 /* with and without retry */
359 Nanosleep(&sfd
->intervall
, NULL
);
360 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
361 continue; /* with next socket() bind() connect() */
363 #endif /* WITH_RETRY */
369 if (opt_unlink_close
&& needbind
) {
370 if ((sfd
->unlink_close
= strndup(us
.sun_path
, sizeof(us
.sun_path
))) == NULL
) {
371 Error2("strndup(\"%s\", "F_Zu
"): out of memory", name
, sizeof(us
.sun_path
));
373 sfd
->opt_unlink_close
= true;
376 if ((result
= _xio_openlate(sfd
, opts
)) < 0) {
383 static int xioopen_unix_sendto(
389 const struct addrdesc
*addrdesc
)
391 /* we expect the form: filename */
393 xiosingle_t
*sfd
= &xxfd
->stream
;
394 const struct opt
*namedopt
;
396 int socktype
= SOCK_DGRAM
;
398 struct sockaddr_un us
;
399 socklen_t uslen
= sizeof(us
);
400 bool needbind
= false;
401 bool needtemp
= false;
402 bool opt_unlink_close
= (addrdesc
->arg1
/*abstract*/ != 1);
403 char *opt_bind_tempname
= NULL
;
407 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
412 sfd
->para
.socket
.un
.tight
= UNIX_TIGHTSOCKLEN
;
413 retropt_socket_pf(opts
, &pf
);
414 if (sfd
->howtoend
== END_UNSPEC
)
415 sfd
->howtoend
= END_SHUTDOWN
;
416 applyopts_offset(sfd
, opts
);
418 sfd
->salen
= xiosetunix(pf
, &sfd
->peersa
.un
, name
, addrdesc
->arg1
/*abstract*/, sfd
->para
.socket
.un
.tight
);
420 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
421 /* only for non abstract because abstract do not work in file system */
422 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
425 sfd
->dtype
= XIODATA_RECVFROM
;
427 if (retropt_bind(opts
, pf
, socktype
, protocol
, (struct sockaddr
*)&us
, &uslen
,
428 (addrdesc
->arg1
/*abstract*/<<1)| sfd
->para
.socket
.un
.tight
,
429 sfd
->para
.socket
.ip
.ai_flags
)
434 if (retropt_string(opts
, OPT_UNIX_BIND_TEMPNAME
, &opt_bind_tempname
) == 0) {
436 Error("do not use both options bind and bind-tempnam");
441 xiosetunix(pf
, &us
, opt_bind_tempname
?opt_bind_tempname
:"",
442 addrdesc
->arg1
/*abstract*/, sfd
->para
.socket
.un
.tight
);
446 (namedopt
= searchopt(opts
, GROUP_NAMED
, 0, 0, 0))) {
447 Error1("Option \"%s\" only with bind option", namedopt
->desc
->defname
);
450 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return -1;
451 applyopts(sfd
, -1, opts
, PH_INIT
);
454 _xioopen_dgram_sendto(needbind
?(union sockaddr_union
*)&us
:NULL
, uslen
,
455 opts
, xioflags
, sfd
, addrdesc
->groups
,
456 pf
, socktype
, protocol
, needtemp
);
461 if (opt_unlink_close
&& needbind
) {
462 if ((sfd
->unlink_close
= strndup(us
.sun_path
, sizeof(us
.sun_path
))) == NULL
) {
463 Error2("strndup(\"%s\", "F_Zu
"): out of memory", name
, sizeof(us
.sun_path
));
465 sfd
->opt_unlink_close
= true;
472 int xioopen_unix_recvfrom(
478 const struct addrdesc
*addrdesc
)
480 /* we expect the form: filename */
482 xiosingle_t
*sfd
= &xxfd
->stream
;
484 int socktype
= SOCK_DGRAM
;
486 struct sockaddr_un us
;
488 bool needbind
= true;
489 bool opt_unlink_early
= false;
490 bool opt_unlink_close
= (addrdesc
->arg1
/*abstract*/ != 1);
493 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
498 sfd
->para
.socket
.un
.tight
= UNIX_TIGHTSOCKLEN
;
499 retropt_socket_pf(opts
, &pf
);
500 if (sfd
->howtoend
== END_UNSPEC
)
501 sfd
->howtoend
= END_NONE
;
502 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
503 applyopts(sfd
, -1, opts
, PH_INIT
);
504 applyopts_named(name
, opts
, PH_EARLY
); /* umask! */
505 applyopts_offset(sfd
, opts
);
507 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
508 /* only for non abstract because abstract do not work in file system */
509 retropt_bool(opts
, OPT_UNLINK_EARLY
, &opt_unlink_early
);
510 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
512 applyopts(sfd
, -1, opts
, PH_EARLY
);
514 uslen
= xiosetunix(pf
, &us
, name
, addrdesc
->arg1
/*abstract*/,
515 sfd
->para
.socket
.un
.tight
);
518 if (retropt_bind(opts
, pf
, socktype
, protocol
, (struct sockaddr
*)&us
, &uslen
,
519 (addrdesc
->arg1
/*abstract*/<<1)|sfd
->para
.socket
.un
.tight
,
520 sfd
->para
.socket
.ip
.ai_flags
)) {
525 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
526 if (opt_unlink_early
) {
527 xio_unlink(name
, E_ERROR
);
530 if (Lstat(name
, &buf
) == 0) {
531 Error1("\"%s\" exists", name
);
532 return STAT_RETRYLATER
;
535 if (opt_unlink_close
) {
536 if ((sfd
->unlink_close
= strdup(name
)) == NULL
) {
537 Error1("strdup(\"%s\"): out of memory", name
);
539 sfd
->opt_unlink_close
= true;
542 /* trying to set user-early, perm-early etc. here is useless because
543 file system entry is available only past bind() call. */
545 applyopts_named(name
, opts
, PH_EARLY
); /* umask! */
547 sfd
->para
.socket
.la
.soa
.sa_family
= pf
;
549 sfd
->dtype
= XIODATA_RECVFROM_ONE
;
553 _xioopen_dgram_recvfrom(sfd
, xioflags
,
554 needbind
?(struct sockaddr
*)&us
:NULL
, uslen
,
555 opts
, pf
, socktype
, protocol
, E_ERROR
);
559 static int xioopen_unix_recv(
565 const struct addrdesc
*addrdesc
)
567 /* we expect the form: filename */
569 xiosingle_t
*sfd
= &xxfd
->stream
;
571 int socktype
= SOCK_DGRAM
;
573 union sockaddr_union us
;
575 bool opt_unlink_early
= false;
576 bool opt_unlink_close
= (addrdesc
->arg1
/*abstract*/ != 1);
580 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
585 sfd
->para
.socket
.un
.tight
= UNIX_TIGHTSOCKLEN
;
586 retropt_socket_pf(opts
, &pf
);
587 if (sfd
->howtoend
== END_UNSPEC
)
588 sfd
->howtoend
= END_SHUTDOWN
;
589 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
590 applyopts(sfd
, -1, opts
, PH_INIT
);
591 applyopts_named(name
, opts
, PH_EARLY
); /* umask! */
592 applyopts_offset(sfd
, opts
);
594 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
595 /* only for non abstract because abstract do not work in file system */
596 retropt_bool(opts
, OPT_UNLINK_EARLY
, &opt_unlink_early
);
597 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
599 applyopts(sfd
, -1, opts
, PH_EARLY
);
601 uslen
= xiosetunix(pf
, &us
.un
, name
, addrdesc
->arg1
/*abstract*/,
602 sfd
->para
.socket
.un
.tight
);
605 if (retropt_bind(opts
, pf
, socktype
, protocol
, &us
.soa
, &uslen
,
606 (addrdesc
->arg1
/*abstract*/<<1)|sfd
->para
.socket
.un
.tight
,
607 sfd
->para
.socket
.ip
.ai_flags
)
612 if (!(ABSTRACT
&& addrdesc
->arg1
/*abstract*/)) {
613 if (opt_unlink_early
) {
614 xio_unlink(name
, E_ERROR
);
617 if (Lstat(name
, &buf
) == 0) {
618 Error1("\"%s\" exists", name
);
619 return STAT_RETRYLATER
;
622 if (opt_unlink_close
) {
623 if ((sfd
->unlink_close
= strdup(name
)) == NULL
) {
624 Error1("strdup(\"%s\"): out of memory", name
);
626 sfd
->opt_unlink_close
= true;
629 applyopts_named(name
, opts
, PH_EARLY
); /* umask! */
631 sfd
->para
.socket
.la
.soa
.sa_family
= pf
;
633 sfd
->dtype
= XIODATA_RECV
;
634 result
= _xioopen_dgram_recv(sfd
, xioflags
, &us
.soa
, uslen
,
635 opts
, pf
, socktype
, protocol
, E_ERROR
);
640 /* generic UNIX socket client, tries connect, SEQPACKET, send(to) */
641 static int xioopen_unix_client(
647 const struct addrdesc
*addrdesc
)
649 /* we expect the form: filename */
651 xio_syntax(argv
[0], 1, argc
-1, addrdesc
->syntax
);
656 _xioopen_unix_client(&xxfd
->stream
, xioflags
, addrdesc
->groups
,
657 addrdesc
->arg1
/*abstract*/, opts
, argv
[1], addrdesc
);
660 /* establishes communication with an existing UNIX type socket. supports stream
661 and datagram socket types: first tries to connect(), but when this fails it
662 falls back to sendto().
663 applies and consumes the following option:
664 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND,
665 PH_CONNECTED, PH_LATE, ?PH_CONNECT
667 OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND,
668 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
671 _xioopen_unix_client(
678 const struct addrdesc
*addrdesc
)
680 const struct opt
*namedopt
;
682 int socktype
= 0; /* to be determined by server socket type */
684 union sockaddr_union them
, us
;
685 socklen_t themlen
, uslen
= sizeof(us
);
686 bool needbind
= false;
687 bool needtemp
= false;
688 bool opt_unlink_close
= false;
689 char *opt_bind_tempname
= NULL
;
693 sfd
->para
.socket
.un
.tight
= UNIX_TIGHTSOCKLEN
;
694 retropt_socket_pf(opts
, &pf
);
695 if (sfd
->howtoend
== END_UNSPEC
)
696 sfd
->howtoend
= END_SHUTDOWN
;
697 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
698 applyopts(sfd
, -1, opts
, PH_INIT
);
699 applyopts_offset(sfd
, opts
);
700 retropt_int(opts
, OPT_SO_TYPE
, &socktype
);
701 retropt_int(opts
, OPT_SO_PROTOTYPE
, &protocol
);
702 applyopts(sfd
, -1, opts
, PH_EARLY
);
704 themlen
= xiosetunix(pf
, &them
.un
, name
, abstract
, sfd
->para
.socket
.un
.tight
);
705 if (!(ABSTRACT
&& abstract
)) {
706 /* only for non abstract because abstract do not work in file system */
707 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
710 if (retropt_bind(opts
, pf
, socktype
, protocol
, &us
.soa
, &uslen
,
711 (abstract
<<1)|sfd
->para
.socket
.un
.tight
,
712 sfd
->para
.socket
.ip
.ai_flags
)
717 if (retropt_string(opts
, OPT_UNIX_BIND_TEMPNAME
, &opt_bind_tempname
) == 0) {
719 Error("do not use both options bind and unix-bind-tempname");
727 (namedopt
= searchopt(opts
, GROUP_NAMED
, 0, 0, 0))) {
728 Error1("Option \"%s\" only with bind option", namedopt
->desc
->defname
);
731 if (opt_unlink_close
) {
732 if ((sfd
->unlink_close
= strdup(name
)) == NULL
) {
733 Error1("strdup(\"%s\"): out of memory", name
);
735 sfd
->opt_unlink_close
= true;
738 /* save options, because we might have to start again */
739 opts0
= copyopts(opts
, GROUP_ALL
);
741 /* just a breakable block, helps to avoid goto */
743 /* sfd->dtype = DATA_STREAM; // is default */
745 xiosetunix(pf
, &us
.un
, opt_bind_tempname
?opt_bind_tempname
:"",
746 abstract
, sfd
->para
.socket
.un
.tight
);
747 /* this function handles AF_UNIX with EPROTOTYPE specially for us */
749 _xioopen_connect(sfd
,
750 needbind
?&us
:NULL
, uslen
,
752 opts
, pf
, socktype
?socktype
:SOCK_STREAM
, protocol
,
753 needtemp
, E_INFO
)) == 0)
755 if ((errno
!= EPROTOTYPE
756 #if WITH_ABSTRACT_UNIXSOCKET
757 && !(abstract
&& errno
== ECONNREFUSED
)
762 xio_unlink(us
.un
.sun_path
, E_ERROR
);
763 dropopts2(opts
, PH_INIT
, PH_SPEC
); opts
= opts0
;
766 xiosetunix(pf
, &us
.un
, opt_bind_tempname
?opt_bind_tempname
:"",
767 abstract
, sfd
->para
.socket
.un
.tight
);
768 socktype
= SOCK_SEQPACKET
;
770 _xioopen_connect(sfd
,
771 needbind
?&us
:NULL
, uslen
,
772 (struct sockaddr
*)&them
, themlen
,
773 opts
, pf
, SOCK_SEQPACKET
, protocol
,
774 needtemp
, E_INFO
)) == 0)
776 if (errno
!= EPROTOTYPE
&& errno
!= EPROTONOSUPPORT
/*AIX*/
777 #if WITH_ABSTRACT_UNIXSOCKET
778 && !(abstract
&& errno
== ECONNREFUSED
)
783 xio_unlink(us
.un
.sun_path
, E_ERROR
);
784 dropopts2(opts
, PH_INIT
, PH_SPEC
); opts
= opts0
;
787 xiosetunix(pf
, &us
.un
, opt_bind_tempname
?opt_bind_tempname
:"",
788 abstract
, sfd
->para
.socket
.un
.tight
);
790 sfd
->salen
= themlen
;
792 _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
793 opts
, xioflags
, sfd
, groups
,
794 pf
, SOCK_DGRAM
, protocol
, needtemp
))
796 sfd
->dtype
= XIODATA_RECVFROM
;
802 Error3("%s: %s: %s", addrdesc
->defname
, name
, strerror(errno
));
804 xio_unlink(us
.un
.sun_path
, E_ERROR
);
808 if ((result
= _xio_openlate(sfd
, opts
)) < 0) {
815 /* returns information that can be used for constructing an environment
816 variable describing the socket address.
817 if idx is 0, this function writes "ADDR" into namebuff and the path into
818 valuebuff, and returns 0 (which means that no more info is there).
819 if idx is != 0, it returns -1
820 namelen and valuelen contain the max. allowed length of output chars in the
822 on error this function returns -1.
825 xiosetsockaddrenv_unix(int idx
, char *namebuff
, size_t namelen
,
826 char *valuebuff
, size_t valuelen
,
827 struct sockaddr_un
*sa
, socklen_t salen
, int ipproto
) {
831 strcpy(namebuff
, "ADDR");
832 sockaddr_unix_info(sa
, salen
, valuebuff
, valuelen
);
836 static const char tmpchars
[] =
837 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
838 static size_t numchars
= sizeof(tmpchars
)-1;
840 /* Simplyfied version of tempnam(). Uses the current directory when pathx is
842 Returns a malloc()'ed string with a probably free name,
843 or NULL when an error occurred */
846 bool donttry
) /* for abstract, do not check if it exists */
849 char *X
; /* begin of XXXXXX */
850 unsigned int i
= TMP_MAX
;
854 char readl
[PATH_MAX
];
857 if (pathx
== NULL
|| pathx
[0] == '\0')
858 pathx
= "/tmp/socat-bind.XXXXXX";
861 if (len
< 6 || strstr(pathx
, "XXXXXX") == NULL
) {
862 Warn1("xio_tempnam(\"%s\"): path pattern is not valid", pathx
);
866 patht
= strdup(pathx
);
868 Error1("strdup("F_Zu
"): out of memory", strlen(pathx
));
871 X
= strstr(patht
, "XXXXXX");
873 Debug1("xio_tempnam(\"%s\"): trying path names, suppressing stat() logs",
878 v
= r2
*RAND_MAX
+ r1
;
879 X
[0] = tmpchars
[v
%numchars
];
881 X
[1] = tmpchars
[v
%numchars
];
883 X
[2] = tmpchars
[v
%numchars
];
885 X
[3] = tmpchars
[v
%numchars
];
887 X
[4] = tmpchars
[v
%numchars
];
889 X
[5] = tmpchars
[v
%numchars
];
895 /* readlink() might be faster than lstat() */
896 rlc
= readlink(patht
, readl
, sizeof(readl
));
897 if (rlc
< 0 && errno
== ENOENT
)
911 #endif /* WITH_UNIX */