diff --git a/CHANGES b/CHANGES index 6014cd2..6cb1d7c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ new features: + new address types SCTP-CONNECT and SCTP-LISTEN implement SCTP stream + mode for IPv4 and IPv6; new address options sctp-maxseg and + sctp-nodelay + added generic socket addresses: SOCKET-CONNECT, SOCKET-LISTEN, SOCKET-SENDTO, SOCKET-RECVFROM, SOCKET-RECV, SOCKET-DATAGRAM allow protocol independent socket handling; all parameters are explicitely diff --git a/Makefile.in b/Makefile.in index e5b1f29..7e505a4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,7 +46,7 @@ XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \ xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \ xio-gopen.c xio-creat.c xio-file.c xio-named.c \ xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \ - xio-rawip.c \ + xio-sctp.c xio-rawip.c \ xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \ xio-pty.c xio-openssl.c \ xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c @@ -63,6 +63,7 @@ HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes. xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \ xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \ xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \ + xio-sctp.h \ xio-system.h xio-termios.h xio-readline.h \ xio-pty.h xio-openssl.h \ xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h diff --git a/VERSION b/VERSION index 0573f31..64a05c6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar+protocol+ioctl+setsockopt+genericsocket" +"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar+protocol+ioctl+setsockopt+genericsocket+sctp" diff --git a/config.h.in b/config.h.in index ec9236a..7f7dcbc 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,5 @@ /* source: config.h.in */ -/* Copyright Gerhard Rieger 2001-2007 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __config_h_included @@ -471,6 +471,7 @@ #undef WITH_GENERICSOCKET #undef WITH_TCP #undef WITH_UDP +#undef WITH_SCTP #undef WITH_LISTEN #undef WITH_SOCKS4 #undef WITH_SOCKS4A diff --git a/configure.in b/configure.in index 8bb4e10..26074c6 100644 --- a/configure.in +++ b/configure.in @@ -237,6 +237,14 @@ AC_ARG_ENABLE(udp, [ --disable-udp disable UDP support], esac], [AC_DEFINE(WITH_UDP) AC_MSG_RESULT(yes)]) +AC_MSG_CHECKING(whether to include SCTP support) +AC_ARG_ENABLE(tcp, [ --disable-sctp disable SCTP support], + [case "$enableval" in + no) AC_MSG_RESULT(no);; + *) AC_DEFINE(WITH_SCTP) AC_MSG_RESULT(yes);; + esac], + [AC_DEFINE(WITH_SCTP) AC_MSG_RESULT(yes)]) + AC_MSG_CHECKING(whether to include listen support) AC_ARG_ENABLE(listen, [ --disable-listen disable listen support], [case "$enableval" in diff --git a/doc/socat.yo b/doc/socat.yo index 2644c4d..5723b1e 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -600,6 +600,69 @@ label(ADDRESS_READLINE)dit(bf(tt(READLINE))) link(noecho)(OPTION_NOECHO)nl() See also: link(STDIO)(ADDRESS_STDIO) +label(ADDRESS_SCTP_CONNECT)dit(bf(tt(SCTP-CONNECT::))) + Establishes an SCTP stream connection to the specified [link(IP + address)(TYPE_IP_ADDRESS)] and [link(TCP service)(TYPE_TCP_SERVICE)] + using TCP/IP version 4 or 6 depending on address specification, name + resolution, or option link(pf)(OPTION_PROTOCOL_FAMILY).nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(SCTP)(GROUP_SCTP),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(bind)(OPTION_BIND), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(connect-timeout)(OPTION_CONNECT_TIMEOUT), + link(tos)(OPTION_TOS), + link(mtudiscover)(OPTION_MTUDISCOVER), + link(mss)(OPTION_MSS), + link(nodelay)(OPTION_NODELAY), + link(nonblock)(OPTION_NONBLOCK), + link(sourceport)(OPTION_SOURCEPORT), + link(retry)(OPTION_RETRY), + link(readbytes)(OPTION_READBYTES)nl() + See also: + link(SCTP4-CONNECT)(ADDRESS_SCTP4_CONNECT), + link(SCTP6-CONNECT)(ADDRESS_SCTP6_CONNECT), + link(SCTP-LISTEN)(ADDRESS_SCTP_LISTEN), + link(TCP-CONNECT)(ADDRESS_TCP_CONNECT) +label(ADDRESS_SCTP4_CONNECT)dit(bf(tt(SCTP4-CONNECT::))) + Like link(SCTP-CONNECT)(ADDRESS_SCTP_CONNECT), but only supports IPv4 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(SCTP)(GROUP_SCTP),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY) nl() +label(ADDRESS_SCTP6_CONNECT)dit(bf(tt(SCTP6-CONNECT::))) + Like link(SCTP-CONNECT)(ADDRESS_SCTP_CONNECT), but only supports IPv6 protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(SCTP)(GROUP_SCTP),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY) nl() +label(ADDRESS_SCTP_LISTEN)dit(bf(tt(SCTP-LISTEN:))) + Listens on [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a + TCP/IP connection. The IP version is 4 or the one specified with + address option link(pf)(OPTION_PROTOCOL_FAMILY), socat option + (link(-4)(option_4), link(-6)(option_6)), or environment variable link(SOCAT_DEFAULT_LISTEN_IP)(ENV_SOCAT_DEFAULT_LISTEN_IP). + Note that opening + this address usually blocks until a client connects.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(SCTP)(GROUP_SCTP),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(crnl)(OPTION_CRNL), + link(fork)(OPTION_FORK), + link(bind)(OPTION_BIND), + link(range)(OPTION_RANGE), + link(tcpwrap)(OPTION_TCPWRAPPERS), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(backlog)(OPTION_BACKLOG), + link(mss)(OPTION_MSS), + link(su)(OPTION_SUBSTUSER), + link(reuseaddr)(OPTION_REUSEADDR), + link(retry)(OPTION_RETRY), + link(cool-write)(OPTION_COOL_WRITE)nl() + See also: + link(SCTP4-LISTEN)(ADDRESS_SCTP4_LISTEN), + link(SCTP6-LISTEN)(ADDRESS_SCTP6_LISTEN), + link(TCP-LISTEN)(ADDRESS_TCP_LISTEN), + link(SCTP-CONNECT)(ADDRESS_SCTP_CONNECT) +label(ADDRESS_SCTP4_LISTEN)dit(bf(tt(SCTP4-LISTEN:))) + Like link(SCTP-LISTEN)(ADDRESS_SCTP_LISTEN), but only supports IPv4 + protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4),link(SCTP)(GROUP_SCTP),link(RETRY)(GROUP_RETRY) nl() +label(ADDRESS_SCTP6_LISTEN)dit(bf(tt(SCTP6-LISTEN:))) + Like link(SCTP-LISTEN)(ADDRESS_SCTP_LISTEN), but only supports IPv6 + protocol.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP6)(GROUP_IP6),link(SCTP)(GROUP_SCTP),link(RETRY)(GROUP_RETRY) nl() label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:::))) Creates a stream socket using the first and second given socket parameters and tt(SOCK_STREAM) (see man socket(2)) and connects to the remote-address. @@ -829,6 +892,7 @@ label(ADDRESS_TCP_CONNECT)dit(bf(tt(TCP::))) link(TCP6)(ADDRESS_TCP6_CONNECT), link(TCP-LISTEN)(ADDRESS_TCP_LISTEN), link(UDP)(ADDRESS_UDP_CONNECT), + link(SCTP-CONNECT)(ADDRESS_SCTP_CONNECT), link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT) label(ADDRESS_TCP4_CONNECT)dit(bf(tt(TCP4::))) Like link(TCP)(ADDRESS_TCP_CONNECT), but only supports IPv4 protocol (link(example)(EXAMPLE_ADDRESS_TCP4_CONNECT)).nl() @@ -839,7 +903,8 @@ label(ADDRESS_TCP6_CONNECT)dit(bf(tt(TCP6::))) label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:))) Listens on [link(TCP service)(TYPE_TCP_SERVICE)] and accepts a TCP/IP connection. The IP version is 4 or the one specified with - link(pf)(OPTION_PROTOCOL_FAMILY). + address option link(pf)(OPTION_PROTOCOL_FAMILY), socat option + (link(-4)(option_4), link(-6)(option_6)), or environment variable link(SOCAT_DEFAULT_LISTEN_IP)(ENV_SOCAT_DEFAULT_LISTEN_IP). Note that opening this address usually blocks until a client connects.nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl() @@ -855,13 +920,15 @@ label(ADDRESS_TCP_LISTEN)dit(bf(tt(TCP-LISTEN:))) link(su)(OPTION_SUBSTUSER), link(reuseaddr)(OPTION_REUSEADDR), link(retry)(OPTION_RETRY), - link(retry)(OPTION_COOL_WRITE)nl() + link(cool-write)(OPTION_COOL_WRITE)nl() See also: - link(TCP4-LISTEN)(ADDRESS_TCP4_CONNECT), + link(TCP4-LISTEN)(ADDRESS_TCP4_LISTEN), link(TCP6-LISTEN)(ADDRESS_TCP6_LISTEN), link(UDP-LISTEN)(ADDRESS_UDP_LISTEN), + link(SCTP-LISTEN)(ADDRESS_SCTP_LISTEN), link(UNIX-LISTEN)(ADDRESS_UNIX_LISTEN), - link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN) + link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN), + link(TCP-CONNECT)(ADDRESS_TCP_CONNECT) label(ADDRESS_TCP4_LISTEN)dit(bf(tt(TCP4-LISTEN:))) Like link(TCP-LISTEN)(ADDRESS_TCP_LISTEN), but only supports IPv4 protocol (link(example)(EXAMPLE_ADDRESS_TCP4_LISTEN)).nl() @@ -2058,10 +2125,24 @@ enddit() startdit()enddit()nl() -em(bf(UDP and TCP option groups)) +label(GROUP_SCTP)em(bf(SCTP option group)) + +These options may be applied to SCTP stream sockets. +startdit() +label(OPTION_SCTP_NODELAY)dit(bf(tt(sctp-nodelay))) + Sets the SCTP_NODELAY socket option that disables the Nagle algorithm. +label(OPTION_SCTP_MAXSEG)dit(bf(tt(sctp-maxseg=))) + Sets the SCTP_MAXSEG socket option to [link(int)(TYPE_INT)]. This + value is then proposed to the peer with the SYN or SYN/ACK packet. +enddit() + +startdit()enddit()nl() + + +em(bf(UDP, TCP, and SCTP option groups)) Here we find options that are related to the network port mechanism and that -thus can be used with UDP and TCP, client and server addresses. +thus can be used with UDP, TCP, and SCTP client and server addresses. startdit() label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=))) For outgoing (client) TCP and UDP connections, it sets the source @@ -3163,11 +3244,11 @@ by the upper case name of the executable or the value of option link(-lp)(option_lp). startdit() +label(ENV_SOCAT_DEFAULT_LISTEN_IP) dit(bf(SOCAT_DEFAULT_LISTEN_IP) (input)) (Values 4 or 6) Sets the IP version to -be used -for listen, recv, and recvfrom addresses if no link(pf)(OPTION_PROTOCOL_FAMILY) -(protocol-family) option is given. Is overridden by socat options -link(-4)(option_4) or link(-6)(option_6). +be used for listen, recv, and recvfrom addresses if no +link(pf)(OPTION_PROTOCOL_FAMILY) (protocol-family) option is given. Is +overridden by socat options link(-4)(option_4) or link(-6)(option_6). dit(bf(SOCAT_PREFERRED_RESOLVE_IP) (input)) (Values 0, 4, or 6) Sets the IP version to diff --git a/socat.c b/socat.c index 28698bf..cf56a83 100644 --- a/socat.c +++ b/socat.c @@ -438,6 +438,11 @@ void socat_version(FILE *fd) { #else fputs(" #undef WITH_UDP\n", fd); #endif +#ifdef WITH_SCTP + fprintf(fd, " #define WITH_SCTP %d\n", WITH_SCTP); +#else + fputs(" #undef WITH_SCTP\n", fd); +#endif #ifdef WITH_LISTEN fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN); #else diff --git a/sysutils.c b/sysutils.c index 472d946..615fb55 100644 --- a/sysutils.c +++ b/sysutils.c @@ -423,7 +423,9 @@ int xiopoll(struct pollfd fds[], nfds_t nfds, int timeout) { #if WITH_TCP || WITH_UDP -/* returns port in network byte order */ +/* returns port in network byte order; + ipproto==IPPROTO_UDP resolves as UDP service, every other value resolves as + TCP */ int parseport(const char *portname, int ipproto) { struct servent *se; char *extra; @@ -438,7 +440,7 @@ int parseport(const char *portname, int ipproto) { return result; } - if ((se = getservbyname(portname, ipproto==IPPROTO_TCP?"tcp":"udp")) == NULL) { + if ((se = getservbyname(portname, ipproto==IPPROTO_UDP?"udp":"tcp")) == NULL) { Error2("cannot resolve service \"%s/%d\"", portname, ipproto); return 0; } diff --git a/test.sh b/test.sh index b847500..f5ebbf1 100755 --- a/test.sh +++ b/test.sh @@ -1866,6 +1866,40 @@ waitudp4port () { return 1 } +# wait until an SCTP4 listen port is ready +waitsctp4port () { + local port="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -n -a |grep '^sctp .* .*[0-9*]:'$port' .* LISTEN') ;; +# FreeBSD) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; +# NetBSD) l=$(netstat -an |grep '^tcp .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]* LISTEN.*') ;; +# Darwin) case "$(uname -r)" in +# [1-5]*) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; +# *) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; +# esac ;; +# AIX) l=$(netstat -an |grep '^tcp[^6] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; +# SunOS) l=$(netstat -an -f inet -P tcp |grep '.*[1-9*]\.'$port' .*\* 0 .* LISTEN') ;; +# HP-UX) l=$(netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' .* LISTEN$') ;; +# OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') ;; +# CYGWIN*) l=$(netstat -an -p TCP |grep '^ TCP [0-9.]*:'$port' .* LISTENING') ;; + *) l=$(netstat -an |grep -i 'sctp .*[0-9*][:.]'$port' .* listen') ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!port $port timed out! \c" >&2 + return 1 +} + # wait until a tcp6 listen port is ready waittcp6port () { local port="$1" @@ -1926,6 +1960,36 @@ waitudp6port () { return 1 } +# wait until a sctp6 listen port is ready +# not all (Linux) variants show this in netstat +waitsctp6port () { + local port="$1" + local logic="$2" # 0..wait until free; 1..wait until listening + local timeout="$3" + local l + [ "$logic" ] || logic=1 + [ "$timeout" ] || timeout=5 + while [ $timeout -gt 0 ]; do + case "$UNAME" in + Linux) l=$(netstat -an |grep '^sctp[6 ] .* [0-9a-f:]*:'$port' .* LISTEN') ;; +# FreeBSD) l=$(netstat -an |grep -i 'tcp[46][6 ] .*[0-9*][:.]'$port' .* listen') ;; +# NetBSD) l=$(netstat -an |grep '^tcp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; +# OpenBSD) l=$(netstat -an |grep -i 'tcp6 .*[0-9*][:.]'$port' .* listen') ;; +# AIX) l=$(netstat -an |grep '^tcp[6 ] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; +# SunOS) l=$(netstat -an -f inet6 -P tcp |grep '.*[1-9*]\.'$port' .*\* [ ]* 0 .* LISTEN') ;; +# #OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp6 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') /*?*/;; + *) l=$(netstat -an |grep -i 'stcp6 .*:'$port' .* listen') ;; + esac + [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ + \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 + sleep 1 + timeout=$((timeout-1)) + done + + $ECHO "!port $port timed out! \c" >&2 + return 1 +} + # we need this misleading function name for canonical reasons waitunixport () { waitfile "$1" "$2" "$3" @@ -9174,6 +9238,7 @@ esac PORT=$((PORT+1)) N=$((N+1)) + # test the SOCKET-RECV address (with UDP4-SENDTO) NAME=SOCKET_RECV case "$TESTS" in @@ -9427,6 +9492,103 @@ PORT=$((PORT+1)) N=$((N+1)) +NAME=SCTP4STREAM +case "$TESTS" in +*%functions%*|*%ip4%*|*%ipapp%*|*%sctp%*|*%$NAME%*) +TEST="$NAME: echo via connection to SCTP V4 socket" +if ! testaddrs sctp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SCTP4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ "$UNAME" = Linux ] && ! grep ^sctp /proc/modules >/dev/null; then + # RHEL5 based systems became unusable when an sctp socket was created but + # module sctp not loaded + $PRINTF "test $F_n $TEST...${YELLOW}load sctp module!${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="127.0.0.1:$tsl" +da=$(date) +CMD1="$SOCAT $opts SCTP4-LISTEN:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout SCTP4:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid1=$! +waitsctp4port $tsl 1 +# SCTP does not seem to support half close, so we let it 1s to finish +(echo "$da"; sleep 1) |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD2" + cat "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid1 2>/dev/null +wait +fi ;; # sctp +esac +PORT=$((PORT+1)) +N=$((N+1)) + +NAME=SCTP6STREAM +case "$TESTS" in +*%functions%*|*%ip6%*|*%ipapp%*|*%sctp%*|*%$NAME%*) +TEST="$NAME: echo via connection to SCTP V6 socket" +if ! testaddrs sctp ip6 >/dev/null || ! runsip6 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SCTP6 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) +elif [ "$UNAME" = Linux ] && ! grep ^sctp /proc/modules >/dev/null; then + $PRINTF "test $F_n $TEST...${YELLOW}load sctp module!${NORMAL}\n" $N + numCANT=$((numCANT+1)) +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +tsl=$PORT +ts="[::1]:$tsl" +da=$(date) +CMD1="$SOCAT $opts SCTP6-listen:$tsl,reuseaddr PIPE" +CMD2="$SOCAT $opts stdin!!stdout SCTP6:$ts" +printf "test $F_n $TEST... " $N +$CMD1 >"$tf" 2>"${te}1" & +pid=$! # background process id +waitsctp6port $tsl 1 +# SCTP does not seem to support half close, so we let it 1s to finish +(echo "$da"; sleep 1) |$CMD2 >>"$tf" 2>>"${te}2" +if [ $? -ne 0 ]; then + $PRINTF "$FAILED: $SOCAT:\n" + echo "$CMD1 &" + echo "$CMD2" + cat "$te" + numFAIL=$((numFAIL+1)) +elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +fi ;; # sctp +esac +PORT=$((PORT+1)) +N=$((N+1)) + + echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed" if [ "$numFAIL" -gt 0 ]; then diff --git a/xio-sctp.c b/xio-sctp.c new file mode 100644 index 0000000..bcfec7e --- /dev/null +++ b/xio-sctp.c @@ -0,0 +1,50 @@ +/* source: xio-sctp.c */ +/* Copyright Gerhard Rieger 2008 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +/* this file contains the source for SCTP related functions and options */ + +#include "xiosysincludes.h" + +#if WITH_SCTP + +#include "xioopen.h" +#include "xio-listen.h" +#include "xio-ip4.h" +#include "xio-ipapp.h" +#include "xio-sctp.h" + +/****** SCTP addresses ******/ + +#if WITH_IP4 || WITH_IP6 +const struct addrdesc addr_sctp_connect = { "sctp-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_SCTP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_SCTP, PF_UNSPEC HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_sctp_listen = { "sctp-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_SCTP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_SCTP, PF_UNSPEC HELP(":") }; +#endif +#endif + +#if WITH_IP4 +const struct addrdesc addr_sctp4_connect = { "sctp4-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_SCTP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_SCTP, PF_INET HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_sctp4_listen = { "sctp4-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_SCTP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_SCTP, PF_INET HELP(":") }; +#endif +#endif /* WITH_IP4 */ + +#if WITH_IP6 +const struct addrdesc addr_sctp6_connect = { "sctp6-connect", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_SCTP|GROUP_CHILD|GROUP_RETRY, SOCK_STREAM, IPPROTO_SCTP, PF_INET6 HELP("::") }; +#if WITH_LISTEN +const struct addrdesc addr_sctp6_listen = { "sctp6-listen", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_SCTP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_STREAM, IPPROTO_SCTP, PF_INET6 HELP(":") }; +#endif +#endif /* WITH_IP6 */ + +/****** SCTP address options ******/ + +#ifdef SCTP_NODELAY +const struct optdesc opt_sctp_nodelay = { "sctp-nodelay", "nodelay", OPT_SCTP_NODELAY, GROUP_IP_SCTP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SCTP, SCTP_NODELAY }; +#endif +#ifdef SCTP_MAXSEG +const struct optdesc opt_sctp_maxseg = { "sctp-maxseg", "mss", OPT_SCTP_MAXSEG, GROUP_IP_SCTP, PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SCTP, SCTP_MAXSEG }; +const struct optdesc opt_sctp_maxseg_late={"sctp-maxseg-late","mss-late",OPT_SCTP_MAXSEG_LATE,GROUP_IP_SCTP,PH_CONNECTED,TYPE_INT,OFUNC_SOCKOPT, SOL_SCTP, SCTP_MAXSEG}; +#endif + +#endif /* WITH_SCTP */ diff --git a/xio-sctp.h b/xio-sctp.h new file mode 100644 index 0000000..de2adb3 --- /dev/null +++ b/xio-sctp.h @@ -0,0 +1,19 @@ +/* source: xio-sctp.h */ +/* Copyright Gerhard Rieger 2008 */ +/* Published under the GNU General Public License V.2, see file COPYING */ + +#ifndef __xio_sctp_h_included +#define __xio_sctp_h_included 1 + +extern const struct addrdesc addr_sctp_connect; +extern const struct addrdesc addr_sctp_listen; +extern const struct addrdesc addr_sctp4_connect; +extern const struct addrdesc addr_sctp4_listen; +extern const struct addrdesc addr_sctp6_connect; +extern const struct addrdesc addr_sctp6_listen; + +extern const struct optdesc opt_sctp_nodelay; +extern const struct optdesc opt_sctp_maxseg; +extern const struct optdesc opt_sctp_maxseg_late; + +#endif /* !defined(__xio_sctp_h_included) */ diff --git a/xiohelp.c b/xiohelp.c index b37115b..fe232cd 100644 --- a/xiohelp.c +++ b/xiohelp.c @@ -43,7 +43,7 @@ static const char *addressgroupnames[] = { "TERMIOS", "RANGE", "PTY", "PARENT", "UNIX", "IP4", "IP6", "INTERFACE", "UDP", "TCP", "SOCKS4", "OPENSSL", - "PROCESS", "APPL", "HTTP", "undef" + "PROCESS", "APPL", "HTTP", "SCTP" } ; diff --git a/xiomodes.h b/xiomodes.h index 90a6745..48f8dac 100644 --- a/xiomodes.h +++ b/xiomodes.h @@ -28,6 +28,7 @@ #include "xio-ipapp.h" #include "xio-tcp.h" #include "xio-udp.h" +#include "xio-sctp.h" #include "xio-socks.h" #include "xio-proxy.h" #endif /* _WITH_SOCKET */ diff --git a/xioopen.c b/xioopen.c index de42455..051bbc7 100644 --- a/xioopen.c +++ b/xioopen.c @@ -135,6 +135,26 @@ const struct addrname addressnames[] = { #if WITH_READLINE { "readline", &addr_readline }, #endif +#if (WITH_IP4 || WITH_IP6) && WITH_SCTP + { "sctp", &addr_sctp_connect }, + { "sctp-connect", &addr_sctp_connect }, +#if WITH_LISTEN + { "sctp-l", &addr_sctp_listen }, + { "sctp-listen", &addr_sctp_listen }, +#endif + { "sctp4", &addr_sctp4_connect }, + { "sctp4-connect", &addr_sctp4_connect }, +#if WITH_LISTEN + { "sctp4-l", &addr_sctp4_listen }, + { "sctp4-listen", &addr_sctp4_listen }, +#endif + { "sctp6", &addr_sctp6_connect }, + { "sctp6-connect", &addr_sctp6_connect }, +#if WITH_LISTEN + { "sctp6-l", &addr_sctp6_listen }, + { "sctp6-listen", &addr_sctp6_listen }, +#endif +#endif /* (WITH_IP4 || WITH_IP6) && WITH_SCTP */ #if WITH_GENERICSOCKET { "sendto", &xioaddr_socket_sendto }, #endif diff --git a/xioopen.h b/xioopen.h index ba8bc62..2002be4 100644 --- a/xioopen.h +++ b/xioopen.h @@ -1,5 +1,5 @@ /* source: xioopen.h */ -/* Copyright Gerhard Rieger 2001-2006 */ +/* Copyright Gerhard Rieger 2001-2008 */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __xioopen_h_included diff --git a/xioopts.c b/xioopts.c index f66485f..550a292 100644 --- a/xioopts.c +++ b/xioopts.c @@ -82,6 +82,12 @@ bool xioopts_ignoregroups; # define IF_TCP(a,b) #endif +#if WITH_SCTP +# define IF_SCTP(a,b) {a,b}, +#else +# define IF_SCTP(a,b) +#endif + #if WITH_SOCKS4 # define IF_SOCKS4(a,b) {a,b}, #else @@ -1208,6 +1214,13 @@ const struct optname optionnames[] = { IF_TCP ("sackena", &opt_tcp_sackena) #endif IF_TERMIOS("sane", &opt_sane) +#ifdef SCTP_MAXSEG + IF_SCTP ("sctp-maxseg", &opt_sctp_maxseg) + IF_SCTP ("sctp-maxseg-late", &opt_sctp_maxseg_late) +#endif +#ifdef SCTP_NODELAY + IF_SCTP ("sctp-nodelay", &opt_sctp_nodelay) +#endif #if WITH_EXT2 && defined(EXT2_SECRM_FL) IF_ANY ("secrm", &opt_ext2_secrm) #endif diff --git a/xioopts.h b/xioopts.h index b5b846d..2a02362 100644 --- a/xioopts.h +++ b/xioopts.h @@ -166,6 +166,7 @@ enum e_func { #define GROUP_PROCESS 0x10000000 /* a process related option */ #define GROUP_APPL 0x20000000 /* option handled by data loop */ #define GROUP_HTTP 0x40000000 /* any HTTP client */ +#define GROUP_IP_SCTP 0x80000000 #define GROUP_ANY (GROUP_PROCESS|GROUP_APPL) #define GROUP_ALL 0xffffffff @@ -568,6 +569,9 @@ enum e_optcode { OPT_RES_USEVC, /* resolver(3) */ OPT_RETRY, OPT_SANE, /* termios */ + OPT_SCTP_MAXSEG, + OPT_SCTP_MAXSEG_LATE, + OPT_SCTP_NODELAY, OPT_SEEK32_CUR, OPT_SEEK32_END, OPT_SEEK32_SET,