merged feature protocol-type

This commit is contained in:
Gerhard Rieger 2008-09-22 22:33:04 +02:00
commit 86c596bd51
23 changed files with 490 additions and 752 deletions

View File

@ -31,6 +31,10 @@ new features:
new address options ipv6-tclass and ipv6-unicast-hops set the related
socket options.
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
@ -78,6 +82,8 @@ further changes:
Makefile now supports datarootdir (thanks to Camillo Lugaresi for
providing the patch)
cleanup in xio-unix.c
####################### V 1.6.0.1:
new features:

View File

@ -1 +1 @@
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar"
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar+protocol"

View File

@ -1590,11 +1590,23 @@ label(OPTION_SNDLOWAT)dit(bf(tt(sndlowat=<bytes>)))
layer will send the data to <bytes> [link(int)(TYPE_INT)].
label(OPTION_SNDTIMEO)dit(bf(tt(sndtimeo=<seconds>)))
Sets the send timeout to seconds [link(timeval)(TYPE_TIMEVAL)].
label(OPTION_TYPE)dit(bf(tt(type=<type>)))
Sets the type of the socket, usually as argument to the code(socket()) or
code(socketpair()) call, to <type> [link(int)(TYPE_INT)].
label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=<string>)))
Forces the use of the specified IP version or protocol. <string> 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=<type>)))
Sets the type of the socket, specified as second argument to the
code(socket()) or code(socketpair()) calls, to <type>
[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 <prototype>
[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)))
@ -1623,8 +1635,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)))
@ -1637,9 +1647,6 @@ COMMENT(label(OPTION_SIOCSPGRP)dit(bf(tt(siocspgrp=<pid_t>)))
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=<string>)))
Forces the use of the specified IP version. <string> can be
something like "ip4" or "ip6".
label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp)))
Sets the SO_TIMESTAMP socket option. This enables receiving and logging of
timestamp ancillary messages.

View File

@ -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"},

82
test.sh
View File

@ -2374,9 +2374,9 @@ N=$((N+1))
#}
NAME=UNIXSOCKET
NAME=UNIXSTREAM
case "$TESTS" in
*%functions%*|*%$NAME%*)
*%functions%*|*%unix%*|*%$NAME%*)
TEST="$NAME: echo via connection to UNIX domain socket"
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
@ -2384,7 +2384,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 </dev/null >$tf 2>"${te}1" &
bg=$! # background process id
@ -8520,82 +8520,6 @@ esac
N=$((N+1))
while read SCM_ENABLE SCM_RECV SCM_TYPE SCM_NAME SCM_VALUE
do
# test: logging of ancillary message with ip-recvopt
NAME=UDP4SCM_$SCM_TYPE
case "$TESTS" in
*%functions%*|*%ip4%*|*%dgram%*|*%udp%*|*%udp4%*|*%recv%*|*%ancillary%*|*%$NAME%*)
#set -vx
TEST="$NAME: IPv4 ancillary messages"
# idea: start a socat process with udp4-recv:..,ip-recvopts and send it a packet
# with IP options (ip-options). check the info log for the appropriate output.
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
ts1p=$PORT; PORT=$((PORT+1))
ts1a="127.0.0.1"
ts1="$ts1a:$ts1p"
CMD0="$SOCAT $opts -d -d -d -u UDP4-RECV:$ts1p,reuseaddr,$SCM_RECV -"
CMD1="$SOCAT $opts -u - UDP4-SENDTO:$ts1,$SCM_ENABLE"
printf "test $F_n $TEST... " $N
# is this option supported?
if $SOCAT -hhh |grep "[[:space:]]$SCM_RECV[[:space:]]" >/dev/null; then
$CMD0 >"$tf" 2>"${te}0" &
pid0="$!"
waitudp4port $ts1p 1
echo "XYZ" |$CMD1 2>>"${te}1"
rc1="$?"
sleep 1
i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done
kill "$pid0" 2>/dev/null; wait
# do not show more messages than requested
case "$opts" in
*-d*-d*-d*-d*) LEVELS="[EWNID]" ;;
*-d*-d*-d*) LEVELS="[EWNI]" ;;
*-d*-d*) LEVELS="[EWN]" ;;
*-d*) LEVELS="[EW]" ;;
*) LEVELS="[E]" ;;
esac
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
echo "$CMD1"
grep " $LEVELS " "${te}0"
grep " $LEVELS " "${te}1"
numFAIL=$((numFAIL+1))
elif ! grep "ancillary message: $SCM_TYPE: $SCM_NAME=$SCM_VALUE" ${te}0 >/dev/null; then
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
grep " $LEVELS " "${te}0"
grep " $LEVELS " "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then
grep " $LEVELS " "${te}0"; echo; grep " $LEVELS " "${te}1";
fi
numOK=$((numOK+1))
fi
else # option is not supported
$PRINTF "${YELLOW}$SCM_RECV not available${NORMAL}\n"
numCANT=$((numCANT+1))
fi # option is not supported
set +vx
;;
esac
N=$((N+1))
done <<<"ip-options=x01000000 ip-recvopts IP_OPTIONS options x01000000
, so-timestamp SCM_TIMESTAMP timestamp $(date '+%a %b %e %H:%M:.. %Y')
ip-ttl=53 ip-recvttl IP_TTL ttl 53
ip-tos=7 ip-recvtos IP_TOS tos 7
, ip-pktinfo IP_PKTINFO locaddr 127.0.0.1
, ip-recvif IP_RECVIF if lo
, ip-recvdstaddr IP_RECVDSTADDR dstaddr 127.0.0.1"
# test: logging of ancillary message
while read PF KEYW ADDR IPPORT SCM_ENABLE SCM_RECV SCM_TYPE SCM_NAME ROOT SCM_VALUE
do

