summaryrefslogtreecommitdiff
path: root/lib/system.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system.c')
-rw-r--r--lib/system.c80
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