Commit b60d6404 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Gisle Vanem's fix to replace the bad use of strerror(). This introduces

Curl_strerror() that attempts to be thread-safe _and_ works on Windows too!
parent 08fe4b32
Loading
Loading
Loading
Loading
+21 −22
Original line number Diff line number Diff line
@@ -5,13 +5,12 @@
AUTOMAKE_OPTIONS = foreign nostdinc

EXTRA_DIST = getdate.y Makefile.b32 Makefile.b32.resp Makefile.m32	\
       Makefile.vc6 Makefile.riscos libcurl.def curllib.dsp		    \
       curllib.dsw config-vms.h config-win32.h config-riscos.h config-mac.h \
       config.h.in ca-bundle.crt README.encoding README.memoryleak	    \
       README.ares makefile.dj config.dj				    \
       libcurl.framework.make libcurl.plist libcurl.rc \
       config-amigaos.h amigaos.c amigaos.h makefile.amiga config-netware.h \
       Makefile.netware nwlib.c libcurl.imp
  Makefile.vc6 Makefile.riscos libcurl.def curllib.dsp curllib.dsw	\
  config-vms.h config-win32.h config-riscos.h config-mac.h config.h.in	\
  ca-bundle.crt README.encoding README.memoryleak README.ares		\
  makefile.dj config.dj libcurl.framework.make libcurl.plist		\
  libcurl.rc config-amigaos.h amigaos.c amigaos.h makefile.amiga	\
  config-netware.h Makefile.netware nwlib.c libcurl.imp

lib_LTLIBRARIES = libcurl.la

@@ -63,20 +62,20 @@ endif

libcurl_la_LDFLAGS = $(UNDEF) $(VERSION) $(MIMPURE)

libcurl_la_SOURCES = arpa_telnet.h file.c netrc.h timeval.c	\
base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c	\
hostip.h progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c	\
http.h sendf.h url.c dict.c ftp.h if2ip.c speedcheck.c url.h dict.h	\
libcurl_la_SOURCES = arpa_telnet.h file.c netrc.h timeval.c base64.c	\
  file.h hostip.c progress.c timeval.h base64.h formdata.c hostip.h	\
  progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c http.h	\
  sendf.h url.c dict.c ftp.h if2ip.c speedcheck.c url.h dict.h		\
  getdate.c if2ip.h speedcheck.h urldata.h getdate.h ldap.c ssluse.c	\
version.c getenv.c ldap.h ssluse.h escape.c mprintf.c telnet.c escape.h	\
netrc.c telnet.h getinfo.c getinfo.h transfer.c strequal.c	\
  version.c getenv.c ldap.h ssluse.h escape.c mprintf.c telnet.c	\
  escape.h netrc.c telnet.h getinfo.c getinfo.h transfer.c strequal.c	\
  strequal.h easy.c security.h security.c krb4.c krb4.h memdebug.c	\
memdebug.h inet_ntoa_r.h http_chunks.c http_chunks.h strtok.c strtok.h	\
connect.c connect.h llist.c llist.h hash.c hash.h multi.c		\
  memdebug.h inet_ntoa_r.h http_chunks.c http_chunks.h strtok.c		\
  strtok.h connect.c connect.h llist.c llist.h hash.c hash.h multi.c	\
  content_encoding.c content_encoding.h share.c share.h http_digest.c	\
  md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h		\
  http_ntlm.c http_ntlm.h ca-bundle.h inet_pton.c inet_pton.h		\
strtoofft.c strtoofft.h
  strtoofft.c strtoofft.h curl_strerror.c

noinst_HEADERS = setup.h transfer.h

+8 −36
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@
#include "urldata.h"
#include "sendf.h"
#include "if2ip.h"
#include "curl_strerror.h"
#include "connect.h"

