aboutsummaryrefslogtreecommitdiff
path: root/lib/gtls.c
diff options
context:
space:
mode:
authorMatthias Bolte <photron@users.sourceforge.net>2010-11-19 13:31:34 -0800
committerDan Fandrich <dan@coneharvesters.com>2010-11-19 13:34:07 -0800
commita83870ef9d1758de371551844efa4f17dda71581 (patch)
tree495eb436ba53e190d9cf2dfac94e42e3f847d485 /lib/gtls.c
parenta768e39b2d6bd60cbf71e983f1003b22603cb71e (diff)
Detect socket errors in GnuTLS on Windows
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. Bug: http://curl.haxx.se/bug/view.cgi?id=3110991
Diffstat (limited to 'lib/gtls.c')
-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()