added test SETSOCKOPT_INT; some corrections on generic ioctl and setsockopt features

This commit is contained in:
Gerhard Rieger 2008-08-12 07:30:10 +02:00
parent 140443794b
commit 8947cc92dc
7 changed files with 180 additions and 134 deletions

76
test.sh
View file

@ -8450,7 +8450,7 @@ N=$((N+1))
# test the generic ioctl-void option
NAME=IOCTL_VOID
case "$TESTS" in
*%functions%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
*%functions%*|*%pty%*|*%generic%*|*%$NAME%*)
TEST="$NAME: test the ioctl-void option"
# there are not many ioctls that apply to non global resources and do not
# require root. TIOCEXCL seems to fit:
@ -8459,7 +8459,7 @@ TEST="$NAME: test the ioctl-void option"
# process 2 opens it too and fails with "device or resource busy" only when the
# previous ioctl was successful
if [ "$UNAME" != Linux ]; then
# we need access to more loopback addresses
# we use the numeric value of TIOCEXL which is system dependent
$PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
@ -8482,7 +8482,7 @@ $CMD2 >/dev/null 2>"${te}2" </dev/null
rc2=$?
kill $pid0 $pid1 2>/dev/null; wait
if ! echo "$da" |diff - "$tf"; then
$PRINTF "${YELLOW}phase 1 failed{NORMAL}\n"
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
echo "$CMD0 &"
echo "$CMD1"
numCANT=$((numCANT+1))
@ -8501,6 +8501,76 @@ fi
fi # !Linux
;;
esac
N=$((N+1))
# test the generic setsockopt-int option
NAME=SETSOCKOPT_INT
case "$TESTS" in
*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*)
TEST="$NAME: test the setsockopt-int option"
# there are not many socket options that apply to non global resources, do not
# require root, do not require a network connection, and can easily be
# tested. SO_REUSEADDR seems to fit:
# process 0 provides a tcp listening socket with reuseaddr;
# process 1 connects to this port; thus the port is connected but no longer
# listening
# process 2 tries to listen on this port with SO_REUSEADDR, will fail if the
# (generically specified) SO_REUSEADDR socket options did not work
# process 3 connects to this port; only if it is successful the test is ok
if [ "$UNAME" != Linux ]; then
# we use the numeric value of SO_REUSEADDR which might be system dependent
$PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tp="$PORT"
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="$(date)"
# level=SOL_SOCKET=1, optname=SO_REUSEADDR=2, value=1
CMD0="$SOCAT $opts TCP4-L:$tp,setsockopt-int=1:2:1 PIPE"
CMD1="$SOCAT $opts - TCP:localhost:$tp"
CMD2="$CMD0"
CMD3="$CMD1"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waittcp4port $tp 1
(echo "$da"; sleep 3) |$CMD1 >"$tf" 2>"${te}1" & # this should always work
pid1=$!
usleep 1000000
$CMD2 >/dev/null 2>"${te}2" &
pid2=$!
waittcp4port $tp 1
(echo "$da") |$CMD3 >"${tf}3" 2>"${te}3"
rc3=$?
kill $pid0 $pid1 $pid2 2>/dev/null; wait
if ! echo "$da" |diff - "$tf"; then
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
echo "$CMD0 &"
echo "$CMD1"
numCANT=$((numCANT+1))
elif [ $rc3 -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD2 &"
echo "$CMD3"
cat "${te}2" "${te}3"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "${tf}3"; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD2 &"
echo "$CMD3"
echo "$da" |diff - "${tf}3"
numCANT=$((numCANT+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2" "${te}3"; fi
numOK=$((numOK+1))
fi
fi # !Linux
;;
esac
PORT=$((PORT+1))
N=$((N+1))

View file

@ -77,8 +77,8 @@ const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRIT
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE };
/****** generic ioctl() options ******/
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_int = { "ioctl-int", NULL, OPT_IOCTL_INT, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_intp = { "ioctl-intp", NULL, OPT_IOCTL_INTP, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_bin = { "ioctl-bin", NULL, OPT_IOCTL_BIN, GROUP_FD, PH_FD, TYPE_INT_BIN, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_string = { "ioctl-string",NULL, OPT_IOCTL_STRING,GROUP_FD, PH_FD, TYPE_INT_STRING,OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_int = { "ioctl-int", NULL, OPT_IOCTL_INT, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_intp = { "ioctl-intp", NULL, OPT_IOCTL_INTP, GROUP_FD, PH_FD, TYPE_INT_INTP, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_bin = { "ioctl-bin", NULL, OPT_IOCTL_BIN, GROUP_FD, PH_FD, TYPE_INT_BIN, OFUNC_IOCTL_GENERIC, 0, 0, 0 };
const struct optdesc opt_ioctl_string = { "ioctl-string",NULL, OPT_IOCTL_STRING,GROUP_FD, PH_FD, TYPE_INT_STRING,OFUNC_IOCTL_GENERIC, 0, 0, 0 };

View file

@ -129,9 +129,9 @@ const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNEC
const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
/* generic setsockopt() options */
const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_INT, OFUNC_SPEC, 0, 0 };
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SPEC, 0, 0 };
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SPEC, 0, 0 };
const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_INT, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
/* a subroutine that is common to all socket addresses that want to connect

View file

@ -1,5 +1,5 @@
/* source: xio-socket.h */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_socket_h_included

View file

@ -29,7 +29,8 @@ static const char *optiontypenames[] = {
"STRUCT-IP_MREQ",
#endif
"IP4NAME",
"INT:INT", "INT:BIN", "INT:STRING",
"INT:INT", "INT:INTP", "INT:BIN", "INT:STRING",
"INT:INT:INT", "INT:INT:BIN", "INT:INT:STRING",
} ;

191
xioopts.c
View file

@ -1313,6 +1313,9 @@ const struct optname optionnames[] = {
#ifdef SO_USELOOPBACK /* AIX433, Solaris */
IF_SOCKET ("so-useloopback", &opt_so_useloopback)
#endif /* SO_USELOOPBACK */
IF_SOCKET ("sockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("sockopt-int", &opt_setsockopt_int)
IF_SOCKET ("sockopt-string", &opt_setsockopt_string)
IF_SOCKS4 ("socksport", &opt_socksport)
IF_SOCKS4 ("socksuser", &opt_socksuser)
IF_IPAPP ("sourceport", &opt_sourceport)
@ -2761,6 +2764,48 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
opt->desc = ODESC_ERROR; ++opt; continue;
}
} else if (opt->desc->func == OFUNC_IOCTL_GENERIC) {
switch (opt->desc->type) {
case TYPE_INT:
if (Ioctl(fd, opt->value.u_int, NULL) < 0) {
Error3("ioctl(%d, 0x%x, NULL): %s",
fd, opt->value.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_INT:
if (Ioctl_int(fd, opt->value.u_int, opt->value2.u_int) < 0) {
Error4("ioctl(%d, %d, %p): %s",
fd, opt->value.u_int, opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_INTP:
if (Ioctl(fd, opt->value.u_int, (void *)&opt->value2.u_int) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)&opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_BIN:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
case TYPE_INT_STRING:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_string) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_string, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented",
opt->desc->type);
}
#if WITH_SOCKET
} else if (opt->desc->func == OFUNC_SOCKOPT) {
if (0) {
@ -2938,6 +2983,38 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
opt->desc->defname, opt->desc->type);
break;
}
} else if (opt->desc->func == OFUNC_SOCKOPT_GENERIC) {
switch (opt->desc->type) {
case TYPE_INT_INT_INT:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
&opt->value3.u_int, sizeof(int)) < 0) {
Error6("setsockopt(%d, %d, %d, {%d}, "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_int, sizeof(int), strerror(errno));
}
break;
case TYPE_INT_INT_BIN:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_bin.b_data, opt->value3.u_bin.b_len) < 0) {
Error5("setsockopt(%d, %d, %d, {...}, "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_bin.b_len, strerror(errno));
}
break;
case TYPE_INT_INT_STRING:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_string,
strlen(opt->value3.u_string)+1) < 0) {
Error6("setsockopt(%d, %d, %d, \"%s\", "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_string, strlen(opt->value3.u_string)+1,
strerror(errno));
}
break;
default:
Error1("setsockopt() data type %d not implemented",
opt->desc->type);
}
#endif /* WITH_SOCKET */
#if HAVE_FLOCK
@ -3156,119 +3233,7 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
}
}
break;
case OPT_IOCTL_VOID:
switch (opt->desc->type) {
case TYPE_INT:
if (Ioctl(fd, opt->value.u_int, NULL) < 0) {
Error3("ioctl(%d, 0x%x, NULL): %s",
fd, opt->value.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_INT:
switch (opt->desc->type) {
case TYPE_INT_INT:
if (Ioctl_int(fd, opt->value.u_int, opt->value2.u_int) < 0) {
Error4("ioctl(%d, %d, %p): %s",
fd, opt->value.u_int, opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_INTP:
switch (opt->desc->type) {
case TYPE_INT_INT:
if (Ioctl(fd, opt->value.u_int, (void *)&opt->value2.u_int) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)&opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_BIN:
switch (opt->desc->type) {
case TYPE_INT_BIN:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_STRING:
switch (opt->desc->type) {
case TYPE_INT_STRING:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_string) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_string, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_SETSOCKOPT_INT:
switch (opt->desc->type) {
case TYPE_INT_INT_INT:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
&opt->value3.u_int, sizeof(int)) < 0) {
Error6("setsockopt(%d, %d, %d, {%d}, "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_int, sizeof(int), strerror(errno));
}
break;
default:
Error1("setsockopt() data type %d not implemented",
opt->desc->type);
}
break;
case OPT_SETSOCKOPT_BIN:
switch (opt->desc->type) {
case TYPE_INT_INT_BIN:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_bin.b_data, opt->value3.u_bin.b_len) < 0) {
Error5("setsockopt(%d, %d, %d, {...}, "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_bin.b_len, strerror(errno));
}
break;
default:
Error1("setsockopt() data type %d not implemented",
opt->desc->type);
}
break;
case OPT_SETSOCKOPT_STRING:
switch (opt->desc->type) {
case TYPE_INT_INT_STRING:
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_string,
strlen(opt->value3.u_string)+1) < 0) {
Error6("setsockopt(%d, %d, %d, \"%s\", "F_Zu"): %s",
fd, opt->value.u_int, opt->value2.u_int,
opt->value3.u_string, strlen(opt->value3.u_string)+1,
strerror(errno));
}
break;
default:
Error1("setsockopt() data type %d not implemented",
opt->desc->type);
}
break;
default: Error1("applyopts(): option \"%s\" not implemented",
opt->desc->defname);
opt->desc = ODESC_ERROR; ++opt; continue;

View file

@ -22,45 +22,53 @@ enum e_types {
TYPE_BIN, /* raw binary data, length determined by data */
TYPE_BOOL, /* value is 0 or 1 (no-value is interpreted as 1) */
TYPE_BYTE, /* unsigned char */
TYPE_INT, /* int */
TYPE_LONG, /* long */
TYPE_STRING, /* char * */
TYPE_NAME = TYPE_STRING,
TYPE_FILENAME = TYPE_STRING,
TYPE_PTRDIFF, /* ptrdiff_t */
TYPE_SHORT, /* short */
TYPE_SIZE_T, /* size_t */
TYPE_SOCKADDR, /* struct sockaddr * */
TYPE_UINT, /* unsigned int */
TYPE_ULONG, /* unsigned long */
TYPE_USHORT, /* unsigned short */
TYPE_2BYTE = TYPE_USHORT,
TYPE_MODET, /* representation of mode_t */
TYPE_GIDT, /* representation of gid_t */
TYPE_UIDT, /* representation of uid_t */
/*TYPE_FLAG,*/
TYPE_INT3, /* int[3] */
TYPE_TIMEVAL, /* struct timeval: {long;long;}, seconds and microsec. */
TYPE_TIMESPEC, /* struct timespec: {time_t;long;}, seconds and nanosec. */
#if HAVE_STRUCT_LINGER
TYPE_LINGER, /* struct linger */
#endif /* HAVE_STRUCT_LINGER */
TYPE_DOUBLE, /* double */
TYPE_STRING_NULL, /* char *; string or NULL */
TYPE_LONGLONG, /* long long */
TYPE_OFF32, /* off_t */
TYPE_OFF64, /* off64_t */
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif
TYPE_IP4NAME, /* IPv4 hostname or address */
TYPE_INT_INT, /* 2 parameters: first is int, second is int */
TYPE_INT_INTP, /* 2 parameters: first is int, second is int* */
TYPE_INT_BIN, /* 2 parameters: first is int, second is binary */
TYPE_INT_STRING, /* 2 parameters: first is int, second is req string */
TYPE_INT_INT_INT, /* 3 params: first and second are int, 3rd is int */
TYPE_INT_INT_BIN, /* 3 params: first and second are int, 3rd is binary */
TYPE_INT_INT_STRING, /* 3 params: first and second are int, 3rd is string */
TYPE_2BYTE = TYPE_USHORT
TYPE_IP4NAME, /* IPv4 hostname or address */
#if HAVE_STRUCT_LINGER
TYPE_LINGER, /* struct linger */
#endif /* HAVE_STRUCT_LINGER */
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif
} ;
enum e_func {
@ -74,8 +82,10 @@ enum e_func {
is int setrequest */
OFUNC_IOCTL_MASK_LONG, /* arg1 is getrequest, arg2 is setrequest:
ioctl(arg1, ); |= arg3; ioctl(arg2, ); */
OFUNC_IOCTL_GENERIC, /* generic ioctl() (request on cmdline) */
OFUNC_SOCKOPT, /* setsockopt() */
OFUNC_SOCKOPT_APPEND,/* getsockopt(), append data, setsockopt() */
OFUNC_SOCKOPT_GENERIC,/* generic setsockopt() (level, optname on cmdline) */
OFUNC_FLOCK, /* flock() */
OFUNC_TERMIO, /* termio() ? */
OFUNC_SPEC, /* special, i.e. no generalizable function call */