/* The last #include file should be: */
@@ -295,7 +296,7 @@ static CURLcode bindlocal(struct connectdata *conn,
      if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                     data->set.device, strlen(data->set.device)+1) != 0) {
        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
           sockfd, data->set.device, strerror(Curl_ourerrno())); */
           sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
        infof(data, "SO_BINDTODEVICE %s failed\n",
              data->set.device);
        /* This is typically "errno 1, error: Operation not permitted" if
@@ -353,38 +354,9 @@ static CURLcode bindlocal(struct connectdata *conn,
        }
#endif
        if(!bindworked) {
          int err = Curl_ourerrno();
          switch(err) {
          case EBADF:
            failf(data, "Invalid descriptor: %d", err);
            break;
          case EINVAL:
            failf(data, "Invalid request: %d", err);
            break;
          case EACCES:
            failf(data, "Address is protected, user not superuser: %d", err);
            break;
          case ENOTSOCK:
            failf(data,
                  "Argument is a descriptor for a file, not a socket: %d",
                  err);
            break;
          case EFAULT:
            failf(data, "Inaccessable memory error: %d", err);
            break;
          case ENAMETOOLONG:
            failf(data, "Address too long: %d", err);
            break;
          case ENOMEM:
            failf(data, "Insufficient kernel memory was available: %d", err);
            break;
          default:
            failf(data, "errno %d", err);
            break;
          } /* end of switch(err) */
	
          failf(data, "%s", Curl_strerror(conn, Curl_ourerrno()));
          return CURLE_HTTP_PORT_FAILED;
        } /* end of else */
        }
	
      } /* end of if  h */
      else {
@@ -489,8 +461,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
  }
  else if(1 != rc) {
    int error = Curl_ourerrno();
    failf(data, "Failed connect to %s:%d, errno: %d",
          conn->hostname, conn->port, error);
    failf(data, "Failed connect to %s:%d; %s",
          conn->hostname, conn->port, Curl_strerror(conn,error));
    return CURLE_COULDNT_CONNECT;
  }
  /*
@@ -652,8 +624,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
        break;
      default:
        /* unknown error, fallthrough and try another address! */
        failf(data, "Failed to connect to %s IP number %d: %d",
              hostname, aliasindex+1, error);
        failf(data, "Failed to connect to %s IP number %d: %s",
              hostname, aliasindex+1, Curl_strerror(conn,error));
        break;
      }
    }
+230 −0
Original line number Diff line number Diff line
@@ -21,6 +21,15 @@
 ***************************************************************************/

#include <curl/curl.h>
#include "setup.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "curl_strerror.h"

#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>

const char *
curl_easy_strerror(CURLcode error)
@@ -294,3 +303,224 @@ curl_share_strerror(CURLSHcode error)

  return "CURLSH unknown";
}

#if defined(WIN32) && !defined(__CYGWIN__)

/* This function handles most / all (?) Winsock errors cURL is able to produce.
 */
static const char *
get_winsock_error (int err, char *buf, size_t len)
{
  char *p;

  switch (err)
  {
    case WSAEINTR:
        p = "Call interrupted.";
        break;
    case WSAEBADF:
        p = "Bad file";
        break;
    case WSAEACCES:
        p = "Bad access";
        break;
    case WSAEFAULT:
        p = "Bad argument";
        break;
    case WSAEINVAL:
        p = "Invalid arguments";
        break;
    case WSAEMFILE:
        p = "Out of file descriptors";
        break;
    case WSAEWOULDBLOCK:
        p = "Call would block";
        break;
    case WSAEINPROGRESS:
    case WSAEALREADY:
        p = "Blocking call in progress";
        break;
    case WSAENOTSOCK:
        p = "Descriptor is not a socket.";
        break;
    case WSAEDESTADDRREQ:
        p = "Need destination address";
        break;
    case WSAEMSGSIZE:
        p = "Bad message size";
        break;
    case WSAEPROTOTYPE:
        p = "Bad protocol";
        break;
    case WSAENOPROTOOPT:
        p = "Protocol option is unsupported";
        break;
    case WSAEPROTONOSUPPORT:
        p = "Protocol is unsupported";
        break;
    case WSAESOCKTNOSUPPORT:
        p = "Socket is unsupported";
        break;
    case WSAEOPNOTSUPP:
        p = "Operation not supported";
        break;
    case WSAEAFNOSUPPORT:
        p = "Address family not supported";
        break;
    case WSAEPFNOSUPPORT:
        p = "Protocol family not supported";
        break;
    case WSAEADDRINUSE:
        p = "Address already in use";
        break;
    case WSAEADDRNOTAVAIL:
        p = "Address not available";
        break;
    case WSAENETDOWN:
        p = "Network down";
        break;
    case WSAENETUNREACH:
        p = "Network unreachable";
        break;
    case WSAENETRESET:
        p = "Network has been reset";
        break;
    case WSAECONNABORTED:
        p = "Connection was aborted";
        break;
    case WSAECONNRESET:
        p = "Connection was reset";
        break;
    case WSAENOBUFS:
        p = "No buffer space";
        break;
    case WSAEISCONN:
        p = "Socket is already connected";
        break;
    case WSAENOTCONN:
        p = "Socket is not connected";
        break;
    case WSAESHUTDOWN:
        p = "Socket has been shut down";
        break;
    case WSAETOOMANYREFS:
        p = "Too many references";
        break;
    case WSAETIMEDOUT:
        p = "Timed out";
        break;
    case WSAECONNREFUSED:
        p = "Connection refused";
        break;
    case WSAELOOP:
        p = "Loop??";
        break;
    case WSAENAMETOOLONG:
        p = "Name too long";
        break;
    case WSAEHOSTDOWN:
        p = "Host down";
        break;
    case WSAEHOSTUNREACH:
        p = "Host unreachable";
        break;
    case WSAENOTEMPTY:
        p = "Not empty";
        break;
    case WSAEPROCLIM:
        p = "Process limit reached";
        break;
    case WSAEUSERS:
        p = "Too many users";
        break;
    case WSAEDQUOT:
        p = "Bad quota";
        break;
    case WSAESTALE:
        p = "Something is stale";
        break;
    case WSAEREMOTE:
        p = "Remote error";
        break;
    case WSAEDISCON:
        p = "Disconnected";
        break;

    /* Extended Winsock errors */
    case WSASYSNOTREADY:
        p = "Winsock library is not ready";
        break;
    case WSANOTINITIALISED:
        p = "Winsock library not initalised";
        break;
    case WSAVERNOTSUPPORTED:
        p = "Winsock version not supported.";
        break;

    /* getXbyY() errors (already handled in herrmsg):
     * Authoritative Answer: Host not found */
    case WSAHOST_NOT_FOUND:
        p = "Host not found";
        break;

    /* Non-Authoritative: Host not found, or SERVERFAIL */
    case WSATRY_AGAIN:
        p = "Host not found, try again";
        break;

    /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
    case WSANO_RECOVERY:
        p = "Unrecoverable error in call to nameserver";
        break;

    /* Valid name, no data record of requested type */
    case WSANO_DATA:
        p = "No data record of requested type";
        break;

    default:
        return NULL;
  }
  strncpy (buf, p, len);
  buf [len-1] = '\0';
  return buf;
}
#endif   /* WIN32 && !__CYGWIN__ */

