diff --git a/CHANGES b/CHANGES index 2e5a048..75b1c42 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,9 @@ +new features: + so-type now only affect the socket() and socketpair() calls, not the + name resolution. so-type and so-prototype can be applied to all socket + based addresses. + corrections: some raw IP and UNIX datagram modes failed on BSD systems diff --git a/VERSION b/VERSION index 9a06c88..721ab27 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock" +"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+protocol" diff --git a/doc/socat.yo b/doc/socat.yo index 4befd5b..99b134b 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -1585,11 +1585,23 @@ label(OPTION_SNDLOWAT)dit(bf(tt(sndlowat=))) layer will send the data to [link(int)(TYPE_INT)]. label(OPTION_SNDTIMEO)dit(bf(tt(sndtimeo=))) Sets the send timeout to seconds [link(timeval)(TYPE_TIMEVAL)]. -label(OPTION_TYPE)dit(bf(tt(type=))) - Sets the type of the socket, usually as argument to the code(socket()) or - code(socketpair()) call, to [link(int)(TYPE_INT)]. +label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=))) + Forces the use of the specified IP version or protocol. can be + something like "ip4" or "ip6". The resulting value is + used as first argument to the code(socket()) or code(socketpair()) calls. + This option affects address resolution and the required syntax of bind and + range options. +label(OPTION_SO_TYPE)dit(bf(tt(type=))) + Sets the type of the socket, specified as second argument to the + code(socket()) or code(socketpair()) calls, to + [link(int)(TYPE_INT)]. Address resolution is not affected by this option. Under Linux, 1 means stream oriented socket, 2 means datagram socket, and 3 means raw socket. +label(OPTION_SO_PROTOTYPE)dit(bf(tt(prototype))) + Sets the protocol of the socket, specified as third argument to the + code(socket()) or code(socketpair()) calls, to + [link(int)(TYPE_INT)]. Address resolution is not affected by this option. + 6 means TCP, 17 means UDP. COMMENT(label(OPTION_USELOOPBACK)dit(bf(tt(useloopback))) Sets the code(SO_USELOOPBACK) socket option.) COMMENT(label(OPTION_ACCEPTCONN)dit(bf(tt(acceptconn))) @@ -1618,8 +1630,6 @@ COMMENT(label(OPTION_PASSCRED)dit(bf(tt(passcred))) Set the code(SO_PASSCRED) socket option.) COMMENT(label(OPTION_PEERCRED)dit(bf(tt(peercred))) This is a read-only socket option.) -COMMENT(label(OPTION_PROTOTYPE)dit(bf(tt(prototype))) - Tries to set the code(SO_PROTOTYPE) socket option.) COMMENT(label(OPTION_REUSEPORT)dit(bf(tt(reuseport))) Set the code(SO_REUSEPORT) socket option.) COMMENT(label(OPTION_SECUTIYAUTHENTICATION)dit(bf(tt(securityauthentication))) @@ -1632,9 +1642,6 @@ COMMENT(label(OPTION_SIOCSPGRP)dit(bf(tt(siocspgrp=))) Set the SIOCSPGRP with code(ioclt()) to enable SIGIO.) COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs))) Set the code(SO_USE_IFBUFS) socket option.) -label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=))) - Forces the use of the specified IP version. can be - something like "ip4" or "ip6". enddit() startdit()enddit()nl() diff --git a/filan.c b/filan.c index e0477d1..3b3d045 100644 --- a/filan.c +++ b/filan.c @@ -479,6 +479,9 @@ int sockan(int fd, FILE *outfile) { {SO_REUSEADDR, "REUSEADDR"}, {SO_TYPE, "TYPE"}, {SO_ERROR, "ERROR"}, +#ifdef SO_PROTOTYPE + {SO_PROTOTYPE, "PROTOTYPE"}, +#endif {SO_DONTROUTE, "DONTROUTE"}, {SO_BROADCAST, "BROADCAST"}, {SO_SNDBUF, "SNDBUF"}, diff --git a/test.sh b/test.sh index aba5733..90005af 100755 --- a/test.sh +++ b/test.sh @@ -2362,7 +2362,7 @@ N=$((N+1)) #} -NAME=UNIXSOCKET +NAME=UNIXSTREAM case "$TESTS" in *%functions%*|*%unix%*|*%$NAME%*) TEST="$NAME: echo via connection to UNIX domain socket" @@ -2372,7 +2372,7 @@ ts="$td/test$N.socket" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD1="$SOCAT $opts UNIX-LISTEN:$ts PIPE" -CMD2="$SOCAT $opts -!!- UNIX:$ts" +CMD2="$SOCAT $opts -!!- UNIX-CONNECT:$ts" printf "test $F_n $TEST... " $N $CMD1 $tf 2>"${te}1" & bg=$! # background process id diff --git a/xio-gopen.c b/xio-gopen.c index bc172ed..7c1497f 100644 --- a/xio-gopen.c +++ b/xio-gopen.c @@ -45,113 +45,17 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio /* note: when S_ISSOCK was undefined, it always gives 0 */ if (exists && S_ISSOCK(st_mode)) { #if WITH_UNIX - int socktype = SOCK_STREAM; - int optsotype = -1; - struct sockaddr_un sa, us; - socklen_t salen, uslen = sizeof(us); - bool needbind = false; + union sockaddr_union us; + socklen_t uslen; char infobuff[256]; - struct opt *opts2; - - socket_un_init(&sa); - socket_un_init(&us); Info1("\"%s\" is a socket, connecting to it", filename); - if (retropt_int(opts, OPT_SO_TYPE, &optsotype) == 0) { - socktype = optsotype; + + result = + _xioopen_unix_client(&fd->stream, xioflags, groups, 0, opts, filename); + if (result < 0) { + return result; } - - if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0) != STAT_NOACTION) { - needbind = true; - } - - retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); - if (opt_unlink_close) { - if ((fd->stream.unlink_close = strdup(filename)) == NULL) { - Error1("strdup(\"%s\"): out of memory", filename); - } - fd->stream.opt_unlink_close = true; - } - - /* save options, because we might have to start again with Socket() */ - opts2 = copyopts(opts, GROUP_ALL); - - if ((fd->stream.fd = Socket(PF_UNIX, socktype, 0)) < 0) { - Error2("socket(PF_UNIX, %d, 0): %s", socktype, strerror(errno)); - return STAT_RETRYLATER; - } - /*0 Info2("socket(PF_UNIX, %d, 0) -> %d", socktype, fd->stream.fd);*/ - applyopts(fd->stream.fd, opts, PH_PASTSOCKET); - applyopts(fd->stream.fd, opts, PH_FD); - - applyopts_cloexec(fd->stream.fd, opts); - - sa.sun_family = AF_UNIX; - salen = xiosetunix(&sa, filename, false, false); - -#if 0 - applyopts(fd->stream.fd, opts, PH_PREBIND); - applyopts(fd->stream.fd, opts, PH_BIND); - if (us) { - if (Bind(fd->stream.fd, us, uslen) < 0) { - Error4("bind(%d, {%s}, "F_Zd"): %s", - fd->fd, sockaddr_info(us, infobuff, sizeof(infobuff)), - uslen, strerror(errno)); - if (fd->forever || --fd->retry) { - Nanosleep(&fd->intervall, NULL); - continue; - } else - return STAT_RETRYLATER; - } - } - applyopts(fd->stream.fd, opts, PH_PASTBIND); -#endif /* 0 */ - - applyopts(fd->stream.fd, opts, PH_CONNECT); - if ((result = Connect(fd->stream.fd, (struct sockaddr *)&sa, salen)) < 0) { - if (errno == EINPROGRESS) { - Warn4("connect(%d, %s, "F_Zd"): %s", - fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)), - sizeof(sa), strerror(errno)); - } else if (errno == EPROTOTYPE && optsotype != SOCK_STREAM) { - Warn4("connect(%d, %s, "F_Zd"): %s", - fd->stream.fd, sockaddr_unix_info(&sa, salen, infobuff, sizeof(infobuff)), - sizeof(sa), strerror(errno)); - Info("assuming datagram socket"); - Close(fd->stream.fd); - - opts = opts2; - if ((fd->stream.fd = Socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { - Error1("socket(PF_UNIX, SOCK_DGRAM, 0): %s", strerror(errno)); - return STAT_RETRYLATER; - } - /*0 Info1("socket(PF_UNIX, SOCK_DGRAM, 0) -> %d", fd->stream.fd);*/ - - applyopts(fd->stream.fd, opts, PH_PASTSOCKET); - applyopts(fd->stream.fd, opts, PH_FD); - - applyopts_cloexec(fd->stream.fd, opts); - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)); - - fd->stream.dtype = XIODATA_RECVFROM; - fd->stream.salen = sizeof(sa); - memcpy(&fd->stream.peersa.soa, &sa, fd->stream.salen); - } else { - Error4("connect(%d, %s, "F_Zd"): %s", - fd->stream.fd, sockaddr_unix_info(&sa, fd->stream.salen, infobuff, sizeof(infobuff)), - sizeof(sa), strerror(errno)); - return STAT_RETRYLATER; - } - } - if (fd->stream.howtoend == END_UNSPEC) { - fd->stream.howtoend = END_SHUTDOWN; - } - - applyopts_fchown(fd->stream.fd, opts); - applyopts(fd->stream.fd, opts, PH_CONNECTED); - applyopts(fd->stream.fd, opts, PH_LATE); applyopts_named(filename, opts, PH_PASTOPEN); /* unlink-late */ if (Getsockname(fd->stream.fd, (struct sockaddr *)&us, &uslen) < 0) { @@ -159,7 +63,8 @@ static int xioopen_gopen(int argc, const char *argv[], struct opt *opts, int xio fd->stream.fd, &us, uslen, strerror(errno)); } else { Notice1("successfully connected via %s", - sockaddr_unix_info(&us, uslen, infobuff, sizeof(infobuff))); + sockaddr_unix_info(&us.un, uslen, + infobuff, sizeof(infobuff))); } #else Error("\"%s\" is a socket, but UNIX socket support is not compiled in"); diff --git a/xio-ip.c b/xio-ip.c index 77dd71d..7519870 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -205,6 +205,18 @@ int xiogetaddrinfo(const char *node, const char *service, if (node != NULL || service != NULL) { struct addrinfo *record; + if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM) { + /* actual socket type value is not supported - fallback to a good one */ + socktype = SOCK_DGRAM; + } + if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) { + /* actual protocol value is not supported - fallback to a good one */ + if (socktype == SOCK_DGRAM) { + protocol = IPPROTO_UDP; + } else { + protocol = IPPROTO_TCP; + } + } hints.ai_flags |= AI_PASSIVE; hints.ai_family = family; hints.ai_socktype = socktype; diff --git a/xio-ipapp.c b/xio-ipapp.c index 1a3effd..c9106ea 100644 --- a/xio-ipapp.c +++ b/xio-ipapp.c @@ -52,8 +52,8 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], - them, &themlen, us, &uslen, &needbind, &lowport, - &socktype) != STAT_OK) { + them, &themlen, us, &uslen, &needbind, &lowport, + socktype) != STAT_OK) { return STAT_NORETRY; } @@ -147,7 +147,11 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, } -/* returns STAT_OK on success or some other value on failure */ +/* returns STAT_OK on success or some other value on failure + applies and consumes the following options: + PH_EARLY + OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT + */ int _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, const char *hostname, @@ -158,7 +162,7 @@ int union sockaddr_union *them, socklen_t *themlen, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, - int *socktype) { + int socktype) { uint16_t port; char infobuff[256]; int result; @@ -167,7 +171,7 @@ int if ((result = xiogetaddrinfo(hostname, portname, - *pf, *socktype, protocol, + *pf, socktype, protocol, (union sockaddr_union *)them, themlen, res_opts0, res_opts1 )) @@ -181,7 +185,7 @@ int applyopts(-1, opts, PH_EARLY); /* 3 means: IP address AND port accepted */ - if (retropt_bind(opts, *pf, *socktype, protocol, (struct sockaddr *)us, uslen, 3, + if (retropt_bind(opts, *pf, socktype, protocol, (struct sockaddr *)us, uslen, 3, res_opts0, res_opts1) != STAT_NOACTION) { *needbind = true; @@ -210,7 +214,6 @@ int } retropt_bool(opts, OPT_LOWPORT, lowport); - retropt_int(opts, OPT_SO_TYPE, socktype); *opts0 = copyopts(opts, GROUP_ALL); @@ -222,22 +225,24 @@ int #if WITH_TCP && WITH_LISTEN +/* + applies and consumes the following options: + OPT_PROTOCOL_FAMILY, OPT_BIND + */ int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, const char *portname, int *pf, int ipproto, unsigned long res_opts0, unsigned long res_opts1, union sockaddr_union *us, socklen_t *uslen, - int *socktype) { + int socktype) { char *bindname = NULL; int result; - retropt_int(opts, OPT_SO_TYPE, socktype); - retropt_socket_pf(opts, pf); retropt_string(opts, OPT_BIND, &bindname); if ((result = - xiogetaddrinfo(bindname, portname, *pf, *socktype, ipproto, + xiogetaddrinfo(bindname, portname, *pf, socktype, ipproto, (union sockaddr_union *)us, uslen, res_opts0, res_opts1)) != STAT_OK) { @@ -284,7 +289,7 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, if (_xioopen_ipapp_listen_prepare(opts, &opts0, argv[1], &pf, ipproto, fd->stream.para.socket.ip.res_opts[1], fd->stream.para.socket.ip.res_opts[0], - us, &uslen, &socktype) + us, &uslen, socktype) != STAT_OK) { return STAT_NORETRY; } diff --git a/xio-ipapp.h b/xio-ipapp.h index ce5ece1..c2dcb1e 100644 --- a/xio-ipapp.h +++ b/xio-ipapp.h @@ -1,5 +1,5 @@ /* source: xio-ipapp.h */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_ipapp_h_included @@ -25,7 +25,7 @@ extern int union sockaddr_union *them, socklen_t *themlen, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, - int *socktype); + int socktype); extern int _xioopen_ip4app_connect(const char *hostname, const char *portname, struct single *xfd, int socktype, int ipproto, void *protname, @@ -39,7 +39,7 @@ extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, unsigned long res_opts0, unsigned long res_opts1, union sockaddr_union *us, socklen_t *uslen, - int *socktype); + int socktype); extern int xioopen_ip6app_connect(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, unsigned groups, int socktype, int ipproto, diff --git a/xio-listen.c b/xio-listen.c index 38a65c6..e17bcaf 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -25,6 +25,13 @@ const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_R #endif +/* + applies and consumes the following option: + PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, + PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2 + OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_BACKLOG, OPT_RANGE, tcpwrap, + OPT_SOURCEPORT, OPT_LOWPORT, cloexec + */ int xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, @@ -81,15 +88,21 @@ int } -/* waits for incoming connection, checks its source address and port. Depending - on fork option, it may fork a subprocess. +/* creates the listening socket, bind, applies options; waits for incoming + connection, checks its source address and port. Depending on fork option, it + may fork a subprocess. Returns 0 if a connection was accepted; with fork option, this is always in a subprocess! Other return values indicate a problem; this can happen in the master process or in a subprocess. - This function does not retry. If you need retries, handle this is a - loop in the calling function. + This function does not retry. If you need retries, handle this in a + loop in the calling function (and always provide the options...) after fork, we set the forever/retry of the child process to 0 + applies and consumes the following option: + PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, + PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2 + OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_BACKLOG, OPT_RANGE, tcpwrap, + OPT_SOURCEPORT, OPT_LOWPORT, cloexec */ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, struct opt *opts, int pf, int socktype, int proto, int level) { @@ -119,9 +132,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl xiosetchilddied(); /* set SIGCHLD handler */ } - if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { - Msg4(level, - "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) { return STAT_RETRYLATER; } diff --git a/xio-openssl.c b/xio-openssl.c index 4fa17bc..ba76a52 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -200,7 +200,7 @@ static int xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], them, &themlen, us, &uslen, - &needbind, &lowport, &socktype); + &needbind, &lowport, socktype); if (result != STAT_OK) return STAT_NORETRY; if (xioopts.logopt == 'm') { @@ -440,7 +440,7 @@ static int if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], - us, &uslen, &socktype) + us, &uslen, socktype) != STAT_OK) { return STAT_NORETRY; } diff --git a/xio-progcall.c b/xio-progcall.c index 0c9f8ed..63fd562 100644 --- a/xio-progcall.c +++ b/xio-progcall.c @@ -10,6 +10,9 @@ #include "xio-process.h" #include "xio-progcall.h" +#include "xio-socket.h" + + /* these options are used by address pty too */ #if HAVE_OPENPTY const struct optdesc opt_openpty = { "openpty", NULL, OPT_OPENPTY, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; @@ -49,7 +52,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ ) { struct opt *popts; /* parent process options */ int numleft; - int d, type, protocol, sv[2], rdpip[2], wrpip[2]; + int d, sv[2], rdpip[2], wrpip[2]; int rw = (xioflags & XIO_ACCMODE); bool usepipes = false; #if HAVE_PTY @@ -358,13 +361,10 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ applyopts(fd->fd, popts, PH_LATE); if (applyopts_single(fd, popts, PH_LATE) < 0) return -1; } else { - d = AF_UNIX; type = SOCK_STREAM; - protocol = 0; /* PF_UNIX does not work on AIX */ - retropt_int(popts, OPT_SO_TYPE, &type); - result = Socketpair(d, type, protocol, sv); + d = AF_UNIX; + retropt_int(popts, OPT_PROTOCOL_FAMILY, &d); + result = xiosocketpair(popts, d, SOCK_STREAM, 0, sv); if (result < 0) { - Error5("socketpair(%d, %d, %d, %p): %s", - d, type, protocol, sv, strerror(errno)); return -1; } /*0 Info5("socketpair(%d, %d, %d, {%d,%d})", diff --git a/xio-proxy.c b/xio-proxy.c index 23ab032..fe15ffd 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -131,7 +131,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], them, &themlen, us, &uslen, - &needbind, &lowport, &socktype); + &needbind, &lowport, socktype); if (result != STAT_OK) return result; Notice4("opening connection to %s:%u via proxy %s:%s", diff --git a/xio-rawip.c b/xio-rawip.c index a1a0e09..7df1b39 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -17,7 +17,6 @@ #include "xio-rawip.h" - static int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int pf, @@ -38,7 +37,7 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, static int _xioopen_rawip_sendto(const char *hostname, const char *protname, struct opt *opts, int xioflags, - xiofile_t *xxfd, unsigned groups, int pf); + xiofile_t *xxfd, unsigned groups, int *pf); const struct addrdesc addr_rawip_sendto = { "ip-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, PF_UNSPEC, 0, 0 HELP("::") }; const struct addrdesc addr_rawip_datagram= { "ip-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, 0, 0 HELP("::") }; @@ -75,17 +74,24 @@ int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, - groups, pf)) != STAT_OK) { + groups, &pf)) != STAT_OK) { return result; } _xio_openlate(&xxfd->stream, opts); return STAT_OK; } +/* + applies and consumes the following options: + PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE + OFUNC_OFFSET + OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, + OPT_GROUP, OPT_CLOEXEC + */ static int _xioopen_rawip_sendto(const char *hostname, const char *protname, struct opt *opts, int xioflags, xiofile_t *xxfd, - unsigned groups, int pf) { + unsigned groups, int *pf) { char *garbage; xiosingle_t *xfd = &xxfd->stream; union sockaddr_union us; @@ -107,7 +113,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, } xfd->howtoend = END_SHUTDOWN; - retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_int(opts, OPT_PROTOCOL_FAMILY, pf); /* ...res_opts[] */ if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; @@ -115,29 +121,29 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, xfd->salen = sizeof(xfd->peersa); if ((result = - xiogetaddrinfo(hostname, NULL, pf, socktype, ipproto, + xiogetaddrinfo(hostname, NULL, *pf, socktype, ipproto, &xfd->peersa, &xfd->salen, xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts[1])) != STAT_OK) { return result; } - if (pf == PF_UNSPEC) { - pf = xfd->peersa.soa.sa_family; + if (*pf == PF_UNSPEC) { + *pf = xfd->peersa.soa.sa_family; } - uslen = socket_init(pf, &us); + uslen = socket_init(*pf, &us); xfd->dtype = XIODATA_RECVFROM_SKIPIP; - if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats, + if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats, xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) { needbind = true; } return _xioopen_dgram_sendto(needbind?&us:NULL, uslen, - opts, xioflags, xfd, groups, pf, socktype, ipproto); + opts, xioflags, xfd, groups, *pf, socktype, ipproto); } @@ -157,7 +163,7 @@ int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, } if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, - groups, pf)) != STAT_OK) { + groups, &pf)) != STAT_OK) { return result; } @@ -216,7 +222,6 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, /*return STAT_NORETRY;*/ } xfd->stream.howtoend = END_NONE; - retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { @@ -274,7 +279,6 @@ int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, protname); /*return STAT_NORETRY;*/ } - retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { diff --git a/xio-socket.c b/xio-socket.c index d93bb98..766f0ab 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -39,7 +39,7 @@ const struct optdesc opt_so_sndbuf_late={ "so-sndbuf-late","sndbuf-late",OPT_SO_ const struct optdesc opt_so_rcvbuf = { "so-rcvbuf", "rcvbuf", OPT_SO_RCVBUF, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVBUF}; const struct optdesc opt_so_rcvbuf_late={"so-rcvbuf-late","rcvbuf-late",OPT_SO_RCVBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVBUF }; const struct optdesc opt_so_error = { "so-error", "error", OPT_SO_ERROR, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ERROR}; -const struct optdesc opt_so_type = { "so-type", "type", OPT_SO_TYPE, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_TYPE }; +const struct optdesc opt_so_type = { "so-type", "type", OPT_SO_TYPE, GROUP_SOCKET, PH_SOCKET, TYPE_INT, OFUNC_SPEC, SOL_SOCKET, SO_TYPE }; const struct optdesc opt_so_dontroute= { "so-dontroute", "dontroute", OPT_SO_DONTROUTE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_DONTROUTE }; #ifdef SO_RCVLOWAT const struct optdesc opt_so_rcvlowat = { "so-rcvlowat", "rcvlowat", OPT_SO_RCVLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVLOWAT }; @@ -115,9 +115,9 @@ const struct optdesc opt_so_dgram_errind={"so-dgram-errind","dgramerrind",OPT_SO #ifdef SO_DONTLINGER /* Solaris */ const struct optdesc opt_so_dontlinger = {"so-dontlinger", "dontlinger", OPT_SO_DONTLINGER, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DONTLINGER }; #endif -#ifdef SO_PROTOTYPE /* Solaris, HP-UX */ -const struct optdesc opt_so_prototype = {"so-prototype", "prototype", OPT_SO_PROTOTYPE, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_PROTOTYPE }; -#endif +/* the SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more + general purpose */ +const struct optdesc opt_so_prototype = {"so-prototype", "prototype", OPT_SO_PROTOTYPE, GROUP_SOCKET,PH_SOCKET, TYPE_INT,OFUNC_SPEC, SOL_SOCKET,SO_PROTOTYPE }; #ifdef FIOSETOWN const struct optdesc opt_fiosetown = { "fiosetown", NULL, OPT_FIOSETOWN, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_IOCTL, FIOSETOWN }; #endif @@ -127,15 +127,21 @@ const struct optdesc opt_siocspgrp = { "siocspgrp", NULL, OPT_SIOCSPGRP, GRO const struct optdesc opt_bind = { "bind", NULL, OPT_BIND, GROUP_SOCKET, PH_BIND, TYPE_STRING,OFUNC_SPEC }; const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNECT_TIMEOUT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.socket.connect_timeout }; const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_protocol = { "protocol", NULL, OPT_PROTOCOL, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC }; /* a subroutine that is common to all socket addresses that want to connect to a peer address. might fork. + applies and consumes the following options: + PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT, + PH_CONNECTED, PH_LATE, + OFUNC_OFFSET, + OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC returns 0 on success. */ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, struct sockaddr *them, size_t themlen, - struct opt *opts, int pf, int stype, int proto, + struct opt *opts, int pf, int socktype, int protocol, bool alt, int level) { int fcntl_flags = 0; char infobuff[256]; @@ -144,9 +150,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, int _errno; int result; - if ((xfd->fd = Socket(pf, stype, proto)) < 0) { - Msg4(level, - "socket(%d, %d, %d): %s", pf, stype, proto, strerror(errno)); + if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) { return STAT_RETRYLATER; } @@ -340,7 +344,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, } } - applyopts_fchown(xfd->fd, opts); + applyopts_fchown(xfd->fd, opts); /* OPT_USER, OPT_GROUP */ applyopts(xfd->fd, opts, PH_CONNECTED); applyopts(xfd->fd, opts, PH_LATE); @@ -354,11 +358,16 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, /* a subroutine that is common to all socket addresses that want to connect to a peer address. might fork. + applies and consumes the following option: + PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT, + PH_CONNECTED, PH_LATE, + OFUNC_OFFSET, + OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC returns 0 on success. */ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, struct sockaddr *them, size_t themlen, - struct opt *opts, int pf, int stype, int proto, + struct opt *opts, int pf, int socktype, int protocol, bool alt) { bool dofork = false; struct opt *opts0; @@ -367,7 +376,6 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, int result; retropt_bool(opts, OPT_FORK, &dofork); - retropt_int(opts, OPT_SO_TYPE, &stype); opts0 = copyopts(opts, GROUP_ALL); @@ -384,7 +392,7 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, level = E_ERROR; result = _xioopen_connect(xfd, us, uslen, them, themlen, opts, - pf, stype, proto, alt, level); + pf, socktype, protocol, alt, level); switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -454,7 +462,12 @@ int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, } -/* common to xioopen_udp_sendto, ..unix_sendto, ..rawip */ +/* common to xioopen_udp_sendto, ..unix_sendto, ..rawip + applies and consumes the following option: + PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE + OFUNC_OFFSET + OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC + */ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */ union sockaddr_union *us, socklen_t uslen, struct opt *opts, @@ -464,9 +477,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */ union sockaddr_union la; socklen_t lalen = sizeof(la); char infobuff[256]; - if ((xfd->fd = Socket(pf, socktype, ipproto)) < 0) { - Msg4(level, - "socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); + if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) { return STAT_RETRYLATER; } @@ -590,6 +601,10 @@ void xiosigaction_hasread(int signum, siginfo_t *siginfo, void *ucontext) { This function does not retry. If you need retries, handle this is a loop in the calling function. after fork, we set the forever/retry of the child process to 0 + applies and consumes the following options: + PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD, + PH_CONNECTED, PH_LATE, PH_LATE2 + OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap */ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, struct sockaddr *us, socklen_t uslen, @@ -616,9 +631,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; - if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { - Msg4(level, - "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) { return STAT_RETRYLATER; } @@ -869,9 +882,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags, if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; - if ((xfd->fd = Socket(pf, socktype, proto)) < 0) { - Msg4(level, - "socket(%d, %d, %d): %s", pf, socktype, proto, strerror(errno)); + if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) { return STAT_RETRYLATER; } @@ -1128,3 +1139,41 @@ int xiocheckpeer(xiosingle_t *xfd, } #endif /* _WITH_SOCKET */ + +/* these do sockets internally */ + +/* retrieves options so-type and so-prototype from opts, calls socketpair, and + ev. generates an appropriate error message. + returns 0 on success or -1 if an error occurred. */ +int +xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) { + int result; + + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_int(opts, OPT_SO_PROTOTYPE, &proto); + result = Socket(pf, socktype, proto); + if (result < 0) { + Msg4(msglevel, "socket(%d, %d, %d): %s", + pf, socktype, proto, strerror(errno)); + return -1; + } + return result; +} + +/* retrieves options so-type and so-prototype from opts, calls socketpair, and + ev. generates an appropriate error message. + returns 0 on success or -1 if an error occurred. */ +int +xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) { + int result; + + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_int(opts, OPT_SO_PROTOTYPE, &proto); + result = Socketpair(pf, socktype, proto, sv); + if (result < 0) { + Error5("socketpair(%d, %d, %d, %p): %s", + pf, socktype, proto, sv, strerror(errno)); + return -1; + } + return result; +} diff --git a/xio-socket.h b/xio-socket.h index 04734f9..bcd36b3 100644 --- a/xio-socket.h +++ b/xio-socket.h @@ -1,10 +1,16 @@ /* source: xio-socket.h */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xio_socket_h_included #define __xio_socket_h_included 1 +/* SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more + general purpose */ +#ifndef SO_PROTOTYPE +#define SO_PROTOTYPE 0x9999 +#endif + extern const struct optdesc opt_connect_timeout; extern const struct optdesc opt_so_debug; extern const struct optdesc opt_so_acceptconn; @@ -56,12 +62,14 @@ extern int retropt_socket_pf(struct opt *opts, int *pf); extern int xioopen_connect(struct single *fd, struct sockaddr *us, size_t uslen, struct sockaddr *them, size_t themlen, - struct opt *opts, int pf, int stype, int proto, + struct opt *opts, + int pf, int socktype, int protocol, bool alt); extern int _xioopen_connect(struct single *fd, struct sockaddr *us, size_t uslen, struct sockaddr *them, size_t themlen, - struct opt *opts, int pf, int stype, int proto, + struct opt *opts, + int pf, int socktype, int protocol, bool alt, int level); /* common to xioopen_udp_sendto, ..unix_sendto, ..rawip */ @@ -86,5 +94,9 @@ int xiogetpacketsrc(int fd, union sockaddr_union *pa, socklen_t *palen); extern int xiocheckpeer(xiosingle_t *xfd, union sockaddr_union *pa, union sockaddr_union *la); +extern int +xiosocket(struct opt *opts, int pf, int socktype, int proto, int level); +extern int +xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]); #endif /* !defined(__xio_socket_h_included) */ diff --git a/xio-socks.c b/xio-socks.c index 71c0ded..078f8d5 100644 --- a/xio-socks.c +++ b/xio-socks.c @@ -88,7 +88,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], them, &themlen, us, &uslen, - &needbind, &lowport, &socktype); + &needbind, &lowport, socktype); Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"", targetname, diff --git a/xio-udp.c b/xio-udp.c index 293b8be..9431d8e 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -114,7 +114,6 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, applyopts(-1, opts, PH_INIT); uslen = socket_init(pf, &us); - retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_bind(opts, pf, socktype, IPPROTO_UDP, (struct sockaddr *)&us, &uslen, 1, fd->stream.para.socket.ip.res_opts[1], @@ -176,8 +175,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, union sockaddr_union _sockname; union sockaddr_union *la = &_sockname; /* local address */ - if ((fd->stream.fd = Socket(pf, socktype, ipproto)) < 0) { - Error4("socket(%d, %d, %d): %s", pf, socktype, ipproto, strerror(errno)); + if ((fd->stream.fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) { return STAT_RETRYLATER; } applyopts(fd->stream.fd, opts, PH_PASTSOCKET); @@ -230,7 +228,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, if (xiocheckpeer(&fd->stream, them, la) < 0) { /* drop packet */ char buff[512]; - Recv(fd->stream.fd, buff, sizeof(buff), 0); + Recv(fd->stream.fd, buff, sizeof(buff), 0); /* drop packet */ Close(fd->stream.fd); continue; } @@ -296,6 +294,8 @@ int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, argv[0], argc-1); return STAT_NORETRY; } + + retropt_socket_pf(opts, &pf); if ((result = _xioopen_udp_sendto(argv[1], argv[2], opts, xioflags, xxfd, groups, pf, socktype, ipproto)) != STAT_OK) { @@ -305,6 +305,12 @@ int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, return STAT_OK; } +/* + applies and consumes the following option: + PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE + OFUNC_OFFSET + OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC + */ static int _xioopen_udp_sendto(const char *hostname, const char *servname, struct opt *opts, @@ -318,7 +324,6 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname, int result; xfd->howtoend = END_SHUTDOWN; - retropt_int(opts, OPT_SO_TYPE, &socktype); /* ...res_opts[] */ if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; @@ -405,6 +410,7 @@ int xioopen_udp_datagram(int argc, const char *argv[], struct opt *opts, return STAT_RETRYLATER; } + retropt_socket_pf(opts, &pf); result = _xioopen_udp_sendto(hostname, argv[2], opts, xioflags, xxfd, groups, pf, socktype, ipproto); diff --git a/xio-unix.c b/xio-unix.c index a19ad6c..dfb3b59 100644 --- a/xio-unix.c +++ b/xio-unix.c @@ -62,17 +62,20 @@ const struct optdesc xioopt_unix_tightsocklen = { "unix-tightsocklen", "tight /* fills the socket address struct and returns its effective length. abstract is usually 0; != 0 generates an abstract socket address on Linux. - tight calculates the resulting length from the path length, not from the - struct length. + tight!=0 calculates the resulting length from the path length, not from the + structures length; this is more common. + the struct need not be initialized when calling this function. */ socklen_t -xiosetunix(struct sockaddr_un *saun, +xiosetunix(int pf, + struct sockaddr_un *saun, const char *path, bool abstract, bool tight) { size_t pathlen; socklen_t len; + socket_un_init(saun); #ifdef WITH_ABSTRACT_UNIXSOCKET if (abstract) { if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) { @@ -130,11 +133,10 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i return STAT_NORETRY; } - socket_un_init(&us); - - retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); name = argv[1]; - uslen = xiosetunix(&us, name, abstract, tight); + retropt_socket_pf(opts, &pf); + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + uslen = xiosetunix(pf, &us, name, abstract, tight); xfd->howtoend = END_SHUTDOWN; @@ -151,7 +153,6 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i } applyopts(-1, opts, PH_INIT); - if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; applyopts(-1, opts, PH_EARLY); if (!(ABSTRACT && abstract)) { @@ -170,8 +171,6 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i applyopts_named(name, opts, PH_EARLY); /* umask! */ } - retropt_int(opts, OPT_SO_TYPE, &socktype); - opts0 = copyopts(opts, GROUP_ALL); if ((result = @@ -205,17 +204,15 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } - socket_un_init(&us); - socket_un_init(&them); - - retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); name = argv[1]; - themlen = xiosetunix(&them, name, abstract, tight); + retropt_socket_pf(opts, &pf); + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + themlen = xiosetunix(pf, &them, name, abstract, tight); if (!(ABSTRACT && abstract)) { /* only for non abstract because abstract do not work in file system */ retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); } - if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0) + if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, 0, 0, 0) != STAT_NOACTION) { needbind = true; } @@ -264,16 +261,12 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i return STAT_NORETRY; } - uslen = socket_init(pf, &us); - xfd->salen = socket_init(pf, &xfd->peersa); - - xfd->howtoend = END_SHUTDOWN; - - retropt_int(opts, OPT_SO_TYPE, &socktype); - retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); name = argv[1]; - xfd->salen = xiosetunix(&xfd->peersa.un, name, abstract, tight); + retropt_socket_pf(opts, &pf); + xfd->salen = xiosetunix(pf, &xfd->peersa.un, name, abstract, tight); + + xfd->howtoend = END_SHUTDOWN; if (!(ABSTRACT && abstract)) { /* only for non abstract because abstract do not work in file system */ @@ -282,7 +275,7 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i xfd->dtype = XIODATA_RECVFROM; - if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) + if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 0, 0, 0) != STAT_NOACTION) { needbind = true; } @@ -327,15 +320,14 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } - socket_un_init(&us); - - retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); name = argv[1]; - uslen = xiosetunix(&us, name, abstract, tight); + retropt_socket_pf(opts, &pf); + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + uslen = xiosetunix(pf, &us, name, abstract, tight); xfd->howtoend = END_NONE; - retropt_int(opts, OPT_SO_TYPE, &socktype); - retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); + retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, + 1, 0, 0); if (!(ABSTRACT && abstract)) { /* only for non abstract because abstract do not work in file system */ @@ -362,9 +354,10 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, xfd->para.socket.la.soa.sa_family = pf; xfd->dtype = XIODATA_RECVFROM_ONE; - return _xioopen_dgram_recvfrom(xfd, xioflags, - needbind?(struct sockaddr *)&us:NULL, uslen, - opts, pf, socktype, protocol, E_ERROR); + return + _xioopen_dgram_recvfrom(xfd, xioflags, + needbind?(struct sockaddr *)&us:NULL, uslen, + opts, pf, socktype, protocol, E_ERROR); } @@ -391,13 +384,10 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, return STAT_NORETRY; } - retropt_int(opts, OPT_SO_TYPE, &socktype); - - socket_un_init(&us.un); - - retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); name = argv[1]; - uslen = xiosetunix(&us.un, name, abstract, tight); + retropt_socket_pf(opts, &pf); + retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); + uslen = xiosetunix(pf, &us.un, name, abstract, tight); #if 1 /*!!! why bind option? */ retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 1, 0, 0); @@ -437,8 +427,28 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, 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) { /* we expect the form: filename */ - const char *name; - xiosingle_t *xfd = &xxfd->stream; + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + return + _xioopen_unix_client(&xxfd->stream, xioflags, groups, abstract, opts, + argv[1]); +} + +/* establishes communication with an existing UNIX type socket. supports stream + and datagram socket types: first tries to connect(), but when this fails it + falls back to sendto(). + applies and consumes the following option: + PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, + PH_CONNECTED, PH_LATE, ?PH_CONNECT + OFUNC_OFFSET, + OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND, + OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK, +*/ +int +_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups, + int abstract, struct opt *opts, const char *name) { int pf = PF_UNIX; int socktype = 0; /* to be determined by server socket type */ int protocol = 0; @@ -447,28 +457,24 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i bool tight = true; bool needbind = false; bool opt_unlink_close = false; + struct opt *opts0; int result; - if (argc != 2) { - Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); - } + applyopts(-1, opts, PH_INIT); + if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; xfd->howtoend = END_SHUTDOWN; - retropt_int(opts, OPT_SO_TYPE, &socktype); - - uslen = socket_init(pf, &us); - themlen = socket_init(pf, &them); + retropt_socket_pf(opts, &pf); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); - name = argv[1]; - themlen = xiosetunix(&them.un, name, abstract, tight); + themlen = xiosetunix(pf, &them.un, name, abstract, tight); if (!(ABSTRACT && abstract)) { /* only for non abstract because abstract do not work in file system */ retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); } - if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) + if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 0, 0, 0) != STAT_NOACTION) { needbind = true; } @@ -480,6 +486,9 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i xfd->opt_unlink_close = true; } + /* save options, because we might have to start again */ + opts0 = copyopts(opts, GROUP_ALL); + /* xfd->dtype = DATA_STREAM; // is default */ if ((result = xioopen_connect(xfd, @@ -492,8 +501,7 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i Unlink(us.un.sun_path); } - applyopts(-1, opts, PH_INIT); - if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; + dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0; xfd->peersa = them; xfd->salen = sizeof(struct sockaddr_un); diff --git a/xio-unix.h b/xio-unix.h index 9d9ad51..343bc1a 100644 --- a/xio-unix.h +++ b/xio-unix.h @@ -21,9 +21,14 @@ extern const struct addrdesc xioaddr_abstract_client; extern const struct optdesc xioopt_unix_tightsocklen; extern socklen_t -xiosetunix(struct sockaddr_un *saun, +xiosetunix(int pf, + struct sockaddr_un *saun, const char *path, bool abstract, bool tight); +extern int +_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups, + int abstract, struct opt *opts, const char *name); + #endif /* !defined(__xio_unix_h_included) */ diff --git a/xioopts.c b/xioopts.c index 291f3ae..aea0c2b 100644 --- a/xioopts.c +++ b/xioopts.c @@ -2333,7 +2333,15 @@ int retropt_int(struct opt *opts, int optcode, int *result) { while (opt->desc != ODESC_END) { if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { - *result = opt->value.u_int; + switch (opt->desc->type) { + case TYPE_INT: *result = opt->value.u_int; break; + case TYPE_STRING: *result = strtol(opt->value.u_string, NULL, 0); + break; + default: Error2("cannot convert type %d of option %s to int", + opt->desc->type, opt->desc->defname); + opt->desc = ODESC_ERROR; + return -1; + } opt->desc = ODESC_DONE; return 0; } @@ -2515,7 +2523,7 @@ int retropt_bind(struct opt *opts, { bool tight = false; struct sockaddr_un *s_un = (struct sockaddr_un *)sa; - *salen = xiosetunix(s_un, bindname, false, tight); + *salen = xiosetunix(af, s_un, bindname, false, tight); } break; #endif /* WITH_UNIX */ diff --git a/xioopts.h b/xioopts.h index 849cb46..dfa8ddc 100644 --- a/xioopts.h +++ b/xioopts.h @@ -499,7 +499,8 @@ enum e_optcode { OPT_PIPES, /*OPT_PORT,*/ OPT_PROMPT, /* readline */ - OPT_PROTOCOL_FAMILY, + OPT_PROTOCOL, /* 6=TCP, 17=UDP */ + OPT_PROTOCOL_FAMILY, /* 1=PF_UNIX, 2=PF_INET, 10=PF_INET6 */ OPT_PROXYPORT, OPT_PROXY_AUTHORIZATION, OPT_PROXY_RESOLVE, @@ -593,9 +594,7 @@ enum e_optcode { #ifdef SO_PRIORITY OPT_SO_PRIORITY, #endif -#ifdef SO_PROTOTYPE OPT_SO_PROTOTYPE, -#endif OPT_SO_RCVBUF, OPT_SO_RCVBUF_LATE, #ifdef SO_RCVLOWAT @@ -771,7 +770,8 @@ enum e_optcode { /* keep consistent with xiohelp.c:optionphasenames ! */ enum e_phase { - PH_ALL, /* not for options; use in apply funcs to say "all phases" */ + PH_ALL, /* not for option definitions; use in apply funcs to + say "all phases" */ PH_INIT, /* retrieving info from original state */ PH_EARLY, /* before any other processing */ PH_PREOPEN, /* before file descriptor is created/opened */