* sysdeps/i386/tls.h (THREAD_SET_PRIVATE_FUTEX,
[glibc.git] / inet / getnameinfo.c
blob50240383f3f53bbb81b0dacf2687325af5a08360
1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
10 way or form.
11 1. All terms of the all other applicable copyrights and licenses must be
12 followed.
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 4. [The copyright holder has authorized the removal of this clause.]
19 5. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 If these license terms cause you a real problem, contact the author. */
36 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
38 #include <alloca.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <arpa/inet.h>
47 #include <net/if.h>
48 #include <netinet/in.h>
49 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <sys/types.h>
52 #include <sys/un.h>
53 #include <sys/utsname.h>
54 #include <bits/libc-lock.h>
56 #ifdef HAVE_LIBIDN
57 # include <libidn/idna.h>
58 extern int __idna_to_unicode_lzlz (const char *input, char **output,
59 int flags);
60 #endif
62 #ifndef min
63 # define min(x,y) (((x) > (y)) ? (y) : (x))
64 #endif /* min */
66 libc_freeres_ptr (static char *domain);
69 static char *
70 internal_function
71 nrl_domainname (void)
73 static int not_first;
75 if (! not_first)
77 __libc_lock_define_initialized (static, lock);
78 __libc_lock_lock (lock);
80 if (! not_first)
82 char *c;
83 struct hostent *h, th;
84 size_t tmpbuflen = 1024;
85 char *tmpbuf = alloca (tmpbuflen);
86 int herror;
88 not_first = 1;
90 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
91 &herror))
93 if (herror == NETDB_INTERNAL && errno == ERANGE)
94 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
95 else
96 break;
99 if (h && (c = strchr (h->h_name, '.')))
100 domain = __strdup (++c);
101 else
103 /* The name contains no domain information. Use the name
104 now to get more information. */
105 while (__gethostname (tmpbuf, tmpbuflen))
106 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
108 if ((c = strchr (tmpbuf, '.')))
109 domain = __strdup (++c);
110 else
112 /* We need to preserve the hostname. */
113 const char *hstname = strdupa (tmpbuf);
115 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
116 &h, &herror))
118 if (herror == NETDB_INTERNAL && errno == ERANGE)
119 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
120 2 * tmpbuflen);
121 else
122 break;
125 if (h && (c = strchr(h->h_name, '.')))
126 domain = __strdup (++c);
127 else
129 struct in_addr in_addr;
131 in_addr.s_addr = htonl (INADDR_LOOPBACK);
133 while (__gethostbyaddr_r ((const char *) &in_addr,
134 sizeof (struct in_addr),
135 AF_INET, &th, tmpbuf,
136 tmpbuflen, &h, &herror))
138 if (herror == NETDB_INTERNAL && errno == ERANGE)
139 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
140 2 * tmpbuflen);
141 else
142 break;
145 if (h && (c = strchr (h->h_name, '.')))
146 domain = __strdup (++c);
152 __libc_lock_unlock (lock);
155 return domain;
160 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
161 socklen_t hostlen, char *serv, socklen_t servlen,
162 unsigned int flags)
164 int serrno = errno;
165 int tmpbuflen = 1024;
166 int herrno;
167 char *tmpbuf = alloca (tmpbuflen);
168 struct hostent th;
169 int ok = 0;
171 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
172 #ifdef HAVE_LIBIDN
173 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
174 #endif
176 return EAI_BADFLAGS;
178 if (sa == NULL || addrlen < sizeof (sa_family_t))
179 return EAI_FAMILY;
181 switch (sa->sa_family)
183 case AF_LOCAL:
184 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
185 return EAI_FAMILY;
186 break;
187 case AF_INET:
188 if (addrlen < sizeof (struct sockaddr_in))
189 return EAI_FAMILY;
190 break;
191 case AF_INET6:
192 if (addrlen < sizeof (struct sockaddr_in6))
193 return EAI_FAMILY;
194 break;
195 default:
196 return EAI_FAMILY;
199 if (host != NULL && hostlen > 0)
200 switch (sa->sa_family)
202 case AF_INET:
203 case AF_INET6:
204 if (!(flags & NI_NUMERICHOST))
206 struct hostent *h = NULL;
207 if (sa->sa_family == AF_INET6)
209 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
210 sizeof(struct in6_addr),
211 AF_INET6, &th, tmpbuf, tmpbuflen,
212 &h, &herrno))
213 if (herrno == NETDB_INTERNAL && errno == ERANGE)
214 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
215 else
216 break;
218 else
220 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
221 sizeof(struct in_addr), AF_INET,
222 &th, tmpbuf, tmpbuflen,
223 &h, &herrno))
224 if (herrno == NETDB_INTERNAL && errno == ERANGE)
225 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
226 else
227 break;
230 if (h == NULL)
232 if (herrno == NETDB_INTERNAL)
234 __set_h_errno (herrno);
235 return EAI_SYSTEM;
237 if (herrno == TRY_AGAIN)
239 __set_h_errno (herrno);
240 return EAI_AGAIN;
244 if (h)
246 char *c;
247 if ((flags & NI_NOFQDN)
248 && (c = nrl_domainname ())
249 && (c = strstr (h->h_name, c))
250 && (c != h->h_name) && (*(--c) == '.'))
251 /* Terminate the string after the prefix. */
252 *c = '\0';
254 #ifdef HAVE_LIBIDN
255 /* If requested, convert from the IDN format. */
256 if (flags & NI_IDN)
258 int idn_flags = 0;
259 if (flags & NI_IDN_ALLOW_UNASSIGNED)
260 idn_flags |= IDNA_ALLOW_UNASSIGNED;
261 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
262 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
264 char *out;
265 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
266 idn_flags);
267 if (rc != IDNA_SUCCESS)
269 if (rc == IDNA_MALLOC_ERROR)
270 return EAI_MEMORY;
271 if (rc == IDNA_DLOPEN_ERROR)
272 return EAI_SYSTEM;
273 return EAI_IDN_ENCODE;
276 if (out != h->h_name)
278 h->h_name = strdupa (out);
279 free (out);
282 #endif
284 size_t len = strlen (h->h_name) + 1;
285 if (len > hostlen)
286 return EAI_OVERFLOW;
288 memcpy (host, h->h_name, len);
290 ok = 1;
294 if (!ok)
296 if (flags & NI_NAMEREQD)
298 __set_errno (serrno);
299 return EAI_NONAME;
301 else
303 const char *c;
304 if (sa->sa_family == AF_INET6)
306 const struct sockaddr_in6 *sin6p;
307 uint32_t scopeid;
309 sin6p = (const struct sockaddr_in6 *) sa;
311 c = inet_ntop (AF_INET6,
312 (const void *) &sin6p->sin6_addr, host, hostlen);
313 scopeid = sin6p->sin6_scope_id;
314 if (scopeid != 0)
316 /* Buffer is >= IFNAMSIZ+1. */
317 char scopebuf[IFNAMSIZ + 1];
318 char *scopeptr;
319 int ni_numericscope = 0;
320 size_t real_hostlen = __strnlen (host, hostlen);
321 size_t scopelen = 0;
323 scopebuf[0] = SCOPE_DELIMITER;
324 scopebuf[1] = '\0';
325 scopeptr = &scopebuf[1];
327 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
328 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
330 if (if_indextoname (scopeid, scopeptr) == NULL)
331 ++ni_numericscope;
332 else
333 scopelen = strlen (scopebuf);
335 else
336 ++ni_numericscope;
338 if (ni_numericscope)
339 scopelen = 1 + __snprintf (scopeptr,
340 (scopebuf
341 + sizeof scopebuf
342 - scopeptr),
343 "%u", scopeid);
345 if (real_hostlen + scopelen + 1 > hostlen)
346 /* XXX We should not fail here. Simply enlarge
347 the buffer or return with out of memory. */
348 return EAI_SYSTEM;
349 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
352 else
353 c = inet_ntop (AF_INET,
354 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
355 host, hostlen);
356 if (c == NULL)
357 return EAI_SYSTEM;
359 ok = 1;
361 break;
363 case AF_LOCAL:
364 if (!(flags & NI_NUMERICHOST))
366 struct utsname utsname;
368 if (!uname (&utsname))
370 strncpy (host, utsname.nodename, hostlen);
371 break;
375 if (flags & NI_NAMEREQD)
377 __set_errno (serrno);
378 return EAI_NONAME;
381 strncpy (host, "localhost", hostlen);
382 break;
384 default:
385 return EAI_FAMILY;
388 if (serv && (servlen > 0))
389 switch (sa->sa_family)
391 case AF_INET:
392 case AF_INET6:
393 if (!(flags & NI_NUMERICSERV))
395 struct servent *s, ts;
396 int e;
397 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
398 ((flags & NI_DGRAM)
399 ? "udp" : "tcp"),
400 &ts, tmpbuf, tmpbuflen, &s)))
402 if (e == ERANGE)
403 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
404 else
405 break;
407 if (s)
409 strncpy (serv, s->s_name, servlen);
410 break;
414 if (__snprintf (serv, servlen, "%d",
415 ntohs (((const struct sockaddr_in *) sa)->sin_port))
416 + 1 > servlen)
417 return EAI_OVERFLOW;
419 break;
421 case AF_LOCAL:
422 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
423 break;
426 if (host && (hostlen > 0))
427 host[hostlen-1] = 0;
428 if (serv && (servlen > 0))
429 serv[servlen-1] = 0;
430 errno = serrno;
431 return 0;
433 libc_hidden_def (getnameinfo)