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