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!
This commit is contained in:
Daniel Stenberg 2004-03-24 22:45:37 +00:00
parent 08fe4b3210
commit b60d6404d8
5 changed files with 277 additions and 66 deletions

View 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

View 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;
}
}

View File

@ -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;
}

View File

@ -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)

View 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;