mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
Combined Bind() calls in xiobind(); fixed UDP-SENDTO lowport bug
This commit is contained in:
parent
56a56e127c
commit
d8ee49007e
8 changed files with 194 additions and 180 deletions
4
CHANGES
4
CHANGES
|
@ -27,6 +27,10 @@ Corrections:
|
||||||
The rawer option failed because it tried to clear CREAD.
|
The rawer option failed because it tried to clear CREAD.
|
||||||
Test: RAWER
|
Test: RAWER
|
||||||
|
|
||||||
|
UDP-SEND and UPD-SENDTO with option lowport always bound to port 1
|
||||||
|
instead of a free port in range 640..1023
|
||||||
|
Test: UDP_LOWPORT
|
||||||
|
|
||||||
Porting:
|
Porting:
|
||||||
OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
|
OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
|
||||||
conditions: client connection to server with certificate with empty
|
conditions: client connection to server with certificate with empty
|
||||||
|
|
41
test.sh
41
test.sh
|
@ -15496,6 +15496,47 @@ esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
# Up to 1.7.4.3 there was a bug with the lowport option:
|
||||||
|
# Active addresses UDP-SEND, UDP-SENDTO always bound to port 1 instead of
|
||||||
|
# 640..1023
|
||||||
|
NAME=UDP_LOWPORT
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: UDP4-SEND with lowport"
|
||||||
|
# Run Socat with UDP4-SEND:...,lowport and full logging and check the
|
||||||
|
# parameters of bind() call. It port is in the range 640..1023 the test
|
||||||
|
# succeeded.
|
||||||
|
if ! eval $NUMCOND; then :; else
|
||||||
|
tf="$td/test$N.stdout"
|
||||||
|
te="$td/test$N.stderr"
|
||||||
|
tdiff="$td/test$N.diff"
|
||||||
|
da="test$N $(date) $RANDOM"
|
||||||
|
CMD="$TRACE $SOCAT $opts -d -d -d -d /dev/null UDP4-SENDTO:$LOCALHOST:$PORT,lowport"
|
||||||
|
printf "test $F_n $TEST... " $N
|
||||||
|
$CMD >/dev/null 2>"${te}"
|
||||||
|
rc1=$?
|
||||||
|
LOWPORT=$(grep 'D bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\),.*/\1/')
|
||||||
|
#echo "LOWPORT=\"$LOWPORT\"" >&2
|
||||||
|
#type socat >&2
|
||||||
|
if [[ $LOWPORT =~ [0-9][0-9]* ]] && [ "$LOWPORT" -ge 640 -a "$LOWPORT" -le 1023 ]; then
|
||||||
|
$PRINTF "$OK\n"
|
||||||
|
if [ "$VERBOSE" ]; then
|
||||||
|
echo "$CMD" >&2
|
||||||
|
fi
|
||||||
|
numOK=$((numOK+1))
|
||||||
|
else
|
||||||
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD" >&2
|
||||||
|
cat "${te}" >&2
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
fi
|
||||||
|
fi # NUMCOND
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
PORT=$((PORT+1))
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
# end of common tests
|
# end of common tests
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
|
|
@ -69,7 +69,7 @@ int _xioopen_interface(const char *ifname,
|
||||||
|
|
||||||
return
|
return
|
||||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, xfd, groups, pf, socktype, 0);
|
opts, xioflags, xfd, groups, pf, socktype, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
|
@ -143,7 +143,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, xfd, groups, *pf, socktype, ipproto);
|
opts, xioflags, xfd, groups, *pf, socktype, ipproto, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
301
xio-socket.c
301
xio-socket.c
|
@ -63,6 +63,14 @@ xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
|
||||||
char *nambuff, int namlen,
|
char *nambuff, int namlen,
|
||||||
char *envbuff, int envlen,
|
char *envbuff, int envlen,
|
||||||
char *valbuff, int vallen);
|
char *valbuff, int vallen);
|
||||||
|
static int xiobind(
|
||||||
|
struct single *xfd,
|
||||||
|
union sockaddr_union *us,
|
||||||
|
size_t uslen,
|
||||||
|
struct opt *opts,
|
||||||
|
int pf,
|
||||||
|
bool alt,
|
||||||
|
int level);
|
||||||
|
|
||||||
|
|
||||||
#if WITH_GENERICSOCKET
|
#if WITH_GENERICSOCKET
|
||||||
|
@ -457,7 +465,7 @@ int _xioopen_socket_sendto(const char *pfname, const char *type,
|
||||||
|
|
||||||
return
|
return
|
||||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, xfd, groups, pf, socktype, proto);
|
opts, xioflags, xfd, groups, pf, socktype, proto, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -775,111 +783,9 @@ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
|
||||||
|
|
||||||
applyopts_cloexec(xfd->fd, opts);
|
applyopts_cloexec(xfd->fd, opts);
|
||||||
|
|
||||||
#if WITH_UNIX
|
if (xiobind(xfd, us, uslen, opts, pf, alt, level) < 0) {
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
return -1;
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
|
||||||
#if WITH_TCP || WITH_UDP
|
|
||||||
if (alt) {
|
|
||||||
union sockaddr_union sin, *sinp;
|
|
||||||
unsigned short *port, i, N;
|
|
||||||
div_t dv;
|
|
||||||
|
|
||||||
/* prepare sockaddr for bind probing */
|
|
||||||
if (us) {
|
|
||||||
sinp = us;
|
|
||||||
} else {
|
|
||||||
if (them->sa_family == AF_INET) {
|
|
||||||
socket_in_init(&sin.ip4);
|
|
||||||
#if WITH_IP6
|
|
||||||
} else {
|
|
||||||
socket_in6_init(&sin.ip6);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
sinp = &sin;
|
|
||||||
}
|
|
||||||
if (them->sa_family == AF_INET) {
|
|
||||||
port = &sin.ip4.sin_port;
|
|
||||||
#if WITH_IP6
|
|
||||||
} else if (them->sa_family == AF_INET6) {
|
|
||||||
port = &sin.ip6.sin6_port;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
port = 0; /* just to make compiler happy */
|
|
||||||
}
|
|
||||||
/* combine random+step variant to quickly find a free port when only
|
|
||||||
few are in use, and certainly find a free port in defined time even
|
|
||||||
if there are almost all in use */
|
|
||||||
/* dirt 1: having tcp/udp code in socket function */
|
|
||||||
/* dirt 2: using a time related system call for init of random */
|
|
||||||
{
|
|
||||||
/* generate a random port, with millisecond random init */
|
|
||||||
#if 0
|
|
||||||
struct timeb tb;
|
|
||||||
ftime(&tb);
|
|
||||||
srandom(tb.time*1000+tb.millitm);
|
|
||||||
#else
|
|
||||||
struct timeval tv;
|
|
||||||
struct timezone tz;
|
|
||||||
tz.tz_minuteswest = 0;
|
|
||||||
tz.tz_dsttime = 0;
|
|
||||||
if ((result = Gettimeofday(&tv, &tz)) < 0) {
|
|
||||||
Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
|
|
||||||
}
|
|
||||||
srandom(tv.tv_sec*1000000+tv.tv_usec);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
|
|
||||||
i = N = XIO_IPPORT_LOWER + dv.rem;
|
|
||||||
do { /* loop over lowport bind() attempts */
|
|
||||||
*port = htons(i);
|
|
||||||
if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
|
|
||||||
Msg4(errno==EADDRINUSE?E_INFO:level,
|
|
||||||
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
|
||||||
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
|
||||||
sizeof(*sinp), strerror(errno));
|
|
||||||
if (errno != EADDRINUSE) {
|
|
||||||
Close(xfd->fd);
|
|
||||||
return STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break; /* could bind to port, good, continue past loop */
|
|
||||||
}
|
|
||||||
--i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
|
|
||||||
if (i == N) {
|
|
||||||
Msg(level, "no low port available");
|
|
||||||
/*errno = EADDRINUSE; still assigned */
|
|
||||||
Close(xfd->fd);
|
|
||||||
return STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
} while (i != N);
|
|
||||||
} else
|
|
||||||
#endif /* WITH_TCP || WITH_UDP */
|
|
||||||
|
|
||||||
if (us) {
|
|
||||||
#if WITH_UNIX
|
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (Bind(xfd->fd, &us->soa, uslen) < 0) {
|
|
||||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
|
||||||
xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
|
||||||
uslen, strerror(errno));
|
|
||||||
Close(xfd->fd);
|
|
||||||
return STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if WITH_UNIX
|
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_CONNECT);
|
applyopts(xfd->fd, opts, PH_CONNECT);
|
||||||
|
|
||||||
|
@ -1116,7 +1022,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
||||||
union sockaddr_union *us, socklen_t uslen,
|
union sockaddr_union *us, socklen_t uslen,
|
||||||
struct opt *opts,
|
struct opt *opts,
|
||||||
int xioflags, xiosingle_t *xfd, unsigned groups,
|
int xioflags, xiosingle_t *xfd, unsigned groups,
|
||||||
int pf, int socktype, int ipproto) {
|
int pf, int socktype, int ipproto, bool alt) {
|
||||||
int level = E_ERROR;
|
int level = E_ERROR;
|
||||||
union sockaddr_union la; socklen_t lalen = sizeof(la);
|
union sockaddr_union la; socklen_t lalen = sizeof(la);
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
|
@ -1138,30 +1044,9 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
||||||
|
|
||||||
applyopts_cloexec(xfd->fd, opts);
|
applyopts_cloexec(xfd->fd, opts);
|
||||||
|
|
||||||
#if WITH_UNIX
|
if (xiobind(xfd, us, uslen, opts, pf, alt, level) < 0) {
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
return -1;
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
|
||||||
|
|
||||||
if (us) {
|
|
||||||
if (Bind(xfd->fd, &us->soa, uslen) < 0) {
|
|
||||||
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
|
|
||||||
xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
|
||||||
uslen, strerror(errno));
|
|
||||||
Close(xfd->fd);
|
|
||||||
return STAT_RETRYLATER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if WITH_UNIX
|
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
|
||||||
|
|
||||||
/*applyopts(xfd->fd, opts, PH_CONNECT);*/
|
/*applyopts(xfd->fd, opts, PH_CONNECT);*/
|
||||||
|
|
||||||
|
@ -1333,25 +1218,16 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||||
|
|
||||||
applyopts_cloexec(xfd->fd, opts);
|
applyopts_cloexec(xfd->fd, opts);
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
if (xiobind(xfd, (union sockaddr_union *)us, uslen,
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
opts, pf, 0, level) < 0) {
|
||||||
if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
|
return -1;
|
||||||
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
|
|
||||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
|
||||||
strerror(errno));
|
|
||||||
Close(xfd->fd);
|
|
||||||
return STAT_RETRYLATER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||||
|
|
||||||
#if WITH_UNIX
|
#if WITH_UNIX
|
||||||
if (pf == AF_UNIX && us != NULL) {
|
if (pf == AF_UNIX && us != NULL) {
|
||||||
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
|
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
|
||||||
#if WITH_UNIX
|
|
||||||
if (pf == AF_UNIX && us != NULL) {
|
|
||||||
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
||||||
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
|
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
|
||||||
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
|
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
|
||||||
|
@ -1592,7 +1468,6 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
||||||
struct opt *opts, int pf, int socktype, int proto,
|
struct opt *opts, int pf, int socktype, int proto,
|
||||||
int level) {
|
int level) {
|
||||||
char *rangename;
|
char *rangename;
|
||||||
char infobuff[256];
|
|
||||||
|
|
||||||
if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||||
|
|
||||||
|
@ -1605,26 +1480,13 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
||||||
|
|
||||||
applyopts_cloexec(xfd->fd, opts);
|
applyopts_cloexec(xfd->fd, opts);
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
if (xiobind(xfd, (union sockaddr_union *)us, uslen, opts, pf, 0, level) < 0) {
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
return -1;
|
||||||
if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
|
|
||||||
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
|
|
||||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
|
||||||
strerror(errno));
|
|
||||||
Close(xfd->fd);
|
|
||||||
return STAT_RETRYLATER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WITH_UNIX
|
#if WITH_UNIX
|
||||||
if (pf == AF_UNIX && us != NULL) {
|
if (pf == AF_UNIX && us != NULL) {
|
||||||
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
|
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
applyopts_single(xfd, opts, PH_PASTBIND);
|
|
||||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
|
||||||
#if WITH_UNIX
|
|
||||||
if (pf == AF_UNIX && us != NULL) {
|
|
||||||
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
/*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
|
||||||
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
|
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
|
||||||
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
|
applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
|
||||||
|
@ -2262,3 +2124,124 @@ xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xiobind(
|
||||||
|
struct single *xfd,
|
||||||
|
union sockaddr_union *us,
|
||||||
|
size_t uslen,
|
||||||
|
struct opt *opts,
|
||||||
|
int pf,
|
||||||
|
bool alt,
|
||||||
|
int level)
|
||||||
|
{
|
||||||
|
char infobuff[256];
|
||||||
|
int result;
|
||||||
|
|
||||||
|
#if WITH_UNIX
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||||
|
applyopts(xfd->fd, opts, PH_BIND);
|
||||||
|
#if WITH_TCP || WITH_UDP
|
||||||
|
if (alt) {
|
||||||
|
union sockaddr_union sin, *sinp;
|
||||||
|
unsigned short *port, i, N;
|
||||||
|
div_t dv;
|
||||||
|
|
||||||
|
/* prepare sockaddr for bind probing */
|
||||||
|
if (us) {
|
||||||
|
sinp = us;
|
||||||
|
} else {
|
||||||
|
if (pf == AF_INET) {
|
||||||
|
socket_in_init(&sin.ip4);
|
||||||
|
#if WITH_IP6
|
||||||
|
} else {
|
||||||
|
socket_in6_init(&sin.ip6);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
sinp = &sin;
|
||||||
|
}
|
||||||
|
if (pf == AF_INET) {
|
||||||
|
port = &sin.ip4.sin_port;
|
||||||
|
#if WITH_IP6
|
||||||
|
} else if (pf == AF_INET6) {
|
||||||
|
port = &sin.ip6.sin6_port;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
port = 0; /* just to make compiler happy */
|
||||||
|
}
|
||||||
|
/* combine random+step variant to quickly find a free port when only
|
||||||
|
few are in use, and certainly find a free port in defined time even
|
||||||
|
if there are almost all in use */
|
||||||
|
/* dirt 1: having tcp/udp code in socket function */
|
||||||
|
/* dirt 2: using a time related system call for init of random */
|
||||||
|
{
|
||||||
|
/* generate a random port, with millisecond random init */
|
||||||
|
#if 0
|
||||||
|
struct timeb tb;
|
||||||
|
ftime(&tb);
|
||||||
|
srandom(tb.time*1000+tb.millitm);
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
struct timezone tz;
|
||||||
|
tz.tz_minuteswest = 0;
|
||||||
|
tz.tz_dsttime = 0;
|
||||||
|
if ((result = Gettimeofday(&tv, &tz)) < 0) {
|
||||||
|
Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
|
||||||
|
}
|
||||||
|
srandom(tv.tv_sec*1000000+tv.tv_usec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* Note: IPPORT_RESERVED is from includes, 1024 */
|
||||||
|
dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
|
||||||
|
i = N = XIO_IPPORT_LOWER + dv.rem;
|
||||||
|
do { /* loop over lowport bind() attempts */
|
||||||
|
*port = htons(i);
|
||||||
|
if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
|
||||||
|
Msg4(errno==EADDRINUSE?E_INFO:level,
|
||||||
|
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
||||||
|
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
||||||
|
sizeof(*sinp), strerror(errno));
|
||||||
|
if (errno != EADDRINUSE) {
|
||||||
|
Close(xfd->fd);
|
||||||
|
return STAT_RETRYLATER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break; /* could bind to port, good, continue past loop */
|
||||||
|
}
|
||||||
|
--i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
|
||||||
|
if (i == N) {
|
||||||
|
Msg(level, "no low port available");
|
||||||
|
/*errno = EADDRINUSE; still assigned */
|
||||||
|
Close(xfd->fd);
|
||||||
|
return STAT_RETRYLATER;
|
||||||
|
}
|
||||||
|
} while (i != N);
|
||||||
|
} else
|
||||||
|
#endif /* WITH_TCP || WITH_UDP */
|
||||||
|
|
||||||
|
if (us) {
|
||||||
|
#if WITH_UNIX
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (Bind(xfd->fd, &us->soa, uslen) < 0) {
|
||||||
|
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||||
|
xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||||
|
uslen, strerror(errno));
|
||||||
|
Close(xfd->fd);
|
||||||
|
return STAT_RETRYLATER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if WITH_UNIX
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
||||||
union sockaddr_union *us, socklen_t uslen,
|
union sockaddr_union *us, socklen_t uslen,
|
||||||
struct opt *opts,
|
struct opt *opts,
|
||||||
int xioflags, xiosingle_t *xfd, unsigned groups,
|
int xioflags, xiosingle_t *xfd, unsigned groups,
|
||||||
int pf, int socktype, int ipproto);
|
int pf, int socktype, int ipproto, bool alt);
|
||||||
extern
|
extern
|
||||||
int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||||
struct sockaddr *us, socklen_t uslen,
|
struct sockaddr *us, socklen_t uslen,
|
||||||
|
|
18
xio-udp.c
18
xio-udp.c
|
@ -410,26 +410,12 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname,
|
||||||
}
|
}
|
||||||
|
|
||||||
retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport);
|
retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport);
|
||||||
if (xfd->para.socket.ip.lowport) {
|
|
||||||
switch (pf) {
|
|
||||||
#if WITH_IP4
|
|
||||||
case PF_INET:
|
|
||||||
/*!!! this is buggy */
|
|
||||||
us.ip4.sin_port = htons(xfd->para.socket.ip.lowport); break;
|
|
||||||
#endif
|
|
||||||
#if WITH_IP6
|
|
||||||
case PF_INET6:
|
|
||||||
/*!!! this is buggy */
|
|
||||||
us.ip6.sin6_port = htons(xfd->para.socket.ip.lowport); break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
needbind = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
xfd->dtype = XIODATA_RECVFROM;
|
xfd->dtype = XIODATA_RECVFROM;
|
||||||
return _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
return _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, xfd, groups,
|
opts, xioflags, xfd, groups,
|
||||||
pf, socktype, ipproto);
|
pf, socktype, ipproto,
|
||||||
|
xfd->para.socket.ip.lowport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -411,7 +411,7 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
|
||||||
return
|
return
|
||||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, xfd, groups,
|
opts, xioflags, xfd, groups,
|
||||||
pf, socktype, protocol);
|
pf, socktype, protocol, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -690,7 +690,7 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||||
if ((result =
|
if ((result =
|
||||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, xfd, groups,
|
opts, xioflags, xfd, groups,
|
||||||
pf, SOCK_DGRAM, protocol))
|
pf, SOCK_DGRAM, protocol, 0))
|
||||||
== 0) {
|
== 0) {
|
||||||
xfd->dtype = XIODATA_RECVFROM;
|
xfd->dtype = XIODATA_RECVFROM;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue