1 /* source: xio-unix.c */
2 /* Copyright Gerhard Rieger 2001-2009 */
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 "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
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
);
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
);
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
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>") };
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>") };
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_INIT
, TYPE_BOOL
, OFUNC_SPEC
, 0, 0 };
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.
67 the struct need not be initialized when calling this function.
71 struct sockaddr_un
*saun
,
79 #ifdef WITH_ABSTRACT_UNIXSOCKET
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);
88 len
= sizeof(struct sockaddr_un
)-sizeof(saun
->sun_path
)+
89 MIN(pathlen
+1, sizeof(saun
->sun_path
));
90 #if HAVE_STRUCT_SOCKADDR_SALEN
94 len
= sizeof(struct sockaddr_un
);
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
));
106 len
= sizeof(struct sockaddr_un
)-sizeof(saun
->sun_path
)+
107 MIN(pathlen
, sizeof(saun
->sun_path
));
108 #if HAVE_STRUCT_SOCKADDR_SALEN
112 len
= sizeof(struct sockaddr_un
);
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 */
121 xiosingle_t
*xfd
= &xxfd
->stream
;
123 int socktype
= SOCK_STREAM
;
125 struct sockaddr_un us
;
128 struct opt
*opts0
= NULL
;
129 bool opt_unlink_early
= false;
130 bool opt_unlink_close
= true;
134 Error2("%s: wrong number of parameters (%d instead of 1)",
140 retropt_socket_pf(opts
, &pf
);
141 retropt_bool(opts
, OPT_UNIX_TIGHTSOCKLEN
, &tight
);
142 uslen
= xiosetunix(pf
, &us
, name
, abstract
, tight
);
144 xfd
->howtoend
= END_SHUTDOWN
;
146 if (!(ABSTRACT
&& abstract
)) {
147 /* only for non abstract because abstract do not work in file system */
148 retropt_bool(opts
, OPT_UNLINK_EARLY
, &opt_unlink_early
);
149 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
150 if (opt_unlink_close
) {
151 if ((xfd
->unlink_close
= strdup(name
)) == NULL
) {
152 Error1("strdup(\"%s\"): out of memory", name
);
154 xfd
->opt_unlink_close
= true;
158 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return STAT_NORETRY
;
159 applyopts(-1, opts
, PH_INIT
);
160 applyopts(-1, opts
, PH_EARLY
);
162 if (!(ABSTRACT
&& abstract
)) {
163 if (opt_unlink_early
) {
164 if (Unlink(name
) < 0) {
165 if (errno
== ENOENT
) {
166 Warn2("unlink(\"%s\"): %s", name
, strerror(errno
));
168 Error2("unlink(\"%s\"): %s", name
, strerror(errno
));
173 /* trying to set user-early, perm-early etc. here is useless because
174 file system entry is available only past bind() call. */
175 applyopts_named(name
, opts
, PH_EARLY
); /* umask! */
178 opts0
= copyopts(opts
, GROUP_ALL
);
181 xioopen_listen(xfd
, xioflags
,
182 (struct sockaddr
*)&us
, uslen
,
183 opts
, opts0
, pf
, socktype
, protocol
))
188 #endif /* WITH_LISTEN */
191 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
) {
192 /* we expect the form: filename */
194 struct single
*xfd
= &xxfd
->stream
;
196 int socktype
= SOCK_STREAM
;
198 struct sockaddr_un them
, us
;
199 socklen_t themlen
, uslen
;
201 bool needbind
= false;
202 bool opt_unlink_close
= false;
206 Error2("%s: wrong number of parameters (%d instead of 1)",
212 retropt_socket_pf(opts
, &pf
);
213 retropt_bool(opts
, OPT_UNIX_TIGHTSOCKLEN
, &tight
);
214 themlen
= xiosetunix(pf
, &them
, name
, abstract
, tight
);
215 if (!(ABSTRACT
&& abstract
)) {
216 /* only for non abstract because abstract do not work in file system */
217 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
219 if (retropt_bind(opts
, pf
, socktype
, protocol
, (struct sockaddr
*)&us
, &uslen
, 0, 0, 0)
224 if (opt_unlink_close
) {
225 if ((xfd
->unlink_close
= strdup(name
)) == NULL
) {
226 Error1("strdup(\"%s\"): out of memory", name
);
228 xfd
->opt_unlink_close
= true;
231 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
232 applyopts(-1, opts
, PH_INIT
);
233 applyopts(-1, opts
, PH_EARLY
);
237 needbind
?(struct sockaddr
*)&us
:NULL
, uslen
,
238 (struct sockaddr
*)&them
, themlen
,
239 opts
, pf
, socktype
, protocol
, false)) != 0) {
242 if ((result
= _xio_openlate(xfd
, opts
)) < 0) {
249 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
) {
250 /* we expect the form: filename */
252 xiosingle_t
*xfd
= &xxfd
->stream
;
254 int socktype
= SOCK_DGRAM
;
256 union sockaddr_union us
;
259 bool needbind
= false;
260 bool opt_unlink_close
= false;
263 Error2("%s: wrong number of parameters (%d instead of 1)",
268 retropt_bool(opts
, OPT_UNIX_TIGHTSOCKLEN
, &tight
);
270 retropt_socket_pf(opts
, &pf
);
271 xfd
->salen
= xiosetunix(pf
, &xfd
->peersa
.un
, name
, abstract
, tight
);
273 xfd
->howtoend
= END_SHUTDOWN
;
275 if (!(ABSTRACT
&& abstract
)) {
276 /* only for non abstract because abstract do not work in file system */
277 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
280 xfd
->dtype
= XIODATA_RECVFROM
;
282 if (retropt_bind(opts
, pf
, socktype
, protocol
, &us
.soa
, &uslen
, 0, 0, 0)
287 if (opt_unlink_close
) {
288 if ((xfd
->unlink_close
= strdup(name
)) == NULL
) {
289 Error1("strdup(\"%s\"): out of memory", name
);
291 xfd
->opt_unlink_close
= true;
294 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
295 applyopts(-1, opts
, PH_INIT
);
298 _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
299 opts
, xioflags
, xfd
, groups
,
300 pf
, socktype
, protocol
);
305 int xioopen_unix_recvfrom(int argc
, const char *argv
[], struct opt
*opts
,
306 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
307 int abstract
, int dummy2
, int dummy3
) {
308 /* we expect the form: filename */
310 xiosingle_t
*xfd
= &xxfd
->stream
;
312 int socktype
= SOCK_DGRAM
;
314 struct sockaddr_un us
;
317 bool needbind
= true;
318 bool opt_unlink_early
= false;
319 bool opt_unlink_close
= true;
322 Error2("%s: wrong number of parameters (%d instead of 1)",
328 retropt_socket_pf(opts
, &pf
);
329 retropt_bool(opts
, OPT_UNIX_TIGHTSOCKLEN
, &tight
);
330 uslen
= xiosetunix(pf
, &us
, name
, abstract
, tight
);
332 xfd
->howtoend
= END_NONE
;
333 retropt_bind(opts
, pf
, socktype
, protocol
, (struct sockaddr
*)&us
, &uslen
,
336 if (!(ABSTRACT
&& abstract
)) {
337 /* only for non abstract because abstract do not work in file system */
338 retropt_bool(opts
, OPT_UNLINK_EARLY
, &opt_unlink_early
);
339 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
340 if (opt_unlink_close
) {
341 if ((xfd
->unlink_close
= strdup(name
)) == NULL
) {
342 Error1("strdup(\"%s\"): out of memory", name
);
344 xfd
->opt_unlink_close
= true;
347 if (opt_unlink_early
) {
348 if (Unlink(name
) < 0) {
349 if (errno
== ENOENT
) {
350 Warn2("unlink(\"%s\"): %s", name
, strerror(errno
));
352 Error2("unlink(\"%s\"): %s", name
, strerror(errno
));
358 xfd
->para
.socket
.la
.soa
.sa_family
= pf
;
360 xfd
->dtype
= XIODATA_RECVFROM_ONE
;
362 _xioopen_dgram_recvfrom(xfd
, xioflags
,
363 needbind
?(struct sockaddr
*)&us
:NULL
, uslen
,
364 opts
, pf
, socktype
, protocol
, E_ERROR
);
369 int xioopen_unix_recv(int argc
, const char *argv
[], struct opt
*opts
,
370 int xioflags
, xiofile_t
*xxfd
, unsigned groups
,
371 int abstract
, int dummy2
, int dummy3
) {
372 /* we expect the form: filename */
374 xiosingle_t
*xfd
= &xxfd
->stream
;
376 int socktype
= SOCK_DGRAM
;
378 union sockaddr_union us
;
381 bool opt_unlink_early
= false;
382 bool opt_unlink_close
= true;
386 Error2("%s: wrong number of parameters (%d instead of 1)",
392 retropt_socket_pf(opts
, &pf
);
393 retropt_bool(opts
, OPT_UNIX_TIGHTSOCKLEN
, &tight
);
394 uslen
= xiosetunix(pf
, &us
.un
, name
, abstract
, tight
);
396 #if 1 /*!!! why bind option? */
397 retropt_bind(opts
, pf
, socktype
, protocol
, &us
.soa
, &uslen
, 1, 0, 0);
400 if (!(ABSTRACT
&& abstract
)) {
401 /* only for non abstract because abstract do not work in file system */
402 retropt_bool(opts
, OPT_UNLINK_EARLY
, &opt_unlink_early
);
403 if (opt_unlink_early
) {
404 if (Unlink(name
) < 0) {
405 if (errno
== ENOENT
) {
406 Warn2("unlink(\"%s\"): %s", name
, strerror(errno
));
408 Error2("unlink(\"%s\"): %s", name
, strerror(errno
));
413 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
415 if (opt_unlink_close
) {
416 if ((xfd
->unlink_close
= strdup(name
)) == NULL
) {
417 Error1("strdup(\"%s\"): out of memory", name
);
419 xfd
->opt_unlink_close
= true;
423 xfd
->para
.socket
.la
.soa
.sa_family
= pf
;
425 xfd
->dtype
= XIODATA_RECV
;
426 result
= _xioopen_dgram_recv(xfd
, xioflags
, &us
.soa
, uslen
,
427 opts
, pf
, socktype
, protocol
, E_ERROR
);
432 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
) {
433 /* we expect the form: filename */
435 Error2("%s: wrong number of parameters (%d instead of 1)", argv
[0], argc
-1);
439 _xioopen_unix_client(&xxfd
->stream
, xioflags
, groups
, abstract
, opts
,
443 /* establishes communication with an existing UNIX type socket. supports stream
444 and datagram socket types: first tries to connect(), but when this fails it
445 falls back to sendto().
446 applies and consumes the following option:
447 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND,
448 PH_CONNECTED, PH_LATE, ?PH_CONNECT
450 OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND,
451 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
454 _xioopen_unix_client(xiosingle_t
*xfd
, int xioflags
, unsigned groups
,
455 int abstract
, struct opt
*opts
, const char *name
) {
457 int socktype
= 0; /* to be determined by server socket type */
459 union sockaddr_union them
, us
;
460 socklen_t themlen
, uslen
;
462 bool needbind
= false;
463 bool opt_unlink_close
= false;
467 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
468 applyopts(-1, opts
, PH_INIT
);
470 xfd
->howtoend
= END_SHUTDOWN
;
471 retropt_socket_pf(opts
, &pf
);
473 retropt_bool(opts
, OPT_UNIX_TIGHTSOCKLEN
, &tight
);
474 themlen
= xiosetunix(pf
, &them
.un
, name
, abstract
, tight
);
476 if (!(ABSTRACT
&& abstract
)) {
477 /* only for non abstract because abstract do not work in file system */
478 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
481 if (retropt_bind(opts
, pf
, socktype
, protocol
, &us
.soa
, &uslen
, 0, 0, 0)
486 if (opt_unlink_close
) {
487 if ((xfd
->unlink_close
= strdup(name
)) == NULL
) {
488 Error1("strdup(\"%s\"): out of memory", name
);
490 xfd
->opt_unlink_close
= true;
493 /* save options, because we might have to start again */
494 opts0
= copyopts(opts
, GROUP_ALL
);
496 /* xfd->dtype = DATA_STREAM; // is default */
499 needbind
?(struct sockaddr
*)&us
:NULL
, uslen
,
500 (struct sockaddr
*)&them
, themlen
,
501 opts
, pf
, socktype
?socktype
:SOCK_STREAM
, protocol
,
503 if (errno
== EPROTOTYPE
) {
505 Unlink(us
.un
.sun_path
);
508 dropopts2(opts
, PH_INIT
, PH_SPEC
); opts
= opts0
;
511 xfd
->salen
= sizeof(struct sockaddr_un
);
513 _xioopen_dgram_sendto(needbind
?&us
:NULL
, uslen
,
514 opts
, xioflags
, xfd
, groups
,
515 pf
, socktype
?socktype
:SOCK_DGRAM
, protocol
))
519 xfd
->dtype
= XIODATA_RECVFROM
;
522 if ((result
= _xio_openlate(xfd
, opts
)) < 0) {
529 /* returns information that can be used for constructing an environment
530 variable describing the socket address.
531 if idx is 0, this function writes "ADDR" into namebuff and the path into
532 valuebuff, and returns 0 (which means that no more info is there).
533 if idx is != 0, it returns -1
534 namelen and valuelen contain the max. allowed length of output chars in the
536 on error this function returns -1.
539 xiosetsockaddrenv_unix(int idx
, char *namebuff
, size_t namelen
,
540 char *valuebuff
, size_t valuelen
,
541 struct sockaddr_un
*sa
, socklen_t salen
, int ipproto
) {
545 strcpy(namebuff
, "ADDR");
546 sockaddr_unix_info(sa
, salen
, valuebuff
, valuelen
);
550 #endif /* WITH_UNIX */