#include "../curl_setup.h"
#ifdef HAVE_STRERROR_R
# if (!defined(HAVE_POSIX_STRERROR_R) && \
!defined(HAVE_GLIBC_STRERROR_R)) || \
(defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R))
# error "strerror_r MUST be either POSIX, glibc style"
# endif
#endif
#include <curl/curl.h>
#ifndef WITHOUT_LIBCURL
#include <curl/mprintf.h>
#define SNPRINTF curl_msnprintf
#else
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define SNPRINTF _snprintf
#else
#define SNPRINTF snprintf
#endif
#endif
#include "winapi.h"
#include "strerr.h"
#include "../curl_memory.h"
#include "../memdebug.h"
#ifdef USE_WINSOCK
static const char *
get_winsock_error(int err, char *buf, size_t len)
{
#ifndef CURL_DISABLE_VERBOSE_STRINGS
const char *p;
size_t alen;
#endif
if(!len)
return NULL;
*buf = '\0';
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)err;
return NULL;
#else
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;
case WSASYSNOTREADY:
p = "Winsock library is not ready";
break;
case WSANOTINITIALISED:
p = "Winsock library not initialised";
break;
case WSAVERNOTSUPPORTED:
p = "Winsock version not supported";
break;
case WSAHOST_NOT_FOUND:
p = "Host not found";
break;
case WSATRY_AGAIN:
p = "Host not found, try again";
break;
case WSANO_RECOVERY:
p = "Unrecoverable error in call to nameserver";
break;
case WSANO_DATA:
p = "No data record of requested type";
break;
default:
return NULL;
}
alen = strlen(p);
if(alen < len)
strcpy(buf, p);
return buf;
#endif
}
#endif
const char *curlx_strerror(int err, char *buf, size_t buflen)
{
#ifdef _WIN32
DWORD old_win_err = GetLastError();
#endif
int old_errno = errno;
char *p;
if(!buflen)
return NULL;
#ifndef _WIN32
DEBUGASSERT(err >= 0);
#endif
*buf = '\0';
#ifdef _WIN32
#ifndef UNDER_CE
if(err >= 0 && err < sys_nerr)
SNPRINTF(buf, buflen, "%s", sys_errlist[err]);
else
#endif
{
if(
#ifdef USE_WINSOCK
!get_winsock_error(err, buf, buflen) &&
#endif
!curlx_get_winapi_error((DWORD)err, buf, buflen))
SNPRINTF(buf, buflen, "Unknown error %d (%#x)", err, err);
}
#else
#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
if(strerror_r(err, buf, buflen) &&
buflen > sizeof("Unknown error ") + 20) {
if(buf[0] == '\0')
SNPRINTF(buf, buflen, "Unknown error %d", err);
}
#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
{
char buffer[256];
char *msg = strerror_r(err, buffer, sizeof(buffer));
if(msg && buflen > 1)
SNPRINTF(buf, buflen, "%s", msg);
else if(buflen > sizeof("Unknown error ") + 20)
SNPRINTF(buf, buflen, "Unknown error %d", err);
}
#else
{
const char *msg = strerror(err);
if(msg && buflen > 1)
SNPRINTF(buf, buflen, "%s", msg);
else if(buflen > sizeof("Unknown error ") + 20)
SNPRINTF(buf, buflen, "Unknown error %d", err);
}
#endif
#endif
p = strrchr(buf, '\n');
if(p && (p - buf) >= 2)
*p = '\0';
p = strrchr(buf, '\r');
if(p && (p - buf) >= 1)
*p = '\0';
if(errno != old_errno)
CURL_SETERRNO(old_errno);
#ifdef _WIN32
if(old_win_err != GetLastError())
SetLastError(old_win_err);
#endif
return buf;
}