View File

@ -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");

View File

@ -213,6 +213,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;

View File

@ -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;
}
@ -142,7 +142,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,
@ -153,7 +157,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;
@ -162,7 +166,7 @@ int
if ((result =
xiogetaddrinfo(hostname, portname,
*pf, *socktype, protocol,
*pf, socktype, protocol,
(union sockaddr_union *)them, themlen,
res_opts0, res_opts1
))
@ -176,7 +180,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;
@ -205,7 +209,6 @@ int
}
retropt_bool(opts, OPT_LOWPORT, lowport);
retropt_int(opts, OPT_SO_TYPE, socktype);
*opts0 = copyopts(opts, GROUP_ALL);
@ -217,22 +220,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) {
@ -279,7 +284,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;
}

View File

@ -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,

View File

@ -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) {
@ -124,9 +137,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;
}

View File

@ -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') {
@ -431,7 +431,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;
}

View File

@ -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})",

View File

@ -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",

View File

@ -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(":<host>:<protocol>") };
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(":<host>:<protocol>") };
@ -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) {

View File

@ -50,7 +50,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 };
@ -129,9 +129,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
@ -141,15 +141,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];
@ -158,9 +164,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;
}
@ -354,7 +358,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);
@ -368,11 +372,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;
@ -381,7 +390,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);
@ -398,7 +406,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
@ -464,7 +472,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,
@ -474,9 +487,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;
}
@ -600,6 +611,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,
@ -626,9 +641,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;
}
@ -881,9 +894,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;
}
@ -1371,3 +1382,41 @@ int xiosetsockaddrenv(const char *lr,
}
#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;
}

View File

@ -5,6 +5,12 @@
#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;
@ -61,12 +67,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 */
@ -93,6 +101,10 @@ int xiogetpacketsrc(int fd, struct msghdr *msgh);
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]);
extern
int xiosetsockaddrenv(const char *lr, union sockaddr_union *sau, socklen_t salen, int proto);

View File

@ -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,

View File

