1 /* $Id: ncbi_strerror.c 602352 2020-02-21 18:08:17Z lavr $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors:  Pavel Ivanov, Anton Lavrentiev, Denis Vakatov
27  *
28  * File Description:
29  *   errno->text conversion helper
30  */
31 
32 
33 #ifdef NCBI_INCLUDE_STRERROR_C
34 
35 
36 #  ifdef _FREETDS_LIBRARY_SOURCE
37 
38 #    include "../impl/ncbi_ftds_ver.h"
39 #    define s_StrError        s_StrErrorInternal
40 #    define UTIL_TcharToUtf8  NCBI_FTDS_VERSION_NAME(UTIL_TcharToUtf8_ftds)
41 #    define UTIL_ReleaseBufferOnHeap  \
42                       NCBI_FTDS_VERSION_NAME(UTIL_ReleaseBufferOnHeap_ftds)
43 
44 #  endif /*_FREETDS_LIBRARY_SOURCE*/
45 
46 
47 #  if defined(NCBI_OS_MSWIN)  &&  defined(_UNICODE)
48 
s_WinStrdup(const char * str)49 static const char* s_WinStrdup(const char* str)
50 {
51     size_t n = strlen(str);
52     char*  s = (char*) LocalAlloc(LMEM_FIXED, ++n * sizeof(*s));
53     return s ? (const char*) memcpy(s, str, n) : 0;
54 }
55 #    define        ERR_STRDUP(s)          s_WinStrdup(s)
56 
UTIL_TcharToUtf8(const TCHAR * str)57 extern const char* UTIL_TcharToUtf8(const TCHAR* str)
58 {
59     char* s = NULL;
60     if (str) {
61         /* Note "-1" means to consume all input including the trailing NUL */
62         int n = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
63         if (n > 0) {
64             s = (char*) LocalAlloc(LMEM_FIXED, n * sizeof(*s));
65             if (s)
66                 WideCharToMultiByte(CP_UTF8, 0, str, -1, s,    n, NULL, NULL);
67         }
68     }
69     return s;
70 }
71 
72 #    ifndef        UTIL_ReleaseBuffer(x)
73 #      define      UTIL_ReleaseBuffer(x)   UTIL_ReleaseBufferOnHeap(x)
74 #    endif
75 
76 #  else /*NCBI_OS_MSWIN && _UNICODE*/
77 
78 #    define        ERR_STRDUP(s)           strdup(s)
79 
80 #    ifdef         UTIL_TcharToUtf8
81 #      undef       UTIL_TcharToUtf8
82 #    endif
83 #    define        UTIL_TcharToUtf8(x)     strdup(x)
84 
85 #    ifdef         UTIL_ReleaseBuffer
86 #      undef       UTIL_ReleaseBuffer
87 #    endif
88 #    define        UTIL_ReleaseBuffer(x)   free((void*)(x))
89 
90 #  endif /*NCBI_OS_MSWIN && _UNICODE*/
91 
92 
93 #  ifdef NCBI_OS_MSWIN
94 
UTIL_ReleaseBufferOnHeap(const void * ptr)95 extern void        UTIL_ReleaseBufferOnHeap(const void* ptr)
96 {
97     if (ptr)
98         LocalFree((HLOCAL) ptr);
99 }
100 
101 #  endif /*NCBI_OS_MSWIN*/
102 
103 
s_StrErrorInternal(int error)104 static const char* s_StrErrorInternal(int error)
105 {
106     static const struct {
107         int         errnum;
108         const char* errstr;
109     } errmap[] = {
110 #  ifdef NCBI_OS_MSWIN
111         {WSAEINTR,              "Interrupted system call"},
112         {WSAEBADF,              "Bad file number"},
113         {WSAEACCES,             "Access denied"},
114         {WSAEFAULT,             "Segmentation fault"},
115         {WSAEINVAL,             "Invalid agrument"},
116         {WSAEMFILE,             "Too many open files"},
117         /*
118          * Windows Sockets definitions of regular Berkeley error constants
119          */
120         {WSAEWOULDBLOCK,        "Resource temporarily unavailable"},
121         {WSAEINPROGRESS,        "Operation now in progress"},
122         {WSAEALREADY,           "Operation already in progress"},
123         {WSAENOTSOCK,           "Not a socket"},
124         {WSAEDESTADDRREQ,       "Destination address required"},
125         {WSAEMSGSIZE,           "Invalid message size"},
126         {WSAEPROTOTYPE,         "Wrong protocol type"},
127         {WSAENOPROTOOPT,        "Bad protocol option"},
128         {WSAEPROTONOSUPPORT,    "Protocol not supported"},
129         {WSAESOCKTNOSUPPORT,    "Socket type not supported"},
130         {WSAEOPNOTSUPP,         "Operation not supported"},
131         {WSAEPFNOSUPPORT,       "Protocol family not supported"},
132         {WSAEAFNOSUPPORT,       "Address family not supported"},
133         {WSAEADDRINUSE,         "Address already in use"},
134         {WSAEADDRNOTAVAIL,      "Cannot assign requested address"},
135         {WSAENETDOWN,           "Network is down"},
136         {WSAENETUNREACH,        "Network is unreachable"},
137         {WSAENETRESET,          "Connection dropped on network reset"},
138         {WSAECONNABORTED,       "Software caused connection abort"},
139         {WSAECONNRESET,         "Connection reset by peer"},
140         {WSAENOBUFS,            "No buffer space available"},
141         {WSAEISCONN,            "Socket is already connected"},
142         {WSAENOTCONN,           "Socket is not connected"},
143         {WSAESHUTDOWN,          "Cannot send after socket shutdown"},
144         {WSAETOOMANYREFS,       "Too many references"},
145         {WSAETIMEDOUT,          "Operation timed out"},
146         {WSAECONNREFUSED,       "Connection refused"},
147         {WSAELOOP,              "Infinite loop"},
148         {WSAENAMETOOLONG,       "Name too long"},
149         {WSAEHOSTDOWN,          "Host is down"},
150         {WSAEHOSTUNREACH,       "Host unreachable"},
151         {WSAENOTEMPTY,          "Not empty"},
152         {WSAEPROCLIM,           "Too many processes"},
153         {WSAEUSERS,             "Too many users"},
154         {WSAEDQUOT,             "Quota exceeded"},
155         {WSAESTALE,             "Stale descriptor"},
156         {WSAEREMOTE,            "Remote error"},
157         /*
158          * Extended Windows Sockets error constant definitions
159          */
160         {WSASYSNOTREADY,        "Network subsystem is unavailable"},
161         {WSAVERNOTSUPPORTED,    "Winsock.dll version out of range"},
162         {WSANOTINITIALISED,     "Not yet initialized"},
163         {WSAEDISCON,            "Graceful shutdown in progress"},
164 #    ifdef WSAENOMORE
165         /*NB: replaced with WSA_E_NO_MORE*/
166         {WSAENOMORE,            "No more data available"},
167 #    endif /*WSAENOMORE*/
168 #    ifdef WSA_E_NO_MORE
169         {WSA_E_NO_MORE,         "No more data available"},
170 #    endif /*WSA_E_NO_MORE*/
171 #    ifdef WSAECANCELLED
172         /*NB: replaced with WSA_E_CANCELLED*/
173         {WSAECANCELLED,         "Call has been cancelled"},
174 #    endif /*WSAECANCELLED*/
175 #    ifdef WSA_E_CANCELLED
176         {WSA_E_CANCELLED,       "Call has been cancelled"},
177 #    endif /*WSA_E_CANCELLED*/
178         {WSAEINVALIDPROCTABLE,  "Invalid procedure table"},
179         {WSAEINVALIDPROVIDER,   "Invalid provider version number"},
180         {WSAEPROVIDERFAILEDINIT,"Cannot init provider"},
181         {WSASYSCALLFAILURE,     "System call failed"},
182         {WSASERVICE_NOT_FOUND,  "Service not found"},
183         {WSATYPE_NOT_FOUND,     "Class type not found"},
184         {WSAEREFUSED,           "Query refused"},
185         /*
186          * WinSock 2 extension
187          */
188 #    ifdef WSA_IO_PENDING
189         {WSA_IO_PENDING,        "Operation has been queued"},
190 #    endif /*WSA_IO_PENDING*/
191 #    ifdef WSA_IO_INCOMPLETE
192         {WSA_IO_INCOMPLETE,     "Operation still in progress"},
193 #    endif /*WSA_IO_INCOMPLETE*/
194 #    ifdef WSA_INVALID_HANDLE
195         {WSA_INVALID_HANDLE,    "Invalid handle"},
196 #    endif /*WSA_INVALID_HANDLE*/
197 #    ifdef WSA_INVALID_PARAMETER
198         {WSA_INVALID_PARAMETER, "Invalid parameter"},
199 #    endif /*WSA_INVALID_PARAMETER*/
200 #    ifdef WSA_NOT_ENOUGH_MEMORY
201         {WSA_NOT_ENOUGH_MEMORY, "Out of memory"},
202 #    endif /*WSA_NOT_ENOUGH_MEMORY*/
203 #    ifdef WSA_OPERATION_ABORTED
204         {WSA_OPERATION_ABORTED, "Operation aborted"},
205 #    endif /*WSA_OPERATION_ABORTED*/
206 #  endif /*NCBI_OS_MSWIN*/
207 #  ifdef NCBI_OS_MSWIN
208 #    define EAI_BASE  0
209 #  else
210 #    define EAI_BASE  100000
211 #  endif /*NCBI_OS_MSWIN*/
212 #  ifdef EAI_ADDRFAMILY
213         {EAI_ADDRFAMILY + EAI_BASE,
214                                 "Address family not supported"},
215 #  endif /*EAI_ADDRFAMILY*/
216 #  ifdef EAI_AGAIN
217         {EAI_AGAIN + EAI_BASE,
218                                 "Temporary failure in name resolution"},
219 #  endif /*EAI_AGAIN*/
220 #  ifdef EAI_BADFLAGS
221         {EAI_BADFLAGS + EAI_BASE,
222                                 "Invalid value for lookup flags"},
223 #  endif /*EAI_BADFLAGS*/
224 #  ifdef EAI_FAIL
225         {EAI_FAIL + EAI_BASE,
226                                 "Non-recoverable failure in name resolution"},
227 #  endif /*EAI_FAIL*/
228 #  ifdef EAI_FAMILY
229         {EAI_FAMILY + EAI_BASE,
230                                 "Address family not supported"},
231 #  endif /*EAI_FAMILY*/
232 #  ifdef EAI_MEMORY
233         {EAI_MEMORY + EAI_BASE,
234                                 "Memory allocation failure"},
235 #  endif /*EAI_MEMORY*/
236 #  ifdef EAI_NODATA
237 #    if EAI_NODATA != EAI_NONAME
238         {EAI_NODATA + EAI_BASE,
239                                 "No address associated with nodename"},
240 #    endif /*EAI_NODATA!=EAI_NONAME*/
241 #  endif /*EAI_NODATA*/
242 #  ifdef EAI_NONAME
243         {EAI_NONAME + EAI_BASE,
244                                 "Host and/or service name unknown"},
245 #  endif /*EAI_NONAME*/
246 #  ifdef EAI_OVERFLOW
247         {EAI_OVERFLOW + EAI_BASE,
248                                 "Argument buffer overflow"},
249 #  endif /*EAI_OVERFLOW*/
250 #  ifdef EAI_SERVICE
251         {EAI_SERVICE + EAI_BASE,
252                                 "Service name not supported for socket type"},
253 #  endif /*EAI_SERVICE*/
254 #  ifdef EAI_SOCKTYPE
255         {EAI_SOCKTYPE + EAI_BASE,
256                                 "Socket type not supported"},
257 #  endif /*EAI_SOCKTYPE*/
258         /* GNU extensions */
259 #  ifdef EAI_ALLDONE
260         {EAI_ALLDONE + EAI_BASE,
261                                 "All requests done"},
262 #  endif /*EAI_ALLDONE*/
263 #  ifdef EAI_CANCELED
264         {EAI_CANCELED + EAI_BASE,
265                                 "Request canceled"},
266 #  endif /*EAI_BADFLAGS*/
267 #  ifdef EAI_INPROGRESS
268         {EAI_INPROGRESS + EAI_BASE,
269                                 "Processing request in progress"},
270 #  endif /*EAI_INPROGRESS*/
271 #  ifdef EAI_INTR
272         {EAI_INTR + EAI_BASE,
273                                 "Interrupted by a signal"},
274 #  endif /*EAI_INTR*/
275 #  ifdef EAI_NOTCANCELED
276         {EAI_NOTCANCELED + EAI_BASE,
277                                 "Request not canceled"},
278 #  endif /*EAI_NOTCANCELED*/
279 #  ifdef EAI_IDN_ENCODE
280         {EAI_IDN_ENCODE + EAI_BASE,
281                                 "IDN encoding failed"},
282 #  endif /*EAI_IDN_ENCODE*/
283 #  ifdef NCBI_OS_MSWIN
284 #    define DNS_BASE  0
285 #  else
286 #    define DNS_BASE  200000
287 #  endif /*NCBI_OS_MSWIN*/
288 #  ifdef HOST_NOT_FOUND
289         {HOST_NOT_FOUND + DNS_BASE,
290                                 "Host not found"},
291 #  endif /*HOST_NOT_FOUND*/
292 #  ifdef TRY_AGAIN
293         {TRY_AGAIN + DNS_BASE,
294                                 "DNS server failure"},
295 #  endif /*TRY_AGAIN*/
296 #  ifdef NO_RECOVERY
297         {NO_RECOVERY + DNS_BASE,
298                                 "Unrecoverable DNS error"},
299 #  endif /*NO_RECOVERY*/
300 #  ifdef NO_ADDRESS
301         {NO_ADDRESS + DNS_BASE,
302                                 "No address record found in DNS"},
303 #  endif /*NO_ADDRESS*/
304 #  ifdef NO_DATA
305         {NO_DATA + DNS_BASE,
306                                 "No DNS data of requested type"},
307 #  endif /*NO_DATA*/
308 
309         /* Last dummy entry - must be present */
310         {0, 0}
311     };
312 #if defined(NCBI_OS_LINUX)  ||  defined(NCBI_OS_CYGWIN)
313     /* To work correctly, descending order of offsets is required here */
314     static const struct {
315         int           erroff;
316         const char* (*errfun)(int errnum);
317     } errsup[] = {
318 #  ifdef __GLIBC__
319         { DNS_BASE, hstrerror    },
320 #  endif /*__GLIBC__*/
321 #  if defined(HAVE_GETADDRINFO)  ||  defined(HAVE_GETNAMEINFO)
322         { EAI_BASE, gai_strerror },
323 #  endif /*HAVE_GETADDRINFO || HAVE_GETNAMEINFO*/
324         /* Last dummy entry - must present */
325         { 0,        0            }
326     };
327 #endif /*NCBI_OS_LINUX || NCBI_OS_CYGWIN*/
328     size_t i;
329 
330     if (!error)
331         return 0;
332 
333 #if defined(NCBI_OS_LINUX)  ||  defined(NCBI_OS_CYGWIN)
334     for (i = 0;  i < sizeof(errsup) / sizeof(errsup[0]) - 1/*dummy*/;  ++i) {
335         if (errsup[i].erroff - 10000 < error
336             &&  error < errsup[i].erroff + 10000) {
337             const char* errstr = errsup[i].errfun(error - errsup[i].erroff);
338             if (errstr  &&  *errstr  &&  strncasecmp(errstr, "Unknown ", 8)!=0)
339                 return ERR_STRDUP(errstr);
340         }
341     }
342 #endif /*NCBI_OS_LINUX || NCBI_OS_CYGWIN*/
343 
344     for (i = 0;  i < sizeof(errmap) / sizeof(errmap[0]) - 1/*dummy*/;  ++i) {
345         if (errmap[i].errnum == error)
346             return ERR_STRDUP(errmap[i].errstr);
347     }
348 
349 #  if defined(NCBI_OS_MSWIN)  &&  defined(_UNICODE)
350     return UTIL_TcharToUtf8(_wcserror(error));
351 #  else
352     return ERR_STRDUP(strerror(error));
353 #  endif /*NCBI_OS_MSWIN && _UNICODE*/
354 }
355 
356 
357 #endif /*NCBI_INCLUDE_STRERROR_C*/
358