1 /*	$NetBSD: gai_strerror.c,v 1.1.1.1 2009/04/12 15:33:35 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 2001 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <port_before.h>
21 #include <netdb.h>
22 #include <port_after.h>
23 
24 #ifdef DO_PTHREADS
25 #include <pthread.h>
26 #include <stdlib.h>
27 #endif
28 
29 static const char *gai_errlist[] = {
30 	"no error",
31 	"address family not supported for name",/*%< EAI_ADDRFAMILY */
32 	"temporary failure",			/*%< EAI_AGAIN */
33 	"invalid flags",			/*%< EAI_BADFLAGS */
34 	"permanent failure",			/*%< EAI_FAIL */
35 	"address family not supported",		/*%< EAI_FAMILY */
36 	"memory failure",			/*%< EAI_MEMORY */
37 	"no address",				/*%< EAI_NODATA */
38 	"unknown name or service",		/*%< EAI_NONAME */
39 	"service not supported for socktype",	/*%< EAI_SERVICE */
40 	"socktype not supported",		/*%< EAI_SOCKTYPE */
41 	"system failure",			/*%< EAI_SYSTEM */
42 	"bad hints",				/*%< EAI_BADHINTS */
43 	"bad protocol",				/*%< EAI_PROTOCOL */
44 	"unknown error"				/*%< Must be last. */
45 };
46 
47 static const int gai_nerr = (sizeof(gai_errlist)/sizeof(*gai_errlist));
48 
49 #define EAI_BUFSIZE 128
50 
51 const char *
52 gai_strerror(int ecode) {
53 #ifndef DO_PTHREADS
54 	static char buf[EAI_BUFSIZE];
55 #else	/* DO_PTHREADS */
56 #ifndef LIBBIND_MUTEX_INITIALIZER
57 #define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
58 #endif
59 	static pthread_mutex_t lock = LIBBIND_MUTEX_INITIALIZER;
60 	static pthread_key_t key;
61 	static int once = 0;
62 	char *buf;
63 #endif
64 
65 	if (ecode >= 0 && ecode < (gai_nerr - 1))
66 		return (gai_errlist[ecode]);
67 
68 #ifdef DO_PTHREADS
69         if (!once) {
70                 if (pthread_mutex_lock(&lock) != 0)
71 			goto unknown;
72                 if (!once) {
73                         if (pthread_key_create(&key, free) != 0) {
74 				(void)pthread_mutex_unlock(&lock);
75 				goto unknown;
76 			}
77 			once = 1;
78 		}
79                 if (pthread_mutex_unlock(&lock) != 0)
80 			goto unknown;
81         }
82 
83 	buf = pthread_getspecific(key);
84         if (buf == NULL) {
85 		buf = malloc(EAI_BUFSIZE);
86                 if (buf == NULL)
87                         goto unknown;
88                 if (pthread_setspecific(key, buf) != 0) {
89 			free(buf);
90 			goto unknown;
91 		}
92         }
93 #endif
94 	/*
95 	 * XXX This really should be snprintf(buf, EAI_BUFSIZE, ...).
96 	 * It is safe until message catalogs are used.
97 	 */
98 	sprintf(buf, "%s: %d", gai_errlist[gai_nerr - 1], ecode);
99 	return (buf);
100 
101 #ifdef DO_PTHREADS
102  unknown:
103 	return ("unknown error");
104 #endif
105 }
106 
107 /*! \file */
108