/*
 * Our thread-safe and smart strerror() replacement.
 */
const char *Curl_strerror(struct connectdata *conn, int err)
{
  char *buf, *p;
  size_t max;

  curlassert(conn);

  buf = conn->syserr_buf;
  max = sizeof(conn->syserr_buf)-1;
  *buf = '\0';
  if (err >= 0 && err < sys_nerr) {
    /* These should be atomic and hopefully thread-safe */
#ifdef HAVE_STRERROR_R
    strerror_r(err, buf, max); /* this may set ERANGE! */
#else
    strncpy(buf, strerror(err), max);
#endif
    *(buf+max) = '\0';
  }
  else
#if defined(WIN32) && !defined(__CYGWIN__)
    if (!get_winsock_error (err, buf, max) &&
        !FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
                        LANG_NEUTRAL, buf, max, NULL))
#endif
     snprintf(buf, max, "Unknown error %d (%#x)", err, err);

  /* strip trailing '\r\n' or '\n'. */
  if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2)
     *p = '\0';
  if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
     *p = '\0';
  return buf;
}
+16 −8
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@
#include "strequal.h"
#include "ssluse.h"
#include "connect.h"
#include "curl_strerror.h"

#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
@@ -1138,6 +1139,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
  const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
  char **modep;
  int rc;
  int error;

  /*
   * we should use Curl_if2ip?  given pickiness of recent ftpd,
@@ -1172,6 +1174,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
  }
  
  portsock = CURL_SOCKET_BAD;
  error = 0;
  for (ai = res; ai; ai = ai->ai_next) {
    /*
     * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
@@ -1180,16 +1183,20 @@ CURLcode ftp_use_port(struct connectdata *conn)
      ai->ai_socktype = hints.ai_socktype;

    portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (portsock == CURL_SOCKET_BAD)
    if (portsock == CURL_SOCKET_BAD) {
      error = Curl_ourerrno();
      continue;
    }

    if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
      error = Curl_ourerrno();
      sclose(portsock);
      portsock = CURL_SOCKET_BAD;
      continue;
    }
      
    if (listen(portsock, 1) < 0) {
      error = Curl_ourerrno();
      sclose(portsock);
      portsock = CURL_SOCKET_BAD;
      continue;
@@ -1199,13 +1206,13 @@ CURLcode ftp_use_port(struct connectdata *conn)
  }
  freeaddrinfo(res);
  if (portsock == CURL_SOCKET_BAD) {
    failf(data, "%s", strerror(errno));
    failf(data, "%s", Curl_strerror(conn,error));
    return CURLE_FTP_PORT_FAILED;
  }

  sslen = sizeof(ss);
  if (getsockname(portsock, sa, &sslen) < 0) {
    failf(data, "%s", strerror(errno));
    failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
    return CURLE_FTP_PORT_FAILED;
  }

@@ -1256,7 +1263,8 @@ CURLcode ftp_use_port(struct connectdata *conn)
                             portmsgbuf, tmp);
      if(result)
        return result;
    } else if (strcmp(*modep, "LPRT") == 0 ||
    }
    else if (strcmp(*modep, "LPRT") == 0 ||
             strcmp(*modep, "PORT") == 0) {
      int i;

+2 −0
Original line number Diff line number Diff line
@@ -572,6 +572,8 @@ struct connectdata {

  int sockerror; /* errno stored by Curl_read() if the underlying layer returns
                    error */
  char syserr_buf [256]; /* buffer for Curl_strerror() */

#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
  /* data used for the asynch name resolve callback */
  struct Curl_async async;