diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/gtls.c | 41 | 
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() | 
