mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 15:48:49 -05:00
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:
parent
08fe4b3210
commit
b60d6404d8
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
24
lib/ftp.c
24
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)
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user