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 */
4
5 /* this file contains the source for opening addresses of UNIX socket type */
6
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
9
10 #include "xio-socket.h"
11 #include "xio-listen.h"
12 #include "xio-unix.h"
13 #include "xio-named.h"
14
15
16 #if WITH_UNIX
17
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
26
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);
37
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 */
59
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) };
61
62
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.
68 */
69 socklen_t
xiosetunix(int pf,struct sockaddr_un * saun,const char * path,bool abstract,bool tight)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;
77
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));
84 }
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);
95 }
96 return len;
97 }
98 #endif /* WITH_ABSTRACT_UNIXSOCKET */
99
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));
103 }
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);
113 }
114 return len;
115 }
116
117 #if WITH_LISTEN
xioopen_unix_listen(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int abstract,int dummy2,int dummy3)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;
132
133 if (argc != 2) {
134 Error2("%s: wrong number of parameters (%d instead of 1)",
135 argv[0], argc-1);
136 return STAT_NORETRY;
137 }
138 name = argv[1];
139
140 xfd->para.socket.un.tight = true;
141 retropt_socket_pf(opts, &pf);
142 xfd->howtoend = END_SHUTDOWN;
143
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);
148 }
149
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);
155
156 uslen = xiosetunix(pf, &us, name, abstract, xfd->para.socket.un.tight);
157
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));
165 }
166 }
167 } else {
168 struct stat buf;
169 if (Lstat(name, &buf) == 0) {
170 Error1("\"%s\" exists", name);
171 return STAT_RETRYLATER;
172 }
173 }
174 if (opt_unlink_close) {
175 if ((xfd->unlink_close = strdup(name)) == NULL) {
176 Error1("strdup(\"%s\"): out of memory", name);
177 }
178 xfd->opt_unlink_close = true;
179 }
180
181 /* trying to set user-early, perm-early etc. here is useless because
182 file system entry is available only past bind() call. */
183 }
184
185 opts0 = copyopts(opts, GROUP_ALL);
186
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;
194
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;
200 }
201 }
202 }
203
204 return 0;
205 }
206 #endif /* WITH_LISTEN */
207
208
xioopen_unix_connect(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int abstract,int dummy2,int dummy3)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 const struct opt *namedopt;
214 int pf = PF_UNIX;
215 int socktype = SOCK_STREAM;
216 int protocol = 0;
217 struct sockaddr_un them, us;
218 socklen_t themlen, uslen = sizeof(us);
219 bool needbind = false;
220 bool opt_unlink_close = true;
221 int result;
222
223 if (argc != 2) {
224 Error2("%s: wrong number of parameters (%d instead of 1)",
225 argv[0], argc-1);
226 return STAT_NORETRY;
227 }
228 name = argv[1];
229
230 xfd->para.socket.un.tight = true;
231 retropt_socket_pf(opts, &pf);
232 xfd->howtoend = END_SHUTDOWN;
233 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
234 applyopts(-1, opts, PH_INIT);
235 applyopts_offset(xfd, opts);
236 applyopts(-1, opts, PH_EARLY);
237
238 themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight);
239
240 if (!(ABSTRACT && abstract)) {
241 /* only for non abstract because abstract do not work in file system */
242 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
243 }
244 if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
245 (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) {
246 needbind = true;
247 }
248
249 if (!needbind &&
250 (namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
251 Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
252 }
253
254 if (opt_unlink_close && needbind) {
255 if ((xfd->unlink_close = strdup(us.sun_path)) == NULL) {
256 Error1("strdup(\"%s\"): out of memory", name);
257 }
258 xfd->opt_unlink_close = true;
259 }
260
261 if ((result =
262 xioopen_connect(xfd,
263 needbind?(union sockaddr_union *)&us:NULL, uslen,
264 (struct sockaddr *)&them, themlen,
265 opts, pf, socktype, protocol, false)) != 0) {
266 return result;
267 }
268 if ((result = _xio_openlate(xfd, opts)) < 0) {
269 return result;
270 }
271 return STAT_OK;
272 }
273
274
xioopen_unix_sendto(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int abstract,int dummy,int dummy3)275 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) {
276 /* we expect the form: filename */
277 const char *name;
278 xiosingle_t *xfd = &xxfd->stream;
279 const struct opt *namedopt;
280 int pf = PF_UNIX;
281 int socktype = SOCK_DGRAM;
282 int protocol = 0;
283 union sockaddr_union us;
284 socklen_t uslen = sizeof(us);
285 bool needbind = false;
286 bool opt_unlink_close = true;
287
288 if (argc != 2) {
289 Error2("%s: wrong number of parameters (%d instead of 1)",
290 argv[0], argc-1);
291 return STAT_NORETRY;
292 }
293 name = argv[1];
294
295 xfd->para.socket.un.tight = true;
296 retropt_socket_pf(opts, &pf);
297 xfd->howtoend = END_SHUTDOWN;
298 applyopts_offset(xfd, opts);
299
300 xfd->salen = xiosetunix(pf, &xfd->peersa.un, name, abstract, xfd->para.socket.un.tight);
301
302 if (!(ABSTRACT && abstract)) {
303 /* only for non abstract because abstract do not work in file system */
304 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
305 }
306
307 xfd->dtype = XIODATA_RECVFROM;
308
309 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
310 (abstract<<1)| xfd->para.socket.un.tight, 0, 0) == STAT_OK) {
311 needbind = true;
312 }
313
314 if (!needbind &&
315 (namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
316 Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
317 }
318
319 if (opt_unlink_close && needbind) {
320 if ((xfd->unlink_close = strdup(us.un.sun_path)) == NULL) {
321 Error1("strdup(\"%s\"): out of memory", name);
322 }
323 xfd->opt_unlink_close = true;
324 }
325
326 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
327 applyopts(-1, opts, PH_INIT);
328
329 return
330 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
331 opts, xioflags, xfd, groups,
332 pf, socktype, protocol);
333 }
334
335
336 static
xioopen_unix_recvfrom(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int abstract,int dummy2,int dummy3)337 int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
338 int xioflags, xiofile_t *xxfd, unsigned groups,
339 int abstract, int dummy2, int dummy3) {
340 /* we expect the form: filename */
341 const char *name;
342 xiosingle_t *xfd = &xxfd->stream;
343 int pf = PF_UNIX;
344 int socktype = SOCK_DGRAM;
345 int protocol = 0;
346 struct sockaddr_un us;
347 socklen_t uslen;
348 bool needbind = true;
349 bool opt_unlink_early = false;
350 bool opt_unlink_close = true;
351
352 if (argc != 2) {
353 Error2("%s: wrong number of parameters (%d instead of 1)",
354 argv[0], argc-1);
355 return STAT_NORETRY;
356 }
357 name = argv[1];
358
359 xfd->para.socket.un.tight = true;
360 retropt_socket_pf(opts, &pf);
361 xfd->howtoend = END_NONE;
362 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
363 applyopts(-1, opts, PH_INIT);
364 applyopts_named(name, opts, PH_EARLY); /* umask! */
365 applyopts_offset(xfd, opts);
366
367 if (!(ABSTRACT && abstract)) {
368 /* only for non abstract because abstract do not work in file system */
369 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
370 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
371 }
372 applyopts(-1, opts, PH_EARLY);
373
374 uslen = xiosetunix(pf, &us, name, abstract, xfd->para.socket.un.tight);
375
376 #if 0
377 if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
378 (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) {
379 }
380 #endif
381
382 if (!(ABSTRACT && abstract)) {
383 if (opt_unlink_early) {
384 if (Unlink(name) < 0) {
385 if (errno == ENOENT) {
386 Warn2("unlink(\"%s\"): %s", name, strerror(errno));
387 } else {
388 Error2("unlink(\"%s\"): %s", name, strerror(errno));
389 }
390 }
391 } else {
392 struct stat buf;
393 if (Lstat(name, &buf) == 0) {
394 Error1("\"%s\" exists", name);
395 return STAT_RETRYLATER;
396 }
397 }
398 if (opt_unlink_close) {
399 if ((xfd->unlink_close = strdup(name)) == NULL) {
400 Error1("strdup(\"%s\"): out of memory", name);
401 }
402 xfd->opt_unlink_close = true;
403 }
404
405 /* trying to set user-early, perm-early etc. here is useless because
406 file system entry is available only past bind() call. */
407 }
408 applyopts_named(name, opts, PH_EARLY); /* umask! */
409
410 xfd->para.socket.la.soa.sa_family = pf;
411
412 xfd->dtype = XIODATA_RECVFROM_ONE;
413
414 /* this may fork */
415 return
416 _xioopen_dgram_recvfrom(xfd, xioflags,
417 needbind?(struct sockaddr *)&us:NULL, uslen,
418 opts, pf, socktype, protocol, E_ERROR);
419 }
420
421
422 static
xioopen_unix_recv(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int abstract,int dummy2,int dummy3)423 int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
424 int xioflags, xiofile_t *xxfd, unsigned groups,
425 int abstract, int dummy2, int dummy3) {
426 /* we expect the form: filename */
427 const char *name;
428 xiosingle_t *xfd = &xxfd->stream;
429 int pf = PF_UNIX;
430 int socktype = SOCK_DGRAM;
431 int protocol = 0;
432 union sockaddr_union us;
433 socklen_t uslen;
434 bool opt_unlink_early = false;
435 bool opt_unlink_close = true;
436 int result;
437
438 if (argc != 2) {
439 Error2("%s: wrong number of parameters (%d instead of 1)",
440 argv[0], argc-1);
441 return STAT_NORETRY;
442 }
443 name = argv[1];
444
445 xfd->para.socket.un.tight = true;
446 retropt_socket_pf(opts, &pf);
447 xfd->howtoend = END_SHUTDOWN;
448 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
449 applyopts(-1, opts, PH_INIT);
450 applyopts_named(name, opts, PH_EARLY); /* umask! */
451 applyopts_offset(xfd, opts);
452
453 if (!(ABSTRACT && abstract)) {
454 /* only for non abstract because abstract do not work in file system */
455 retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
456 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
457 }
458 applyopts(-1, opts, PH_EARLY);
459
460 uslen = xiosetunix(pf, &us.un, name, abstract, xfd->para.socket.un.tight);
461
462 #if 0
463 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
464 (abstract<<1)|xfd->para.socket.un.tight, 0, 0)
465 == STAT_OK) {
466 }
467 #endif
468
469 if (!(ABSTRACT && abstract)) {
470 if (opt_unlink_early) {
471 if (Unlink(name) < 0) {
472 if (errno == ENOENT) {
473 Warn2("unlink(\"%s\"): %s", name, strerror(errno));
474 } else {
475 Error2("unlink(\"%s\"): %s", name, strerror(errno));
476 }
477 }
478 } else {
479 struct stat buf;
480 if (Lstat(name, &buf) == 0) {
481 Error1("\"%s\" exists", name);
482 return STAT_RETRYLATER;
483 }
484 }
485 if (opt_unlink_close) {
486 if ((xfd->unlink_close = strdup(name)) == NULL) {
487 Error1("strdup(\"%s\"): out of memory", name);
488 }
489 xfd->opt_unlink_close = true;
490 }
491 }
492 applyopts_named(name, opts, PH_EARLY); /* umask! */
493
494 xfd->para.socket.la.soa.sa_family = pf;
495
496 xfd->dtype = XIODATA_RECV;
497 result = _xioopen_dgram_recv(xfd, xioflags, &us.soa, uslen,
498 opts, pf, socktype, protocol, E_ERROR);
499 return result;
500 }
501
502
xioopen_unix_client(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int abstract,int dummy2,int dummy3)503 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) {
504 /* we expect the form: filename */
505 if (argc != 2) {
506 Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
507 }
508
509 return
510 _xioopen_unix_client(&xxfd->stream, xioflags, groups, abstract, opts,
511 argv[1]);
512 }
513
514 /* establishes communication with an existing UNIX type socket. supports stream
515 and datagram socket types: first tries to connect(), but when this fails it
516 falls back to sendto().
517 applies and consumes the following option:
518 PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND,
519 PH_CONNECTED, PH_LATE, ?PH_CONNECT
520 OFUNC_OFFSET,
521 OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND,
522 OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
523 */
524 int
_xioopen_unix_client(xiosingle_t * xfd,int xioflags,unsigned groups,int abstract,struct opt * opts,const char * name)525 _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
526 int abstract, struct opt *opts, const char *name) {
527 const struct opt *namedopt;
528 int pf = PF_UNIX;
529 int socktype = 0; /* to be determined by server socket type */
530 int protocol = 0;
531 union sockaddr_union them, us;
532 socklen_t themlen, uslen = sizeof(us);
533 bool needbind = false;
534 bool opt_unlink_close = false;
535 struct opt *opts0;
536 int result;
537
538 xfd->para.socket.un.tight = true;
539 retropt_socket_pf(opts, &pf);
540 xfd->howtoend = END_SHUTDOWN;
541 if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
542 applyopts(-1, opts, PH_INIT);
543 applyopts_offset(xfd, opts);
544 retropt_int(opts, OPT_SO_TYPE, &socktype);
545 retropt_int(opts, OPT_SO_PROTOTYPE, &protocol);
546 applyopts(-1, opts, PH_EARLY);
547
548 themlen = xiosetunix(pf, &them.un, name, abstract, xfd->para.socket.un.tight);
549 if (!(ABSTRACT && abstract)) {
550 /* only for non abstract because abstract do not work in file system */
551 retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
552 }
553 if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
554 (abstract<<1)|xfd->para.socket.un.tight, 0, 0)
555 != STAT_NOACTION) {
556 needbind = true;
557 }
558
559 if (!needbind &&
560 (namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
561 Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
562 }
563
564 if (opt_unlink_close) {
565 if ((xfd->unlink_close = strdup(name)) == NULL) {
566 Error1("strdup(\"%s\"): out of memory", name);
567 }
568 xfd->opt_unlink_close = true;
569 }
570
571 /* save options, because we might have to start again */
572 opts0 = copyopts(opts, GROUP_ALL);
573
574 /* just a breakable block, helps to avoid goto */
575 do {
576 /* xfd->dtype = DATA_STREAM; // is default */
577 /* this function handles AF_UNIX with EPROTOTYPE specially for us */
578 if ((result =
579 xioopen_connect(xfd,
580 needbind?&us:NULL, uslen,
581 &them.soa, themlen,
582 opts, pf, socktype?socktype:SOCK_STREAM, protocol,
583 false)) == 0)
584 break;
585 if (errno != EPROTOTYPE || socktype != 0)
586 break;
587 if (needbind)
588 Unlink(us.un.sun_path);
589 dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
590
591 socktype = SOCK_SEQPACKET;
592 if ((result =
593 xioopen_connect(xfd,
594 needbind?&us:NULL, uslen,
595 (struct sockaddr *)&them, themlen,
596 opts, pf, SOCK_SEQPACKET, protocol,
597 false)) == 0)
598 break;
599 if (errno != EPROTOTYPE)
600 break;
601 if (needbind)
602 Unlink(us.un.sun_path);
603 dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
604
605 xfd->peersa = them;
606 xfd->salen = sizeof(struct sockaddr_un);
607 if ((result =
608 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
609 opts, xioflags, xfd, groups,
610 pf, SOCK_DGRAM, protocol))
611 == 0) {
612 xfd->dtype = XIODATA_RECVFROM;
613 break;
614 }
615 } while (0);
616
617 if (result != 0) {
618 if (needbind) {
619 Unlink(us.un.sun_path);
620 }
621 return result;
622 }
623
624 if ((result = _xio_openlate(xfd, opts)) < 0) {
625 return result;
626 }
627 return 0;
628 }
629
630
631 /* returns information that can be used for constructing an environment
632 variable describing the socket address.
633 if idx is 0, this function writes "ADDR" into namebuff and the path into
634 valuebuff, and returns 0 (which means that no more info is there).
635 if idx is != 0, it returns -1
636 namelen and valuelen contain the max. allowed length of output chars in the
637 respective buffer.
638 on error this function returns -1.
639 */
640 int
xiosetsockaddrenv_unix(int idx,char * namebuff,size_t namelen,char * valuebuff,size_t valuelen,struct sockaddr_un * sa,socklen_t salen,int ipproto)641 xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
642 char *valuebuff, size_t valuelen,
643 struct sockaddr_un *sa, socklen_t salen, int ipproto) {
644 if (idx != 0) {
645 return -1;
646 }
647 strcpy(namebuff, "ADDR");
648 sockaddr_unix_info(sa, salen, valuebuff, valuelen);
649 return 0;
650 }
651
652 #endif /* WITH_UNIX */
653