summaryrefslogtreecommitdiff
path: root/src/modules/extra/m_ssl_gnutls.cpp
diff options
context:
space:
mode:
authorAttila Molnar <attilamolnar@hush.com>2015-03-06 18:24:11 +0100
committerAttila Molnar <attilamolnar@hush.com>2015-03-06 18:24:11 +0100
commite1e7ab0a18100d7e2cde0eb8d787f6ce1f958643 (patch)
tree4cd50754b3a7dc1994f33c171be1a4193af8075d /src/modules/extra/m_ssl_gnutls.cpp
parent30b78bc2f4f7b74574abfbb3a3c2dc04686d2e7d (diff)
m_ssl_gnutls Set a vector push function on GnuTLS 2.12 and later
Setting a vector push function is recommended to reduce overhead during handshake
Diffstat (limited to 'src/modules/extra/m_ssl_gnutls.cpp')
-rw-r--r--src/modules/extra/m_ssl_gnutls.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp
index 12a776b06..a2bdb76ee 100644
--- a/src/modules/extra/m_ssl_gnutls.cpp
+++ b/src/modules/extra/m_ssl_gnutls.cpp
@@ -73,6 +73,7 @@ typedef gnutls_dh_params_t gnutls_dh_params;
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_HANDSHAKEN };
#if INSPIRCD_GNUTLS_HAS_VERSION(2, 12, 0)
+#define INSPIRCD_GNUTLS_HAS_VECTOR_PUSH
#define GNUTLS_NEW_CERT_CALLBACK_API
typedef gnutls_retr2_st cert_cb_last_param_type;
#else
@@ -833,6 +834,42 @@ info_done_dealloc:
return rv;
}
+#ifdef INSPIRCD_GNUTLS_HAS_VECTOR_PUSH
+ static ssize_t VectorPush(gnutls_transport_ptr_t transportptr, const giovec_t* iov, int iovcnt)
+ {
+ StreamSocket* sock = reinterpret_cast<StreamSocket*>(transportptr);
+#ifdef _WIN32
+ GnuTLSIOHook* session = static_cast<GnuTLSIOHook*>(sock->GetIOHook());
+#endif
+
+ if (sock->GetEventMask() & FD_WRITE_WILL_BLOCK)
+ {
+#ifdef _WIN32
+ gnutls_transport_set_errno(session->sess, EAGAIN);
+#else
+ errno = EAGAIN;
+#endif
+ return -1;
+ }
+
+ // Cast the giovec_t to iovec not to IOVector so the correct function is called on Windows
+ int ret = SocketEngine::WriteV(sock, reinterpret_cast<const iovec*>(iov), iovcnt);
+#ifdef _WIN32
+ // See the function above for more info about the usage of gnutls_transport_set_errno() on Windows
+ if (ret < 0)
+ gnutls_transport_set_errno(session->sess, SocketEngine::IgnoreError() ? EAGAIN : errno);
+#endif
+
+ int size = 0;
+ for (int i = 0; i < iovcnt; i++)
+ size += iov[i].iov_len;
+
+ if (ret < size)
+ SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
+ return ret;
+ }
+
+#else // INSPIRCD_GNUTLS_HAS_VECTOR_PUSH
static ssize_t gnutls_push_wrapper(gnutls_transport_ptr_t session_wrap, const void* buffer, size_t size)
{
StreamSocket* sock = reinterpret_cast<StreamSocket*>(session_wrap);
@@ -868,6 +905,7 @@ info_done_dealloc:
SocketEngine::ChangeEventMask(sock, FD_WRITE_WILL_BLOCK);
return rv;
}
+#endif // INSPIRCD_GNUTLS_HAS_VECTOR_PUSH
public:
GnuTLSIOHook(IOHookProvider* hookprov, StreamSocket* sock, inspircd_gnutls_session_init_flags_t flags, const reference<GnuTLS::Profile>& sslprofile)
@@ -878,7 +916,11 @@ info_done_dealloc:
{
gnutls_init(&sess, flags);
gnutls_transport_set_ptr(sess, reinterpret_cast<gnutls_transport_ptr_t>(sock));
+#ifdef INSPIRCD_GNUTLS_HAS_VECTOR_PUSH
+ gnutls_transport_set_vec_push_function(sess, VectorPush);
+#else
gnutls_transport_set_push_function(sess, gnutls_push_wrapper);
+#endif
gnutls_transport_set_pull_function(sess, gnutls_pull_wrapper);
profile->SetupSession(sess);