| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
- #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
- /* when built for the test servers */
- /* adjust for old MSVC */
- #if defined(_MSC_VER) && (_MSC_VER < 1900)
- #define SNPRINTF _snprintf
- #else
- #define SNPRINTF snprintf
- #endif
- #endif /* !WITHOUT_LIBCURL */
- #include "winapi.h"
- #include "strerr.h"
- /* The last 2 #include files should be in this order */
- #include "../curl_memory.h"
- #include "../memdebug.h"
- #ifdef USE_WINSOCK
- /* This is a helper function for curlx_strerror that converts Winsock error
- * codes (WSAGetLastError) to error messages.
- * Returns NULL if no error message was found for error code.
- */
- 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;
- /* Extended Winsock errors */
- 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;
- /* 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;
- }
- alen = strlen(p);
- if(alen < len)
- strcpy(buf, p);
- return buf;
- #endif
- }
- #endif /* USE_WINSOCK */
- /*
- * Our thread-safe and smart strerror() replacement.
- *
- * The 'err' argument passed in to this function MUST be a true errno number
- * as reported on this system. We do no range checking on the number before
- * we pass it to the "number-to-message" conversion function and there might
- * be systems that do not do proper range checking in there themselves.
- *
- * We do not do range checking (on systems other than Windows) since there is
- * no good reliable and portable way to do it.
- *
- * On Windows different types of error codes overlap. This function has an
- * order of preference when trying to match error codes:
- * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError).
- *
- * It may be more correct to call one of the variant functions instead:
- * Call Curl_sspi_strerror if the error code is definitely Windows SSPI.
- * Call curlx_winapi_strerror if the error code is definitely Windows API.
- */
- 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
- /* 'sys_nerr' is the maximum errno number, it is not widely portable */
- 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 /* !_WIN32 */
- #if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
- /*
- * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
- * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
- * message string, or EINVAL if 'errnum' is not a valid error number.
- */
- 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)
- /*
- * The glibc-style strerror_r() only *might* use the buffer we pass to
- * the function, but it always returns the error message as a pointer,
- * so we must copy that string unconditionally (if non-NULL).
- */
- {
- 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
- {
- /* !checksrc! disable BANNEDFUNC 1 */
- 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 /* _WIN32 */
- /* strip trailing '\r\n' or '\n'. */
- 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;
- }
|