diff options
author | Tim Rühsen <tim.ruehsen@gmx.de> | 2016-07-14 12:31:55 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-07-15 13:46:49 +0200 |
commit | 1f98f7ceab7c331b8281ab39ffe9cd53c7ae765f (patch) | |
tree | 21015e52a6bd611b6f0ac9254c17aefdd83bb024 /lib/system.c | |
parent | c2e839247e14415b72c824726ddbc59fa54f941f (diff) | |
download | gnutls-fast-open.tar.gz |
Support TCP Fast Openfast-open
New function gnutls_transport_set_fastopen() with example usage
in gnutls-cli (enabled with new --fastopen option).
Diffstat (limited to 'lib/system.c')
-rw-r--r-- | lib/system.c | 80 |
1 files changed, 70 insertions, 10 deletions
diff --git a/lib/system.c b/lib/system.c index 5c9bc6e68f..e08510d283 100644 --- a/lib/system.c +++ b/lib/system.c @@ -31,6 +31,11 @@ #include <sys/types.h> #include <c-ctype.h> +/* Get TCP_FASTOPEN */ +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif + #ifdef _WIN32 # include <windows.h> # include <wincrypt.h> @@ -111,10 +116,9 @@ int system_errno(gnutls_transport_ptr_t ptr) return errno; } -#ifdef MSG_NOSIGNAL -ssize_t -system_writev_nosignal(gnutls_transport_ptr_t ptr, const giovec_t * iovec, - int iovec_cnt) +static ssize_t +_system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, + int iovec_cnt, int flags) { struct msghdr hdr; @@ -122,21 +126,77 @@ system_writev_nosignal(gnutls_transport_ptr_t ptr, const giovec_t * iovec, hdr.msg_iov = (struct iovec *)iovec; hdr.msg_iovlen = iovec_cnt; - return sendmsg(GNUTLS_POINTER_TO_INT(ptr), &hdr, MSG_NOSIGNAL); + return sendmsg(GNUTLS_POINTER_TO_INT(ptr), &hdr, flags); } -#endif -ssize_t -system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, - int iovec_cnt) +static ssize_t +_system_writev_tfo(gnutls_session_t session, const giovec_t * iovec, + int iovec_cnt, int flags) { + int fd = GNUTLS_POINTER_TO_INT(session->internals.transport_send_ptr); + int ret, on = 1; + struct msghdr hdr; + if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on)) == -1) + _gnutls_debug_log("Failed to set socket option FASTOPEN\n"); + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_name = session->internals.connect_addr; + hdr.msg_namelen = session->internals.connect_addrlen; hdr.msg_iov = (struct iovec *)iovec; hdr.msg_iovlen = iovec_cnt; - return sendmsg(GNUTLS_POINTER_TO_INT(ptr), &hdr, 0); + ret = sendmsg(fd, &hdr, flags | MSG_FASTOPEN); + + if (ret < 0) { + if (errno == EINPROGRESS) { + errno = EAGAIN; // GnuTLS does not handle EINPROGRESS + } else if (errno == EOPNOTSUPP) { + // fallback from fastopen, e.g. when fastopen is disabled in system + _gnutls_debug_log("Fallback from TCP Fast Open... TFO is not enabled at system level\n"); + ret = connect(fd, session->internals.connect_addr, session->internals.connect_addrlen); + if (errno == ENOTCONN || errno == EINPROGRESS) + errno = EAGAIN; + } + } + + /* This function has to be called just once, connect info not needed any more */ + gnutls_free(session->internals.connect_addr); + session->internals.connect_addr = NULL; + session->internals.connect_addrlen = 0; + + return ret; +} + +#ifdef MSG_NOSIGNAL +ssize_t +system_writev_nosignal(gnutls_transport_ptr_t ptr, const giovec_t * iovec, + int iovec_cnt) +{ + return _system_writev(ptr, iovec, iovec_cnt, MSG_NOSIGNAL); +} + +ssize_t +system_writev_nosignal_tfo(gnutls_session_t session, const giovec_t * iovec, + int iovec_cnt) +{ + return _system_writev_tfo(session, iovec, iovec_cnt, MSG_NOSIGNAL); +} +#endif + +ssize_t +system_writev(gnutls_transport_ptr_t ptr, const giovec_t * iovec, + int iovec_cnt) +{ + return _system_writev(ptr, iovec, iovec_cnt, 0); +} + +ssize_t +system_writev_tfo(gnutls_session_t session, const giovec_t * iovec, + int iovec_cnt) +{ + return _system_writev_tfo(session, iovec, iovec_cnt, 0); } #endif |