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 +#include "setup.h" +#include +#include +#include + +#include "curl_strerror.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include 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;