add listen-timeout to function as an accept timeout
[socat/sam.git] / xio-unix.c
blobe45a3fa11bfac8db83f2662f59b27515808448b8
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"
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_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.
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);
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));
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 bool tight = true;
128 struct opt *opts0 = NULL;
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;
139 name = argv[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));
167 } else {
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);
180 if ((result =
181 xioopen_listen(xfd, xioflags,
182 (struct sockaddr *)&us, uslen,
183 opts, opts0, pf, socktype, protocol))
184 != 0)
185 return result;
186 return 0;
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 */
193 const char *name;
194 struct single *xfd = &xxfd->stream;
195 int pf = PF_UNIX;
196 int socktype = SOCK_STREAM;
197 int protocol = 0;
198 struct sockaddr_un them, us;
199 socklen_t themlen, uslen;
200 bool tight = true;
201 bool needbind = false;
202 bool opt_unlink_close = false;
203 int result;
205 if (argc != 2) {
206 Error2("%s: wrong number of parameters (%d instead of 1)",
207 argv[0], argc-1);
208 return STAT_NORETRY;
211 name = argv[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)
220 != STAT_NOACTION) {
221 needbind = true;
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);
235 if ((result =
236 xioopen_connect(xfd,
237 needbind?(struct sockaddr *)&us:NULL, uslen,
238 (struct sockaddr *)&them, themlen,
239 opts, pf, socktype, protocol, false)) != 0) {
240 return result;
242 if ((result = _xio_openlate(xfd, opts)) < 0) {
243 return result;
245 return STAT_OK;
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 */
251 const char *name;
252 xiosingle_t *xfd = &xxfd->stream;
253 int pf = PF_UNIX;
254 int socktype = SOCK_DGRAM;
255 int protocol = 0;
256 union sockaddr_union us;
257 socklen_t uslen;
258 bool tight = true;
259 bool needbind = false;
260 bool opt_unlink_close = false;
262 if (argc != 2) {
263 Error2("%s: wrong number of parameters (%d instead of 1)",
264 argv[0], argc-1);
265 return STAT_NORETRY;
268 retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
269 name = argv[1];
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)
283 != STAT_NOACTION) {
284 needbind = true;
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);
297 return
298 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
299 opts, xioflags, xfd, groups,
300 pf, socktype, protocol);
304 static
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 */
309 const char *name;
310 xiosingle_t *xfd = &xxfd->stream;
311 int pf = PF_UNIX;
312 int socktype = SOCK_DGRAM;
313 int protocol = 0;
314 struct sockaddr_un us;
315 socklen_t uslen;
316 bool tight = true;
317 bool needbind = true;
318 bool opt_unlink_early = false;
319 bool opt_unlink_close = true;
321 if (argc != 2) {
322 Error2("%s: wrong number of parameters (%d instead of 1)",
323 argv[0], argc-1);
324 return STAT_NORETRY;
327 name = argv[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,
334 1, 0, 0);
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));
351 } else {
352 Error2("unlink(\"%s\"): %s", name, strerror(errno));
358 xfd->para.socket.la.soa.sa_family = pf;
360 xfd->dtype = XIODATA_RECVFROM_ONE;
361 return
362 _xioopen_dgram_recvfrom(xfd, xioflags,
363 needbind?(struct sockaddr *)&us:NULL, uslen,
364 opts, pf, socktype, protocol, E_ERROR);
368 static
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 */
373 const char *name;
374 xiosingle_t *xfd = &xxfd->stream;
375 int pf = PF_UNIX;
376 int socktype = SOCK_DGRAM;
377 int protocol = 0;
378 union sockaddr_union us;
379 socklen_t uslen;
380 bool tight = true;
381 bool opt_unlink_early = false;
382 bool opt_unlink_close = true;
383 int result;
385 if (argc != 2) {
386 Error2("%s: wrong number of parameters (%d instead of 1)",
387 argv[0], argc-1);
388 return STAT_NORETRY;
391 name = argv[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);
398 #endif
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));
407 } else {
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);
428 return result;
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 */
434 if (argc != 2) {
435 Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
438 return
439 _xioopen_unix_client(&xxfd->stream, xioflags, groups, abstract, opts,
440 argv[1]);
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
449 OFUNC_OFFSET,
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,
453 int
454 _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
455 int abstract, struct opt *opts, const char *name) {
456 int pf = PF_UNIX;
457 int socktype = 0; /* to be determined by server socket type */
458 int protocol = 0;
459 union sockaddr_union them, us;
460 socklen_t themlen, uslen;
461 bool tight = true;
462 bool needbind = false;
463 bool opt_unlink_close = false;
464 struct opt *opts0;
465 int result;
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)
482 != STAT_NOACTION) {
483 needbind = true;
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 */
497 if ((result =
498 xioopen_connect(xfd,
499 needbind?(struct sockaddr *)&us:NULL, uslen,
500 (struct sockaddr *)&them, themlen,
501 opts, pf, socktype?socktype:SOCK_STREAM, protocol,
502 false)) != 0) {
503 if (errno == EPROTOTYPE) {
504 if (needbind) {
505 Unlink(us.un.sun_path);
508 dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
510 xfd->peersa = them;
511 xfd->salen = sizeof(struct sockaddr_un);
512 if ((result =
513 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
514 opts, xioflags, xfd, groups,
515 pf, socktype?socktype:SOCK_DGRAM, protocol))
516 != 0) {
517 return result;
519 xfd->dtype = XIODATA_RECVFROM;
522 if ((result = _xio_openlate(xfd, opts)) < 0) {
523 return result;
525 return 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
535 respective buffer.
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) {
542 if (idx != 0) {
543 return -1;
545 strcpy(namebuff, "ADDR");
546 sockaddr_unix_info(sa, salen, valuebuff, valuelen);
547 return 0;
550 #endif /* WITH_UNIX */