@ -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;
}
@ -299,6 +297,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) {
@ -308,6 +308,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,
@ -321,7 +327,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;
@ -408,6 +413,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);

View File

@ -15,76 +15,69 @@
#if WITH_UNIX
static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
/* to avoid unneccessary "live" if () conditionals when no abstract support is
compiled in (or at least to give optimizing compilers a good chance) we need
a constant that can be used in C expressions */
#if WITH_ABSTRACT_UNIXSOCKET
# define ABSTRACT 1
#else
# define ABSTRACT 0
#endif
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);
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);
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);
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);
static
int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto);
int xioflags, xiofile_t *xxfd, unsigned groups,
int abstract, int dummy2, int dummy3);
static
int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
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);
/* the first free parameter is 0 for "normal" unix domain sockets, or 1 for
abstract unix sockets (Linux); the second and third free parameter are
unsused */
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>") };
#if WITH_LISTEN
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>") };
#endif /* WITH_LISTEN */
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>") };
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>") };
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>") };
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>") };
#if WITH_ABSTRACT_UNIXSOCKET
static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int dummy2, int dummy3);
static int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
static
int xioopen_abstract_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto);
static
int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
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>") };
#if WITH_LISTEN
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>") };
#endif /* WITH_LISTEN */
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>") };
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>") };
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>") };
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>") };
#endif /* WITH_ABSTRACT_UNIXSOCKET */
const struct addrdesc addr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#if WITH_LISTEN
const struct addrdesc addr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#endif /* WITH_LISTEN */
const struct addrdesc addr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") };
#if WITH_ABSTRACT_UNIXSOCKET
const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_abstract_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_abstract_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#endif /* WITH_LISTEN */
const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_abstract_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_abstract_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_abstract_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_abstract_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") };
#endif /* WITH_ABSTRACT_UNIXSOCKET */
const struct optdesc opt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 };
const struct optdesc xioopt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 };
/* fills the socket address struct and returns its effective length.
abstract is usually 0; != 0 generates an abstract socket address on Linux.
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;
if (!abstract) {
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"",
pathlen, sizeof(saun->sun_path));
}
strncpy(saun->sun_path, path, sizeof(saun->sun_path));
if (tight) {
len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
MIN(pathlen, sizeof(saun->sun_path));
#if HAVE_STRUCT_SOCKADDR_SALEN
saun->sun_len = len;
#endif
} else {
len = sizeof(struct sockaddr_un);
}
} else {
socket_un_init(saun);
#ifdef WITH_ABSTRACT_UNIXSOCKET
if (abstract) {
if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) {
Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"",
pathlen+1, sizeof(saun->sun_path));
@ -100,15 +93,32 @@ xiosetunix(struct sockaddr_un *saun,
} else {
len = sizeof(struct sockaddr_un);
}
return len;
}
#endif /* WITH_ABSTRACT_UNIXSOCKET */
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"",
pathlen, sizeof(saun->sun_path));
}
strncpy(saun->sun_path, path, sizeof(saun->sun_path));
if (tight) {
len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
MIN(pathlen, sizeof(saun->sun_path));
} else {
len = sizeof(struct sockaddr_un);
}
return len;
}
#if WITH_LISTEN
static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
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) {
/* we expect the form: filename */
const char *name;
xiosingle_t *xfd = &xxfd->stream;
int pf = PF_UNIX;
int socktype = SOCK_STREAM;
int protocol = 0;
struct sockaddr_un us;
socklen_t uslen;
bool tight = true;
@ -123,50 +133,50 @@ 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, false, tight);
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((xfd->unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name);
}
xfd->opt_unlink_close = true;
}
retropt_socket_pf(opts, &pf);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
uslen = xiosetunix(pf, &us, name, abstract, tight);
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY);
if (opt_unlink_early) {
if (Unlink(name) < 0) {
if (errno == ENOENT) {
Warn2("unlink(\"%s\"): %s", name, strerror(errno));
} else {
Error2("unlink(\"%s\"): %s", name, strerror(errno));
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((xfd->unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name);
}
xfd->opt_unlink_close = true;
}
}
/* trying to set user-early, perm-early etc. here is useless because
file system entry is available only past bind() call. */
applyopts_named(name, opts, PH_EARLY); /* umask! */
applyopts(-1, opts, PH_INIT);
applyopts(-1, opts, PH_EARLY);
retropt_int(opts, OPT_SO_TYPE, &socktype);
if (!(ABSTRACT && abstract)) {
if (opt_unlink_early) {
if (Unlink(name) < 0) {
if (errno == ENOENT) {
Warn2("unlink(\"%s\"): %s", name, strerror(errno));
} else {
Error2("unlink(\"%s\"): %s", name, strerror(errno));
}
}
}
/* trying to set user-early, perm-early etc. here is useless because
file system entry is available only past bind() call. */
applyopts_named(name, opts, PH_EARLY); /* umask! */
}
opts0 = copyopts(opts, GROUP_ALL);
if ((result =
xioopen_listen(xfd, xioflags,
(struct sockaddr *)&us, uslen,
opts, opts0, PF_UNIX, socktype, 0))
opts, opts0, pf, socktype, protocol))
!= 0)
return result;
return 0;
@ -174,10 +184,13 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
#endif /* WITH_LISTEN */
static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
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) {
/* we expect the form: filename */
const char *name;
struct single *xfd = &xxfd->stream;
int pf = PF_UNIX;
int socktype = SOCK_STREAM;
int protocol = 0;
struct sockaddr_un them, us;
socklen_t themlen, uslen;
bool tight = true;
@ -191,15 +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, false, tight);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0)
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, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
@ -219,7 +232,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype, 0, false)) != 0) {
opts, pf, socktype, protocol, false)) != 0) {
return result;
}
if ((result = _xio_openlate(xfd, opts)) < 0) {
@ -229,13 +242,16 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
}
static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
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) {
/* we expect the form: filename */
const char *name;
xiosingle_t *xfd = &xxfd->stream;
int pf = PF_UNIX;
int socktype = SOCK_DGRAM;
int protocol = 0;
union sockaddr_union us;
socklen_t uslen;
bool tight = true;
int pf = PF_UNIX;
bool needbind = false;
bool opt_unlink_close = false;
@ -245,22 +261,21 @@ 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);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
retropt_socket_pf(opts, &pf);
xfd->salen = xiosetunix(pf, &xfd->peersa.un, name, abstract, tight);
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, false, tight);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
}
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;
}
@ -277,15 +292,21 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0);
opts, xioflags, xfd, groups,
pf, socktype, protocol);
}
static
int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int dummy3) {
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;
int pf = PF_UNIX;
int socktype = SOCK_DGRAM;
int protocol = 0;
struct sockaddr_un us;
socklen_t uslen;
bool tight = true;
@ -299,49 +320,57 @@ 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, false, tight);
retropt_socket_pf(opts, &pf);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
uslen = xiosetunix(pf, &us, name, abstract, tight);
xfd->stream.howtoend = END_NONE;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
xfd->howtoend = END_NONE;
retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
1, 0, 0);
if (opt_unlink_close) {
if ((xfd->stream.unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name);
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((xfd->unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name);
}
xfd->opt_unlink_close = true;
}
xfd->stream.opt_unlink_close = true;
}
if (opt_unlink_early) {
if (Unlink(name) < 0) {
if (errno == ENOENT) {
Warn2("unlink(\"%s\"): %s", name, strerror(errno));
} else {
Error2("unlink(\"%s\"): %s", name, strerror(errno));
if (opt_unlink_early) {
if (Unlink(name) < 0) {
if (errno == ENOENT) {
Warn2("unlink(\"%s\"): %s", name, strerror(errno));
} else {
Error2("unlink(\"%s\"): %s", name, strerror(errno));
}
}
}
}
xfd->stream.para.socket.la.soa.sa_family = pf;
xfd->para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECVFROM_ONE;
return _xioopen_dgram_recvfrom(&xfd->stream, xioflags,
needbind?(struct sockaddr *)&us:NULL, uslen,
opts, pf, socktype, 0, E_ERROR);
xfd->dtype = XIODATA_RECVFROM_ONE;
return
_xioopen_dgram_recvfrom(xfd, xioflags,
needbind?(struct sockaddr *)&us:NULL, uslen,
opts, pf, socktype, protocol, E_ERROR);
}
static
int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto) {
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;
int pf = PF_UNIX;
int socktype = SOCK_DGRAM;
int protocol = 0;
union sockaddr_union us;
socklen_t uslen;
bool tight = true;
@ -355,76 +384,97 @@ 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, false, 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, ipproto, &us.soa, &uslen, 1, 0, 0);
retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 1, 0, 0);
#endif
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
if (opt_unlink_early) {
if (Unlink(name) < 0) {
if (errno == ENOENT) {
Warn2("unlink(\"%s\"): %s", name, strerror(errno));
} else {
Error2("unlink(\"%s\"): %s", name, strerror(errno));
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
if (opt_unlink_early) {
if (Unlink(name) < 0) {
if (errno == ENOENT) {
Warn2("unlink(\"%s\"): %s", name, strerror(errno));
} else {
Error2("unlink(\"%s\"): %s", name, strerror(errno));
}
}
}
}
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) {
if ((xfd->stream.unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name);
if (opt_unlink_close) {
if ((xfd->unlink_close = strdup(name)) == NULL) {
Error1("strdup(\"%s\"): out of memory", name);
}
xfd->opt_unlink_close = true;
}
xfd->stream.opt_unlink_close = true;
}
xfd->stream.para.socket.la.soa.sa_family = pf;
xfd->para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECV;
result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen,
opts, pf, socktype, ipproto, E_ERROR);
xfd->dtype = XIODATA_RECV;
result = _xioopen_dgram_recv(xfd, xioflags, &us.soa, uslen,
opts, pf, socktype, protocol, E_ERROR);
return result;
}
static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
const char *name;
xiosingle_t *xfd = &xxfd->stream;
bool tight = true;
int pf = PF_UNIX;
union sockaddr_union them, us;
socklen_t themlen;
socklen_t uslen;
bool needbind = false;
bool opt_unlink_close = false;
int result;
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 */
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
}
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype);
return
_xioopen_unix_client(&xxfd->stream, xioflags, groups, abstract, opts,
argv[1]);
}
uslen = socket_init(pf, &us);
themlen = socket_init(pf, &them);
/* 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;
union sockaddr_union them, us;
socklen_t themlen, uslen;
bool tight = true;
bool needbind = false;
bool opt_unlink_close = false;
struct opt *opts0;
int result;
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
xfd->howtoend = END_SHUTDOWN;
retropt_socket_pf(opts, &pf);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
themlen = xiosetunix(&them.un, name, false, tight);
themlen = xiosetunix(pf, &them.un, name, abstract, tight);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
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;
}
@ -436,26 +486,29 @@ 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,
needbind?(struct sockaddr *)&us:NULL, uslen,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype?socktype:SOCK_STREAM, 0, false)) != 0) {
opts, pf, socktype?socktype:SOCK_STREAM, protocol,
false)) != 0) {
if (errno == EPROTOTYPE) {
if (needbind) {
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);
if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf,
socktype?socktype:SOCK_DGRAM, 0))
opts, xioflags, xfd, groups,
pf, socktype?socktype:SOCK_DGRAM, protocol))
!= 0) {
return result;
}
@ -469,278 +522,6 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
}
#if WITH_ABSTRACT_UNIXSOCKET
#if WITH_LISTEN
static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
/* we expect the form: filename */
const char *name;
xiosingle_t *xfd = &xxfd->stream;
bool tight = true;
struct sockaddr_un us;
socklen_t uslen;
struct opt *opts0 = NULL;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
socket_un_init(&us);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
uslen = xiosetunix(&us, name, true, tight);
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY);
/* trying to set user-early, perm-early etc. here is useless because
file system entry is available only past bind() call. */
retropt_int(opts, OPT_SO_TYPE, &socktype);
opts0 = copyopts(opts, GROUP_ALL);
if ((result =
xioopen_listen(xfd, xioflags,
(struct sockaddr *)&us, uslen,
opts, opts0, PF_UNIX, socktype, 0))
!= 0)
return result;
return 0;
}
#endif /* WITH_LISTEN */
static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
/* we expect the form: filename */
const char *name;
struct single *xfd = &xxfd->stream;
bool tight = true;
struct sockaddr_un them, us;
socklen_t themlen, uslen;
bool needbind = false;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
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, true, tight);
if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY);
if ((result =
xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype, 0, false)) != 0) {
return result;
}
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;
}
return 0;
}
static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
const char *name;
xiosingle_t *xfd = &xxfd->stream;
union sockaddr_union us;
socklen_t uslen;
bool tight = true;
int pf = PF_UNIX;
bool needbind = false;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
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, true, tight);
xfd->dtype = XIODATA_RECVFROM;
if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0);
}
static
int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int dummy3) {
const char *name;
struct sockaddr_un us;
socklen_t uslen;
bool tight = true;
bool needbind = true;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
socket_un_init(&us);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
uslen = xiosetunix(&us, name, true, tight);
xfd->stream.howtoend = END_NONE;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
xfd->stream.para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECVFROM_ONE;
return _xioopen_dgram_recvfrom(&xfd->stream, xioflags,
needbind?(struct sockaddr *)&us:NULL, uslen,
opts, pf, socktype, 0, E_ERROR);
}
static
int xioopen_abstract_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto) {
const char *name;
union sockaddr_union us;
socklen_t uslen;
bool tight = true;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
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, true, tight);
#if 1 /*!!! why bind option? */
retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, 0, 0);
#endif
xfd->stream.para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECV;
result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen,
opts, pf, socktype, ipproto, E_ERROR);
return result;
}
static int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
const char *name;
xiosingle_t *xfd = &xxfd->stream;
bool tight = true;
int pf = PF_UNIX;
union sockaddr_union them, us;
socklen_t themlen;
socklen_t uslen;
bool needbind = false;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
}
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype);
uslen = socket_init(pf, &us);
themlen = socket_init(pf, &them);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
themlen = xiosetunix(&them.un, name, true, tight);
if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
/* xfd->dtype = DATA_STREAM; // is default */
if ((result =
xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype?socktype:SOCK_STREAM, 0, false)) != 0) {
if (errno == EPROTOTYPE) {
if (needbind) {
Unlink(us.un.sun_path);
}
/* ...res_opts[] */
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
xfd->peersa = them;
xfd->salen = themlen;
if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf,
socktype?socktype:SOCK_DGRAM, 0))
!= 0) {
return result;
}
xfd->dtype = XIODATA_RECVFROM;
}
}
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;
}
return 0;
}
#endif /* WITH_ABSTRACT_UNIXSOCKET */
/* returns information that can be used for constructing an environment
variable describing the socket address.
if idx is 0, this function writes "ADDR" into namebuff and the path into

View File

@ -5,12 +5,12 @@
#ifndef __xio_unix_h_included
#define __xio_unix_h_included 1
extern const struct addrdesc addr_unix_connect;
extern const struct addrdesc addr_unix_listen;
extern const struct addrdesc addr_unix_sendto;
extern const struct addrdesc addr_unix_recvfrom;
extern const struct addrdesc addr_unix_recv;
extern const struct addrdesc addr_unix_client;
extern const struct addrdesc xioaddr_unix_connect;
extern const struct addrdesc xioaddr_unix_listen;
extern const struct addrdesc xioaddr_unix_sendto;
extern const struct addrdesc xioaddr_unix_recvfrom;
extern const struct addrdesc xioaddr_unix_recv;
extern const struct addrdesc xioaddr_unix_client;
extern const struct addrdesc xioaddr_abstract_connect;
extern const struct addrdesc xioaddr_abstract_listen;
extern const struct addrdesc xioaddr_abstract_sendto;
@ -18,10 +18,11 @@ extern const struct addrdesc xioaddr_abstract_recvfrom;
extern const struct addrdesc xioaddr_abstract_recv;
extern const struct addrdesc xioaddr_abstract_client;
extern const struct optdesc opt_unix_tightsocklen;
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);
@ -30,4 +31,8 @@ xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
char *valuebuff, size_t valuelen,
struct sockaddr_un *sa, socklen_t salen, int ipproto);
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) */

