From 9d7d9997dfcb2de3b523228602983ed12dbf7e1a Mon Sep 17 00:00:00 2001 From: saradickinson Date: Fri, 24 Oct 2014 15:08:20 +0000 Subject: [PATCH 1/2] TCP fast open support (linux only). Enabled with --enable-tcp-fastopen configure option. --- configure | 24 ++++++++++++++++++++++++ configure.ac | 12 ++++++++++++ src/config.h.in | 3 +++ src/stub.c | 30 ++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 2 deletions(-) mode change 100644 => 100755 configure.ac diff --git a/configure b/configure index b4cbffe8..ab066f90 100755 --- a/configure +++ b/configure @@ -744,6 +744,7 @@ with_gnu_ld with_sysroot enable_libtool_lock enable_rpath +enable_tcp_fastopen with_libidn with_libldns with_libunbound @@ -1380,6 +1381,7 @@ Optional Features: optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-rpath disable hardcoded rpath (default=enabled) + --enable-tcp-fastopen Enable TCP Fast Open Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -10788,6 +10790,28 @@ if test "x$enable_rpath" = xno; then fi +# Check whether --enable-tcp-fastopen was given. +if test "${enable_tcp_fastopen+set}" = set; then : + enableval=$enable_tcp_fastopen; +fi + +case "$enable_tcp_fastopen" in + yes) + # TODO: Check if it is available (linux only) + { $as_echo "$as_me:${as_lineno-$LINENO}: TCP Fast Open enabled" >&5 +$as_echo "$as_me: TCP Fast Open enabled" >&6;} + +cat >>confdefs.h <<_ACEOF +#define USE_TCP_FASTOPEN 1 +_ACEOF + + ;; + no|*) + { $as_echo "$as_me:${as_lineno-$LINENO}: TCP Fast Open not enabled" >&5 +$as_echo "$as_me: TCP Fast Open not enabled" >&6;} + ;; +esac + # search to set include and library paths right # find libidn diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index 1a07a439..4e345a13 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,18 @@ fi ]) ACX_ARG_RPATH +AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--enable-tcp-fastopen], [Enable TCP Fast Open])) +case "$enable_tcp_fastopen" in + yes) + # TODO: Check if it is available (linux only) + AC_MSG_NOTICE([TCP Fast Open enabled]) + AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.]) + ;; + no|*) + AC_MSG_NOTICE([TCP Fast Open not enabled]) + ;; +esac + # search to set include and library paths right # find libidn AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], diff --git a/src/config.h.in b/src/config.h.in index d25ff728..bc517817 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -130,6 +130,9 @@ /* Needed for sync stub resolver functions */ #undef USE_MINI_EVENT +/* Define this to enable TCP fast open. */ +#undef USE_TCP_FASTOPEN + /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ diff --git a/src/stub.c b/src/stub.c index e287914b..3e44d961 100755 --- a/src/stub.c +++ b/src/stub.c @@ -802,11 +802,29 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) /* We have an initialized packet buffer. * Lets see how much of it we can write */ +#if defined (USE_TCP_FASTOPEN) && defined(MSG_FASTOPEN) + /* We use sendto() here which will do both a connect and send */ + written = sendto(fd, pkt, pkt_len + 2, MSG_FASTOPEN, + (struct sockaddr *)&(netreq->upstream->addr), + netreq->upstream->addr_len); + /* If pipelining we will find that the connection is already up so + just fall back to a 'normal' write. */ + if (written == -1 && errno == EISCONN) + written = write(fd, pkt, pkt_len + 2); + + if ((written == -1 && (errno == EAGAIN || + errno == EWOULDBLOCK || + /* Add the error case where the connection is in progress which is when + a cookie is not available (e.g. when doing the first request to an + upstream). We must let the handshake complete since non-blocking. */ + errno == EINPROGRESS)) || + written < pkt_len + 2) { +#else written = write(fd, pkt, pkt_len + 2); if ((written == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) || written < pkt_len + 2) { - +#endif /* We couldn't write the whole packet. * We have to return with STUB_TCP_AGAIN, but if * the packet was on the stack only, we have to copy @@ -834,7 +852,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) } else {/* if (! tcp->write_buf) */ - /* Coming back from an earlier unfinished write. + /* Coming back from an earlier unfinished write or handshake. * Try to send remaining data */ written = write(fd, tcp->write_buf + tcp->written, tcp->write_buf_len - tcp->written); @@ -998,12 +1016,16 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq) return GETDNS_RETURN_GENERIC_ERROR; getdns_sock_nonblock(netreq->fd); +#if defined (USE_TCP_FASTOPEN) && defined(MSG_FASTOPEN) + /* Leave the connect to the later call to sendto() */ +#else if (connect(netreq->fd, (struct sockaddr *)&upstream->addr, upstream->addr_len) == -1 && errno != EINPROGRESS) { close(netreq->fd); return GETDNS_RETURN_GENERIC_ERROR; } +#endif netreq->upstream = upstream; GETDNS_SCHEDULE_EVENT( @@ -1025,6 +1047,9 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq) return GETDNS_RETURN_GENERIC_ERROR; getdns_sock_nonblock(upstream->fd); +#if defined (USE_TCP_FASTOPEN) && defined(MSG_FASTOPEN) + /* Leave the connect to the later call to sendto() */ +#else if (connect(upstream->fd, (struct sockaddr *)&upstream->addr, upstream->addr_len) == -1 && errno != EINPROGRESS){ @@ -1033,6 +1058,7 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq) upstream->fd = -1; return GETDNS_RETURN_GENERIC_ERROR; } +#endif /* Attach to the global event loop * so it can do it's own scheduling */ From 0680e1144ff8ef4e8c93321270e703784c016200 Mon Sep 17 00:00:00 2001 From: saradickinson Date: Tue, 28 Oct 2014 17:37:11 +0000 Subject: [PATCH 2/2] Add detection of TFO support during configure --- configure | 61 +++++++++++++++++++++++++++++++++++++++++++++++----- configure.ac | 6 +++--- src/stub.c | 7 +++--- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/configure b/configure index ab066f90..68553361 100755 --- a/configure +++ b/configure @@ -1754,6 +1754,52 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_func +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl + # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -10797,9 +10843,16 @@ fi case "$enable_tcp_fastopen" in yes) - # TODO: Check if it is available (linux only) - { $as_echo "$as_me:${as_lineno-$LINENO}: TCP Fast Open enabled" >&5 -$as_echo "$as_me: TCP Fast Open enabled" >&6;} + ac_fn_c_check_decl "$LINENO" "MSG_FASTOPEN" "ac_cv_have_decl_MSG_FASTOPEN" "$ac_includes_default +#include + +" +if test "x$ac_cv_have_decl_MSG_FASTOPEN" = xyes; then : + +else + as_fn_error $? "TCP Fast Open is not available: please rerun without --enable-tcp-fastopen" "$LINENO" 5 +fi + cat >>confdefs.h <<_ACEOF #define USE_TCP_FASTOPEN 1 @@ -10807,8 +10860,6 @@ _ACEOF ;; no|*) - { $as_echo "$as_me:${as_lineno-$LINENO}: TCP Fast Open not enabled" >&5 -$as_echo "$as_me: TCP Fast Open not enabled" >&6;} ;; esac diff --git a/configure.ac b/configure.ac index 4e345a13..3ca5f550 100755 --- a/configure.ac +++ b/configure.ac @@ -82,12 +82,12 @@ ACX_ARG_RPATH AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--enable-tcp-fastopen], [Enable TCP Fast Open])) case "$enable_tcp_fastopen" in yes) - # TODO: Check if it is available (linux only) - AC_MSG_NOTICE([TCP Fast Open enabled]) + AC_CHECK_DECL([MSG_FASTOPEN], [], [AC_MSG_ERROR([TCP Fast Open is not available: please rerun without --enable-tcp-fastopen])], [AC_INCLUDES_DEFAULT +#include + ]) AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.]) ;; no|*) - AC_MSG_NOTICE([TCP Fast Open not enabled]) ;; esac diff --git a/src/stub.c b/src/stub.c index 3e44d961..aeb53f09 100755 --- a/src/stub.c +++ b/src/stub.c @@ -802,7 +802,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) /* We have an initialized packet buffer. * Lets see how much of it we can write */ -#if defined (USE_TCP_FASTOPEN) && defined(MSG_FASTOPEN) +#ifdef USE_TCP_FASTOPEN /* We use sendto() here which will do both a connect and send */ written = sendto(fd, pkt, pkt_len + 2, MSG_FASTOPEN, (struct sockaddr *)&(netreq->upstream->addr), @@ -1016,7 +1016,7 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq) return GETDNS_RETURN_GENERIC_ERROR; getdns_sock_nonblock(netreq->fd); -#if defined (USE_TCP_FASTOPEN) && defined(MSG_FASTOPEN) +#ifdef USE_TCP_FASTOPEN /* Leave the connect to the later call to sendto() */ #else if (connect(netreq->fd, (struct sockaddr *)&upstream->addr, @@ -1047,9 +1047,10 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq) return GETDNS_RETURN_GENERIC_ERROR; getdns_sock_nonblock(upstream->fd); -#if defined (USE_TCP_FASTOPEN) && defined(MSG_FASTOPEN) +#ifdef USE_TCP_FASTOPEN /* Leave the connect to the later call to sendto() */ #else + fprintf(stderr,"connecting"); if (connect(upstream->fd, (struct sockaddr *)&upstream->addr, upstream->addr_len) == -1 && errno != EINPROGRESS){