Implementation of DCCP socket addresses
diff --git a/CHANGES b/CHANGES
index 8e5fb7a..e7f93ca 100644
--- a/CHANGES
+++ b/CHANGES
@@ -170,6 +170,15 @@
than pipe buffer. Socat now tries to detect if transfer block size is
large enough and issues a warning.
+ Added direct support of DCCP protocol, new addresses:
+ DCCP-CONNECT (DCCP)
+ DCCP-LISTEN (DCCP-L)
+ DCCP4-CONNECT (DCCP4)
+ DCCP4-LISTEN (DCCP4-L)
+ DCCP6-CONNECT (DCCP6)
+ DCCP6-LISTEN (DCCP6-L)
+ New option: dccp-set-ccid (ccid)
+
Corrections:
When a sub process (EXEC, SYSTEM) terminated with exit code other than
0, its last sent data might have been lost depending on timing of read/
diff --git a/Makefile.in b/Makefile.in
index 3f8d86f..5f67f8b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -49,7 +49,7 @@
xio-socketpair.c xio-gopen.c xio-creat.c xio-file.c xio-named.c \
xio-socket.c xio-interface.c xio-listen.c xio-unix.c xio-vsock.c \
xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c \
- xio-sctp.c xio-rawip.c xio-posixmq.c \
+ xio-sctp.c xio-dccp.c xio-rawip.c xio-posixmq.c \
xio-socks.c xio-socks5.c xio-proxy.c xio-udp.c \
xio-progcall.c xio-exec.c xio-system.c xio-shell.c \
xio-termios.c xio-readline.c \
@@ -68,7 +68,7 @@
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h \
xio-socketpair.h xio-socket.h xio-interface.h xio-listen.h xio-unix.h xio-vsock.h \
xio-ip.h xio-ip4.h xio-ip6.h xio-rawip.h xio-posixmq.h \
- xio-ipapp.h xio-tcp.h xio-udp.h xio-sctp.h \
+ xio-ipapp.h xio-tcp.h xio-udp.h xio-sctp.h xio-dccp.h \
xio-socks.h xio-socks5.h xio-proxy.h xio-progcall.h xio-exec.h \
xio-system.h xio-shell.h xio-termios.h xio-readline.h \
xio-pty.h xio-openssl.h xio-streams.h xio-namespaces.h \
diff --git a/config.h.in b/config.h.in
index 4ef4dd1..f0d2842 100644
--- a/config.h.in
+++ b/config.h.in
@@ -282,6 +282,9 @@
/* Define if you have the <linux/if_tun.h> header file. */
#undef HAVE_LINUX_IF_TUN_H
+/* Define if you have the <linux/dccp.h> header file. */
+#undef HAVE_LINUX_DCCP_H
+
/* Define if you have the <linux/vm_sockets.h> header file. */
#undef HAVE_LINUX_VM_SOCKETS_H
@@ -710,6 +713,7 @@
#undef WITH_TCP
#undef WITH_UDP
#undef WITH_SCTP
+#undef WITH_DCCP
#undef WITH_LISTEN
#undef WITH_POSIXMQ
#undef WITH_SOCKS4
diff --git a/configure.ac b/configure.ac
index 41a9844..f444ad8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -369,6 +369,32 @@
fi
fi
+AC_MSG_CHECKING(whether to include DCCP support)
+AC_ARG_ENABLE(dccp, [ --disable-dccp disable DCCP support],
+ [case "$enableval" in
+ no) AC_MSG_RESULT(no); WITH_DCCP= ;;
+ *) AC_MSG_RESULT(yes); WITH_DCCP=1 ;;
+ esac],
+ [AC_MSG_RESULT(yes); WITH_DCCP=1 ])
+
+if test -n "$WITH_DCCP"; then
+AC_MSG_CHECKING(for IPPROTO_DCCP)
+AC_CACHE_VAL(sc_cv_define_ipproto_dccp,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>],
+[IPPROTO_DCCP;],
+[sc_cv_define_ipproto_dccp=yes],
+[sc_cv_define_ipproto_dccp=no])])
+AC_MSG_RESULT($sc_cv_define_ipproto_dccp)
+if test $sc_cv_define_ipproto_dccp = yes; then
+ AC_DEFINE(WITH_DCCP)
+ AC_CHECK_HEADER(linux/dccp.h,
+ AC_DEFINE(HAVE_LINUX_DCCP_H))
+else
+ AC_MSG_WARN([IPPROTO_DCCP undefined, disabling DCCP support])
+fi
+fi
+
AC_MSG_CHECKING(whether to include vsock support)
AC_ARG_ENABLE(vsock, [ --disable-vsock disable vsock support],
[case "$enableval" in
diff --git a/doc/socat.yo b/doc/socat.yo
index e00741d..c7a81a4 100644
--- a/doc/socat.yo
+++ b/doc/socat.yo
@@ -51,10 +51,10 @@
Socat() is a command line based utility that establishes two bidirectional byte
streams and transfers data between them. Because the streams can be constructed
-from a large set of different types of data sinks and sources
+from a large set of different types of data sinks and sources
(see link(address types)(ADDRESS_TYPES)), and because lots of
link(address options)(ADDRESS_OPTIONS) may be applied to the streams, socat can
-be used for many different purposes.
+be used for many different purposes.
Filan() is a utility that prints information about its active file
descriptors to stdout. It has been written for debugging socat(), but might be
@@ -314,6 +314,69 @@
link(unlink-late)(OPTION_UNLINK_LATE),
link(append)(OPTION_APPEND)nl()
See also: link(OPEN)(ADDRESS_OPEN), link(GOPEN)(ADDRESS_GOPEN)
+
+label(ADDRESS_DCCP_CONNECT)dit(bf(tt(DCCP-CONNECT:<host>:<port>)) (bf(tt(DCCP:<host>:<port>))))
+ Establishes a DCCP connect to the specified <host> [link(IP
+ address)(TYPE_IP_ADDRESS)] and <port> [link(DCCP service)(TYPE_TCP_SERVICE)]
+ using 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(connect-timeout)(OPTION_CONNECT_TIMEOUT),
+ link(tos)(OPTION_TOS),
+ link(dccp-set-ccid)(OPTION_DCCP_SET_CCID),
+ link(nonblock)(OPTION_NONBLOCK),
+ link(sourceport)(OPTION_SOURCEPORT),
+ link(retry)(OPTION_RETRY),
+ link(readbytes)(OPTION_READBYTES)nl()
+ See also:
+ link(DCCP4-CONNECT)(ADDRESS_DCCP4_CONNECT),
+ link(DCCP6-CONNECT)(ADDRESS_DCCP6_CONNECT),
+ link(DCCP-LISTEN)(ADDRESS_DCCP_LISTEN),
+ link(TCP-CONNECT)(ADDRESS_TCP_CONNECT)
+ link(SCTP-CONNECT)(ADDRESS_SCTP_CONNECT)
+label(ADDRESS_DCCP4_CONNECT)dit(bf(tt(DCCP4-CONNECT:<host>:<port>)) (bf(tt(DCCP4:<host>:<port>))))
+ Like link(DCCP-CONNECT)(ADDRESS_DCCP_CONNECT), but only supports IPv4 protocol.nl()
+ Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(DCCP)(GROUP_DCCP),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY) nl()
+label(ADDRESS_DCCP6_CONNECT)dit(bf(tt(DCCP6-CONNECT:<host>:<port>)) (bf(tt(DCCP6:<host>:<port>))))
+ Like link(DCCP-CONNECT)(ADDRESS_DCCP_CONNECT), but only supports IPv6 protocol.nl()
+ Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP6)(GROUP_IP6),link(DCCP)(GROUP_DCCP),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY) nl()
+
+label(ADDRESS_DCCP_LISTEN)dit(bf(tt(DCCP-LISTEN:<port>)) (bf(tt(DCCP-L:<port>))))
+ Listens on <port> [link(DCCP service)(TYPE_TCP_SERVICE)] and accepts an
+ DCCP 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(DCCP)(GROUP_DCCP),link(RETRY)(GROUP_RETRY) nl()
+ Useful options:
+ link(fork)(OPTION_FORK),
+ link(bind)(OPTION_BIND),
+ link(range)(OPTION_RANGE),
+ link(max-children)(OPTION_MAX_CHILDREN),
+ link(backlog)(OPTION_BACKLOG),
+ link(accept-timeout)(OPTION_ACCEPT_TIMEOUT),
+ link(dccp-set-sid)(OPTION_DCCP_SET_CCID),
+ link(su)(OPTION_SUBSTUSER),
+ link(reuseaddr)(OPTION_SO_REUSEADDR),
+ link(retry)(OPTION_RETRY)nl()
+ See also:
+ link(DCCP4-LISTEN)(ADDRESS_DCCP4_LISTEN),
+ link(DCCP6-LISTEN)(ADDRESS_DCCP6_LISTEN),
+ link(TCP-LISTEN)(ADDRESS_TCP_LISTEN),
+ link(SCTP-LISTEN)(ADDRESS_SCTP_LISTEN),
+ link(DCCP-CONNECT)(ADDRESS_DCCP_CONNECT)
+label(ADDRESS_DCCP4_LISTEN)dit(bf(tt(DCCP4-LISTEN:<port>)) (bf(tt(DCCP4-L:<port>))))
+ Like link(DCCP-LISTEN)(ADDRESS_DCCP_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(DCCP)(GROUP_DCCP),link(RETRY)(GROUP_RETRY) nl()
+label(ADDRESS_DCCP6_LISTEN)dit(bf(tt(DCCP6-LISTEN:<port>)) (bf(tt(DCCP6-L:<port>))))
+ Like link(DCCP-LISTEN)(ADDRESS_DCCP_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(DCCP)(GROUP_DCCP),link(RETRY)(GROUP_RETRY) nl()
+
label(ADDRESS_EXEC)dit(bf(tt(EXEC:<command-line>)))
Forks a sub process that establishes communication with its parent process
and invokes the specified program with code(execvp()).
@@ -2651,10 +2714,22 @@
startdit()enddit()nl()
-em(bf(UDP, TCP, and SCTP option group))
+label(GROUP_DCCP)em(bf(DCCP option group))
+
+These options may be applied to DCCP sockets.
+startdit()
+label(OPTION_DCCP_SET_CCID)dit(bf(tt(dccp-set-ccid=<int>)))
+dit(bf(tt(ccid=<int>)))
+ Selects the desired congestion control mechanism (CCID).
+enddit()
+
+startdit()enddit()nl()
+
+
+em(bf(UDP, TCP, SCTP, and DCCP option group))
Here we find options that are related to the network port mechanism and thus
-can be used with UDP, TCP, and SCTP client and server addresses.
+can be used with UDP, TCP, SCTP, and DCCP client and server addresses.
startdit()
label(OPTION_SOURCEPORT)dit(bf(tt(sourceport=<port>)))
For outgoing (client) TCP and UDP connections, it sets the source
@@ -4080,10 +4155,9 @@
TCP-LISTEN:10021,reuseaddr,socktype=6,protocol=33,fork \
PIPE</div>)
-is a simple DCCP echo server. It uses socat()s TCP procedures, but changes the
+is a simple DCCP echo server. DCCP is now directly provisioned in socat(),
+however this example shows how use socat()s TCP procedures and change the
socket type to SOCK_DCCP=6 (on Linux) and the IP protocol to IPPROTO_DCCP=33.
-This works in contrast to attempts with UDP basis, even though DCCP is named a
-datagram protocol.
label(EXAMPLE_GENERIC_DCCP_CLIENT)
@@ -4099,7 +4173,8 @@
htmlcommand(<hr><div class="shell">socat - \
TCP:<server>:10021,reuseaddr,socktype=6,protocol=33,fork</div>)
-is a simple DCCP client. It uses socat()s TCP procedures, but changes the
+is a simple DCCP client. DCCP is now directly provisioned in socat(),
+however this example shows how use socat()s TCP procedures, but changes the
socket type to SOCK_DCCP=6 (on Linux) and the IP protocol to IPPROTO_DCCP=33.
diff --git a/socat.c b/socat.c
index c857b0b..f13f813 100644
--- a/socat.c
+++ b/socat.c
@@ -599,6 +599,11 @@
#else
fputs(" #undef WITH_SCTP\n", fd);
#endif
+#ifdef WITH_DCCP
+ fprintf(fd, " #define WITH_DCCP %d\n", WITH_DCCP);
+#else
+ fputs(" #undef WITH_DCCP\n", fd);
+#endif
#ifdef WITH_LISTEN
fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN);
#else
diff --git a/sysincludes.h b/sysincludes.h
index b960dc4..0c2aff3 100644
--- a/sysincludes.h
+++ b/sysincludes.h
@@ -150,7 +150,9 @@
#if HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
#endif
-
+#if HAVE_LINUX_DCCP_H
+#include <linux/dccp.h>
+#endif
#if HAVE_TERMIOS_H && _WITH_TERMIOS
#include <termios.h>
#endif
diff --git a/test.sh b/test.sh
index 84f5909..dd4ed16 100755
--- a/test.sh
+++ b/test.sh
@@ -978,9 +978,25 @@
return 0;
}
-routesip6 () {
- runsip6 >/dev/null || { echo route6; return 1; }
- ping -c 1 -s 0 -6 2606:4700:4700::1111 >/dev/null 2>&1 || { echo route6; return 1; }
+# check if DCCP on IPv4 is available on host
+runsdccp4 () {
+ runsip4 >/dev/null || { echo DCCP4; return 1; }
+ $SOCAT -h |grep -i ' DCCP4-' >/dev/null || return 1
+ $SOCAT /dev/null DCCP4-L:0,accept-timeout=0.001 2>/dev/null || return 1;
+ return 0;
+}
+
+# check if DCCP on IPv6 is available on host
+runsdccp6 () {
+ runsip6 >/dev/null || { echo DCCP6; return 1; }
+ $SOCAT -h |grep -i ' DCCP6-' >/dev/null || return 1
+ $SOCAT /dev/null DCCP6-L:0,accept-timeout=0.001 2>/dev/null || return 1;
+ return 0;
+}
+
+# check if UNIX domain sockets work
+runsunix () {
+ # for now...
return 0;
}
@@ -1066,7 +1082,7 @@
if [ "$inet" ]; then
if [ -z "$NTERNET" ]; then
- echo "Use test.sh option -internet"
+ echo "Use test.sh option --internet"
return -1
fi
fi
@@ -18127,6 +18143,68 @@
N=$((N+1))
+NAME=DCCP4
+case "$TESTS" in
+*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%dccp%*|*%listen%*|*%$NAME%*)
+TEST="$NAME: DCCP over IPv4"
+if ! eval $NUMCOND; then :
+elif ! cond=$(checkconds "" "" "" \
+ "IP4 DCCP LISTEN STDIO PIPE" \
+ "DCCP4-LISTEN PIPE STDIN STDOUT DCCP4" \
+ "so-reuseaddr" \
+ "dccp4" ); then
+ $PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N
+ numCANT=$((numCANT+1))
+ listCANT="$listCANT $N"
+else
+tf="$td/test$N.stdout"
+te="$td/test$N.stderr"
+tdiff="$td/test$N.diff"
+newport dccp4; tsl=$PORT
+ts="127.0.0.1:$tsl"
+da="test$N $(date) $RANDOM"
+CMD1="$TRACE $SOCAT $opts DCCP4-LISTEN:$tsl,$REUSEADDR PIPE"
+CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT DCCP4:$ts"
+printf "test $F_n $TEST... " $N
+$CMD1 >"$tf" 2>"${te}1" &
+pid1=$!
+waittcp4port $tsl 1
+echo "$da" |$CMD2 >>"$tf" 2>>"${te}2"
+if [ $? -ne 0 ]; then
+ $PRINTF "$FAILED\n"
+ echo "$CMD0 &"
+ cat "${te}0" >&2
+ echo "$CMD1"
+ cat "${te}1" >&2
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+ namesFAIL="$namesFAIL $NAME"
+elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
+ $PRINTF "$FAILED\n"
+ echo "$CMD0 &"
+ cat "${te}0" >&2
+ echo "$CMD1"
+ cat "${te}1" >&2
+ echo "// diff:" >&2
+ cat "$tdiff" >&2
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+ namesFAIL="$namesFAIL $NAME"
+else
+ $PRINTF "$OK\n"
+ if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
+ if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
+ if [ "$VERBOSE" ]; then echo "$CMD1"; fi
+ if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
+ numOK=$((numOK+1))
+fi
+kill $pid1 2>/dev/null
+wait
+fi ;; # NUMCOND, checkconds
+esac
+N=$((N+1))
+
+
# end of common tests
##################################################################################
diff --git a/xio-dccp.c b/xio-dccp.c
new file mode 100644
index 0000000..4a37416
--- /dev/null
+++ b/xio-dccp.c
@@ -0,0 +1,46 @@
+/* source: xio-dccp.c */
+/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
+/* Published under the GNU General Public License V.2, see file COPYING */
+
+/* this file contains the source for DCCP related functions and options */
+
+#include "xiosysincludes.h"
+
+#if WITH_DCCP
+
+#include "xioopen.h"
+#include "xio-listen.h"
+#include "xio-ip4.h"
+#include "xio-ipapp.h"
+#include "xio-dccp.h"
+
+/****** DCCP addresses ******/
+
+#if WITH_IP4 || WITH_IP6
+const struct addrdesc xioaddr_dccp_connect = { "DCCP-CONNECT", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_CHILD|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_UNSPEC HELP(":<host>:<port>") };
+#if WITH_LISTEN
+const struct addrdesc xioaddr_dccp_listen = { "DCCP-LISTEN", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_UNSPEC HELP(":<port>") };
+#endif
+#endif
+
+#if WITH_IP4
+const struct addrdesc xioaddr_dccp4_connect = { "DCCP4-CONNECT", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_DCCP|GROUP_CHILD|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET HELP(":<host>:<port>") };
+#if WITH_LISTEN
+const struct addrdesc xioaddr_dccp4_listen = { "DCCP4-LISTEN", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_IP_DCCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET HELP(":<port>") };
+#endif
+#endif /* WITH_IP4 */
+
+#if WITH_IP6
+const struct addrdesc xioaddr_dccp6_connect = { "DCCP6-CONNECT", 1+XIO_RDWR, xioopen_ipapp_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_CHILD|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET6 HELP(":<host>:<port>") };
+#if WITH_LISTEN
+const struct addrdesc xioaddr_dccp6_listen = { "DCCP6-LISTEN", 1+XIO_RDWR, xioopen_ipapp_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_IP_DCCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_RETRY, SOCK_DCCP, IPPROTO_DCCP, PF_INET6 HELP(":<port>") };
+#endif
+#endif /* WITH_IP6 */
+
+/****** DCCP address options ******/
+
+#if defined(SOL_DCCP) && defined(DCCP_SOCKOPT_QPOLICY_ID)
+const struct optdesc xioopt_dccp_set_ccid = { "dccp-set-ccid", "ccid", OPT_DCCP_SET_CCID, GROUP_IP_DCCP, PH_PASTSOCKET, TYPE_BYTE, OFUNC_SOCKOPT, SOL_DCCP, DCCP_SOCKOPT_CCID };
+#endif
+
+#endif /* WITH_DCCP */
diff --git a/xio-dccp.h b/xio-dccp.h
new file mode 100644
index 0000000..0ec5455
--- /dev/null
+++ b/xio-dccp.h
@@ -0,0 +1,17 @@
+/* source: xio-dccp.h */
+/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
+/* Published under the GNU General Public License V.2, see file COPYING */
+
+#ifndef __xio_dccp_h_included
+#define __xio_dccp_h_included 1
+
+extern const struct addrdesc xioaddr_dccp_connect;
+extern const struct addrdesc xioaddr_dccp_listen;
+extern const struct addrdesc xioaddr_dccp4_connect;
+extern const struct addrdesc xioaddr_dccp4_listen;
+extern const struct addrdesc xioaddr_dccp6_connect;
+extern const struct addrdesc xioaddr_dccp6_listen;
+
+extern const struct optdesc xioopt_dccp_set_ccid;
+
+#endif /* !defined(__xio_dccp_h_included) */
diff --git a/xio-openssl.c b/xio-openssl.c
index 4ea3a51..2948cab 100644
--- a/xio-openssl.c
+++ b/xio-openssl.c
@@ -640,7 +640,7 @@
/* this can fork() for us; it only returns on error or on
successful establishment of connection */
- if (ipproto == IPPROTO_TCP) {
+ if (ipproto == IPPROTO_TCP || ipproto == IPPROTO_DCCP) {
result = _xioopen_listen(sfd, xioflags,
(struct sockaddr *)us, uslen,
opts, pf, socktype, ipproto,
diff --git a/xio.h b/xio.h
index 71bddc6..1a68819 100644
--- a/xio.h
+++ b/xio.h
@@ -95,7 +95,7 @@
} ;
/* Keep condition consistent with xioopts.h:GROUP_*! */
-#if WITH_SCTP || WITH_POSIXMQ
+#if WITH_POSIXMQ || WITH_SCTP || WITH_DCCP
typedef uint64_t groups_t;
#define F_groups_t F_uint64_x
#else
diff --git a/xiohelp.c b/xiohelp.c
index b05127a..519b464 100644
--- a/xiohelp.c
+++ b/xiohelp.c
@@ -48,7 +48,7 @@
"UNIX", "IP4", "IP6", "INTERFACE",
"UDP", "TCP", "SOCKS4", "OPENSSL",
"PROCESS", "APPL", "HTTP", "undef",
- "SCTP", "POSIXMQ"
+ "POSIXMQ", "SCTP", "DCCP"
} ;
/* keep consistent with xioopts.h:enum ephase ! */
diff --git a/xiomodes.h b/xiomodes.h
index 68b6fbd..911bc6d 100644
--- a/xiomodes.h
+++ b/xiomodes.h
@@ -31,6 +31,7 @@
#include "xio-tcp.h"
#include "xio-udp.h"
#include "xio-sctp.h"
+#include "xio-dccp.h"
#include "xio-socks.h"
#include "xio-socks5.h"
#include "xio-proxy.h"
diff --git a/xioopen.c b/xioopen.c
index 3ffa375..4599d1b 100644
--- a/xioopen.c
+++ b/xioopen.c
@@ -43,6 +43,32 @@
#endif
#if WITH_GENERICSOCKET
{ "DATAGRAM", &xioaddr_socket_datagram },
+#endif
+#if (WITH_IP4 || WITH_IP6) && WITH_DCCP
+ { "DCCP", &xioaddr_dccp_connect },
+ { "DCCP-CONNECT", &xioaddr_dccp_connect },
+#if WITH_LISTEN
+ { "DCCP-L", &xioaddr_dccp_listen },
+ { "DCCP-LISTEN", &xioaddr_dccp_listen },
+#endif
+#if WITH_IP4
+ { "DCCP4", &xioaddr_dccp4_connect },
+ { "DCCP4-CONNECT", &xioaddr_dccp4_connect },
+#if WITH_LISTEN
+ { "DCCP4-L", &xioaddr_dccp4_listen },
+ { "DCCP4-LISTEN", &xioaddr_dccp4_listen },
+#endif
+#endif /* WITH_IP4 */
+#if WITH_IP6
+ { "DCCP6", &xioaddr_dccp6_connect },
+ { "DCCP6-CONNECT", &xioaddr_dccp6_connect },
+#if WITH_LISTEN
+ { "DCCP6-L", &xioaddr_dccp6_listen },
+ { "DCCP6-LISTEN", &xioaddr_dccp6_listen },
+#endif
+#endif /* WITH_IP6 */
+#endif /* (WITH_IP4 || WITH_IP6) && WITH_DCCP */
+#if WITH_GENERICSOCKET
{ "DGRAM", &xioaddr_socket_datagram },
#endif
#if WITH_OPENSSL
diff --git a/xioopts.c b/xioopts.c
index a428586..a6d1849 100644
--- a/xioopts.c
+++ b/xioopts.c
@@ -96,6 +96,12 @@
# define IF_SCTP(a,b)
#endif
+#if WITH_DCCP
+# define IF_DCCP(a,b) {a,b},
+#else
+# define IF_DCCP(a,b)
+#endif
+
#if WITH_SOCKS4
# define IF_SOCKS4(a,b) {a,b},
#else
@@ -315,6 +321,9 @@
IF_ANY ("bytes", &opt_readbytes)
IF_OPENSSL("cafile", &opt_openssl_cafile)
IF_OPENSSL("capath", &opt_openssl_capath)
+#if defined(SOL_DCCP) && defined(DCCP_SOCKOPT_QPOLICY_ID)
+ IF_DCCP ("ccid", &xioopt_dccp_set_ccid)
+#endif
IF_ANY ("cd", &opt_chdir)
IF_OPENSSL("cert", &opt_openssl_certificate)
IF_OPENSSL("certificate", &opt_openssl_certificate)
@@ -392,6 +401,9 @@
IF_TERMIOS("ctlecho", &opt_echoctl)
IF_TERMIOS("ctty", &opt_tiocsctty)
IF_EXEC ("dash", &opt_dash)
+#if defined(SOL_DCCP) && defined(DCCP_SOCKOPT_QPOLICY_ID)
+ IF_DCCP ("dccp-set-ccid", &xioopt_dccp_set_ccid)
+#endif
IF_SOCKET ("debug", &opt_so_debug)
/*IF_RESOLVE("debug", &opt_res_debug)*/
#ifdef O_DEFER
diff --git a/xioopts.h b/xioopts.h
index f0f9894..21281ba 100644
--- a/xioopts.h
+++ b/xioopts.h
@@ -182,7 +182,6 @@
#define GROUP_IP_UDP 0x01000000 /* not yet used? */
#define GROUP_IP_TCP 0x02000000
-#define GROUP_IPAPP (GROUP_IP_UDP|GROUP_IP_TCP|GROUP_IP_SCTP) /* true: indicates one of UDP, TCP, SCTP */
#define GROUP_IP_SOCKS4 0x04000000
#define GROUP_OPENSSL 0x08000000
@@ -191,19 +190,20 @@
#define GROUP_HTTP 0x40000000 /* any HTTP client */
/* Keep condition consistent with xio.h:groups_t! */
-#if WITH_SCTP || WITH_POSIXMQ
+#if WITH_POSIXMQ || WITH_SCTP || WITH_DCCP
/* The following groups are not expected on systems without uint64_t */
-/* The following groups are not expected on systems withous uint64_t */
-#define GROUP_IP_SCTP 0x0100000000U
-#define GROUP_POSIXMQ 0x0200000000U
-#define GROUP_ALL 0x03ffffffffU
-#else
-#define GROUP_IP_SCTP 0
+#define GROUP_POSIXMQ 0x0100000000U
+#define GROUP_IP_SCTP 0x0200000000U
+#define GROUP_IP_DCCP 0x0400000000U
+#define GROUP_ALL 0x07ffffffffU
+#else /* !(WITH_POSIXMQ || WITH_SCTP || WITH_DCCP) */
#define GROUP_POSIXMQ 0
+#define GROUP_IP_SCTP 0
+#define GROUP_IP_DCCP 0
#define GROUP_ALL 0xffffffffU
-#endif
+#endif /* !(WITH_POSIXMQ || WITH_SCTP || WITH_DCCP) */
-#define GROUP_IPAPP (GROUP_IP_UDP|GROUP_IP_TCP|GROUP_IP_SCTP) /* true: indicates one of UDP, TCP, SCTP */
+#define GROUP_IPAPP (GROUP_IP_UDP|GROUP_IP_TCP|GROUP_IP_SCTP|GROUP_IP_DCCP) /* true: indicates one of UDP, TCP, SCTP, DCCP */
#define GROUP_ANY (GROUP_PROCESS|GROUP_APPL)
@@ -300,6 +300,7 @@
OPT_CSIZE, /* termios.c_cflag */
OPT_CSTOPB, /* termios.c_cflag */
OPT_DASH, /* exec() */
+ OPT_DCCP_SET_CCID,
OPT_ECHO, /* termios.c_lflag */
OPT_ECHOCTL, /* termios.c_lflag */
OPT_ECHOE, /* termios.c_lflag */