View File

@ -106,7 +106,7 @@ const struct addrname addressnames[] = {
#endif
#endif /* WITH_RAWIP */
#if WITH_UNIX
{ "local", &addr_unix_connect },
{ "local", &xioaddr_unix_connect },
#endif
#if WITH_FILE
{ "open", &addr_open },
@ -231,19 +231,19 @@ const struct addrname addressnames[] = {
{ "udp6-sendto", &addr_udp6_sendto },
#endif
#if WITH_UNIX
{ "unix", &addr_unix_client },
{ "unix-client", &addr_unix_client },
{ "unix-connect", &addr_unix_connect },
{ "unix", &xioaddr_unix_client },
{ "unix-client", &xioaddr_unix_client },
{ "unix-connect", &xioaddr_unix_connect },
#endif
#if WITH_UNIX && WITH_LISTEN
{ "unix-l", &addr_unix_listen },
{ "unix-listen", &addr_unix_listen },
{ "unix-l", &xioaddr_unix_listen },
{ "unix-listen", &xioaddr_unix_listen },
#endif
#if WITH_UNIX
{ "unix-recv", &addr_unix_recv },
{ "unix-recvfrom", &addr_unix_recvfrom },
{ "unix-send", &addr_unix_sendto },
{ "unix-sendto", &addr_unix_sendto },
{ "unix-recv", &xioaddr_unix_recv },
{ "unix-recvfrom", &xioaddr_unix_recvfrom },
{ "unix-send", &xioaddr_unix_sendto },
{ "unix-sendto", &xioaddr_unix_sendto },
#endif
#else /* !0 */
# if WITH_INTEGRATE

View File

@ -1502,7 +1502,7 @@ const struct optname optionnames[] = {
#ifdef O_TEXT
IF_ANY ("text", &opt_o_text)
#endif
IF_UNIX ("tightsocklen", &opt_unix_tightsocklen)
IF_UNIX ("tightsocklen", &xioopt_unix_tightsocklen)
IF_TERMIOS("time", &opt_vtime)
#ifdef SO_TIMESTAMP
IF_SOCKET ("timestamp", &opt_so_timestamp)
@ -1533,7 +1533,7 @@ const struct optname optionnames[] = {
IF_ANY ("uid-l", &opt_user_late)
IF_NAMED ("umask", &opt_umask)
IF_IP6 ("unicast-hops", &opt_ipv6_unicast_hops)
IF_UNIX ("unix-tightsocklen", &opt_unix_tightsocklen)
IF_UNIX ("unix-tightsocklen", &xioopt_unix_tightsocklen)
IF_NAMED ("unlink", &opt_unlink)
IF_NAMED ("unlink-close", &opt_unlink_close)
IF_NAMED ("unlink-early", &opt_unlink_early)
@ -2398,7 +2398,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;
}
@ -2580,7 +2588,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 */

View File

@ -521,7 +521,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,
@ -615,9 +616,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
@ -794,7 +793,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 */