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 &#x5C;
     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 - &#x5C;
     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 */