aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/gtls.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/lib/gtls.c b/lib/gtls.c
index 84410eda8..93bb91de6 100644
--- a/lib/gtls.c
+++ b/lib/gtls.c
@@ -85,15 +85,52 @@ static bool gtls_inited = FALSE;
* We use custom functions rather than the GNU TLS defaults because it allows
* us to get specific about the fourth "flags" argument, and to use arbitrary
* private data with gnutls_transport_set_ptr if we wish.
+ *
+ * On Windows translate WSAGetLastError() to errno values as GNU TLS does it
+ * internally too. This is necessary because send() and recv() on Windows
+ * don't set errno when they fail but GNU TLS expects a proper errno value.
+ *
+ * Use gnutls_transport_set_global_errno() like the GNU TLS documentation
+ * suggests to avoid problems with different errno variables when GNU TLS and
+ * curl are linked to different versions of msvcrt.dll.
*/
+#ifdef USE_WINSOCK
+static void translate_wsa_to_errno(void)
+{
+ switch(WSAGetLastError()) {
+ case WSAEWOULDBLOCK:
+ gnutls_transport_set_global_errno(EAGAIN);
+ break;
+ case WSAEINTR:
+ gnutls_transport_set_global_errno(EINTR);
+ break;
+ default:
+ gnutls_transport_set_global_errno(EIO);
+ break;
+ }
+}
+#endif
+
static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
{
- return swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+ ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+#ifdef USE_WINSOCK
+ if(ret < 0) {
+ translate_wsa_to_errno();
+ }
+#endif
+ return ret;
}
static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
{
- return sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+ ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+#ifdef USE_WINSOCK
+ if(ret < 0) {
+ translate_wsa_to_errno();
+ }
+#endif
+ return ret;
}
/* Curl_gtls_init()