From 8947cc92dc2dc37cb5a4041efe11733ab36a1a20 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Tue, 12 Aug 2008 07:30:10 +0200 Subject: [PATCH] added test SETSOCKOPT_INT; some corrections on generic ioctl and setsockopt features --- test.sh | 76 +++++++++++++++++++- xio-fd.c | 10 +-- xio-socket.c | 6 +- xio-socket.h | 2 +- xiohelp.c | 3 +- xioopts.c | 191 +++++++++++++++++++++------------------------------ xioopts.h | 26 ++++--- 7 files changed, 180 insertions(+), 134 deletions(-) diff --git a/test.sh b/test.sh index 7acd059..dee3739 100755 --- a/test.sh +++ b/test.sh @@ -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; 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)) diff --git a/xio-fd.c b/xio-fd.c index a982005..9fc1d57 100644 --- a/xio-fd.c +++ b/xio-fd.c @@ -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 }; diff --git a/xio-socket.c b/xio-socket.c index 5399967..2bb3b47 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -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 diff --git a/xio-socket.h b/xio-socket.h index 4947ead..5a68920 100644 --- a/xio-socket.h +++ b/xio-socket.h @@ -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 diff --git a/xiohelp.c b/xiohelp.c index 4ed9323..b37115b 100644 --- a/xiohelp.c +++ b/xiohelp.c @@ -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", } ; diff --git a/xioopts.c b/xioopts.c index f843da2..4022ca2 100644 --- a/xioopts.c +++ b/xioopts.c @@ -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; diff --git a/xioopts.h b/xioopts.h index d6d9f59..db78829 100644 --- a/xioopts.h +++ b/xioopts.h @@ -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 */