]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
Gisle Vanem's fix to replace the bad use of strerror(). This introduces
authorDaniel Stenberg <daniel@haxx.se>
Wed, 24 Mar 2004 22:45:37 +0000 (22:45 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 24 Mar 2004 22:45:37 +0000 (22:45 +0000)
Curl_strerror() that attempts to be thread-safe _and_ works on Windows too!

lib/Makefile.am
lib/connect.c
lib/curl_strerror.c
lib/ftp.c
lib/urldata.h

index 788deda541586be870623cf14945cf0703aa6ea2..943eec28f931f3490c079c5927423ceb7823db3d 100644 (file)
@@ -4,14 +4,13 @@
 
 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
+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
 
 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    \
-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     \
-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              \
-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
+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  \
+  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   \
+  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 curl_strerror.c
 
 noinst_HEADERS = setup.h transfer.h
 
index 14d3a70b4a4c241d12b5fc618de07d7a3beeb0a0..04e3d234bb782a435c47b2661e518f6b00fd175c 100644 (file)
@@ -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;
       }
     }
index 677c1a685ba8c46628613097c0ffa3f5892609db..ac08978f5ad5c0eca1f094792c7d57790a9e7c50 100644 (file)
  ***************************************************************************/
 
 #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;
+}
index 369b61882531fe10a8e0afcc28b95135d4b42e42..32c159fe75ae372db7c33d24f1e982b2273b32b8 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -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;
   }
 
@@ -1248,18 +1255,19 @@ CURLcode ftp_use_port(struct connectdata *conn)
       /* do not transmit IPv6 scope identifier to the wire */
       if (sa->sa_family == AF_INET6) {
         char *q = strchr(portmsgbuf, '%');
-          if (q)
-            *q = '\0';
+        if (q)
+          *q = '\0';
       }
 
       result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
                              portmsgbuf, tmp);
       if(result)
         return result;
-    } else if (strcmp(*modep, "LPRT") == 0 ||
-               strcmp(*modep, "PORT") == 0) {
+    }
+    else if (strcmp(*modep, "LPRT") == 0 ||
+             strcmp(*modep, "PORT") == 0) {
       int i;
-      
+
       if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
         continue;
       if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
index 41b81deea39e7bb2a0ce8652422625e0a70194c5..e9bea7e4415959f6f947ee795b3790406faaa3fa 100644 (file)
@@ -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;