aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-03-24 22:45:37 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-03-24 22:45:37 +0000
commitb60d6404d80ca58293761fc31ccf34df95116339 (patch)
tree14d6b39e5a0e74eea8bb4d6e805fdef9beb60706
parent08fe4b32109f636d1b55205941efac0e57bbc3e1 (diff)
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!
-rw-r--r--lib/Makefile.am43
-rw-r--r--lib/connect.c44
-rw-r--r--lib/curl_strerror.c230
-rw-r--r--lib/ftp.c24
-rw-r--r--lib/urldata.h2
5 files changed, 277 insertions, 66 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 788deda54..943eec28f 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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
diff --git a/lib/connect.c b/lib/connect.c
index 14d3a70b4..04e3d234b 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -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;
}
}
diff --git a/lib/curl_strerror.c b/lib/curl_strerror.c
index 677c1a685..ac08978f5 100644
--- a/lib/curl_strerror.c
+++ b/lib/curl_strerror.c
@@ -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;
+}
diff --git a/lib/ftp.c b/lib/ftp.c
index 369b61882..32c159fe7 100644
--- 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)
diff --git a/lib/urldata.h b/lib/urldata.h
index 41b81deea..e9bea7e44 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -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;