Update.
[glibc.git] / inet / getnameinfo.c
blob063bec4c793f193c9f083a9d5c9c5b6be45c4885
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 <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <arpa/inet.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <sys/param.h>
48 #include <sys/socket.h>
49 #include <sys/types.h>
50 #include <sys/un.h>
51 #include <sys/utsname.h>
52 #include <bits/libc-lock.h>
54 #ifndef min
55 # define min(x,y) (((x) > (y)) ? (y) : (x))
56 #endif /* min */
59 static char *
60 internal_function
61 nrl_domainname (void)
63 static char *domain;
64 static int not_first;
66 if (! not_first)
68 __libc_lock_define_initialized (static, lock);
69 __libc_lock_lock (lock);
71 if (! not_first)
73 char *c;
74 struct hostent *h, th;
75 size_t tmpbuflen = 1024;
76 char *tmpbuf = alloca (tmpbuflen);
77 int herror;
79 not_first = 1;
81 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
82 &herror))
84 if (herror == NETDB_INTERNAL && errno == ERANGE)
86 tmpbuflen *= 2;
87 tmpbuf = alloca (tmpbuflen);
89 else
90 break;
93 if (h && (c = strchr (h->h_name, '.')))
94 domain = __strdup (++c);
95 else
97 /* The name contains no domain information. Use the name
98 now to get more information. */
99 while (__gethostname (tmpbuf, tmpbuflen))
101 tmpbuflen *= 2;
102 tmpbuf = alloca (tmpbuflen);
105 if ((c = strchr (tmpbuf, '.')))
106 domain = __strdup (++c);
107 else
109 /* We need to preserve the hostname. */
110 const char *hstname = strdupa (tmpbuf);
112 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
113 &h, &herror))
115 if (herror == NETDB_INTERNAL && errno == ERANGE)
117 tmpbuflen *= 2;
118 tmpbuf = alloca (tmpbuflen);
120 else
121 break;
124 if (h && (c = strchr(h->h_name, '.')))
125 domain = __strdup (++c);
126 else
128 struct in_addr in_addr;
130 in_addr.s_addr = htonl (INADDR_LOOPBACK);
132 while (__gethostbyaddr_r ((const char *) &in_addr,
133 sizeof (struct in_addr),
134 AF_INET, &th, tmpbuf,
135 tmpbuflen, &h, &herror))
137 if (herror == NETDB_INTERNAL && errno == ERANGE)
139 tmpbuflen *= 2;
140 tmpbuf = alloca (tmpbuflen);
142 else
143 break;
146 if (h && (c = strchr (h->h_name, '.')))
147 domain = __strdup (++c);
153 __libc_lock_unlock (lock);
156 return domain;
161 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
162 socklen_t hostlen, char *serv, socklen_t servlen,
163 unsigned int flags)
165 int serrno = errno;
166 int tmpbuflen = 1024;
167 int herrno;
168 char *tmpbuf = alloca (tmpbuflen);
169 struct hostent th;
170 int ok = 0;
172 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
173 return EAI_BADFLAGS;
175 if (sa == NULL || addrlen < sizeof (sa_family_t))
176 return EAI_FAMILY;
178 switch (sa->sa_family)
180 case AF_LOCAL:
181 if (addrlen < (socklen_t) (((struct sockaddr_un *) NULL)->sun_path))
182 return EAI_FAMILY;
183 break;
184 case AF_INET:
185 if (addrlen < sizeof (struct sockaddr_in))
186 return EAI_FAMILY;
187 break;
188 case AF_INET6:
189 if (addrlen < sizeof (struct sockaddr_in6))
190 return EAI_FAMILY;
191 break;
192 default:
193 return EAI_FAMILY;
196 if (host != NULL && hostlen > 0)
197 switch (sa->sa_family)
199 case AF_INET:
200 case AF_INET6:
201 if (!(flags & NI_NUMERICHOST))
203 struct hostent *h = NULL;
204 if (h == NULL)
206 if (sa->sa_family == AF_INET6)
208 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
209 sizeof(struct in6_addr),
210 AF_INET6, &th, tmpbuf, tmpbuflen,
211 &h, &herrno))
213 if (herrno == NETDB_INTERNAL)
215 if (errno == ERANGE)
217 tmpbuflen *= 2;
218 tmpbuf = alloca (tmpbuflen);
220 else
222 __set_h_errno (herrno);
223 __set_errno (serrno);
224 return EAI_SYSTEM;
227 else
229 break;
233 else
235 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
236 sizeof(struct in_addr), AF_INET,
237 &th, tmpbuf, tmpbuflen,
238 &h, &herrno))
240 if (errno == ERANGE)
242 tmpbuflen *= 2;
243 tmpbuf = alloca (tmpbuflen);
245 else
247 break;
253 if (h)
255 char *c;
256 if ((flags & NI_NOFQDN)
257 && (c = nrl_domainname ())
258 && (c = strstr (h->h_name, c))
259 && (c != h->h_name) && (*(--c) == '.'))
261 strncpy (host, h->h_name,
262 min(hostlen, (size_t) (c - h->h_name)));
263 host[min(hostlen - 1, (size_t) (c - h->h_name))]
264 = '\0';
265 ok = 1;
267 else
269 strncpy (host, h->h_name, hostlen);
270 ok = 1;
275 if (!ok)
277 if (flags & NI_NAMEREQD)
279 __set_errno (serrno);
280 return EAI_NONAME;
282 else
284 const char *c;
285 if (sa->sa_family == AF_INET6)
287 const struct sockaddr_in6 *sin6p;
288 uint32_t scopeid;
290 sin6p = (const struct sockaddr_in6 *) sa;
292 c = inet_ntop (AF_INET6,
293 (const void *) &sin6p->sin6_addr, host, hostlen);
294 scopeid = sin6p->sin6_scope_id;
295 if (scopeid != 0)
297 /* Buffer is >= IFNAMSIZ+1. */
298 char scopebuf[IFNAMSIZ + 1];
299 char *scopeptr;
300 int ni_numericscope = 0;
301 size_t real_hostlen = __strnlen (host, hostlen);
302 size_t scopelen = 0;
304 scopebuf[0] = SCOPE_DELIMITER;
305 scopebuf[1] = '\0';
306 scopeptr = &scopebuf[1];
308 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
309 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
311 if (if_indextoname (scopeid, scopeptr) == NULL)
312 ++ni_numericscope;
313 else
314 scopelen = strlen (scopebuf);
316 else
317 ++ni_numericscope;
319 if (ni_numericscope)
320 scopelen = 1 + __snprintf (scopeptr,
321 (scopebuf
322 + sizeof scopebuf
323 - scopeptr),
324 "%u", scopeid);
326 if (real_hostlen + scopelen + 1 > hostlen)
327 /* XXX We should not fail here. Simply enlarge
328 the buffer or return with out of memory. */
329 return EAI_SYSTEM;
330 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
333 else
334 c = inet_ntop (AF_INET,
335 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
336 host, hostlen);
337 if (c == NULL)
339 __set_errno (serrno);
340 return EAI_SYSTEM;
343 ok = 1;
345 break;
347 case AF_LOCAL:
348 if (!(flags & NI_NUMERICHOST))
350 struct utsname utsname;
352 if (!uname (&utsname))
354 strncpy (host, utsname.nodename, hostlen);
355 break;
359 if (flags & NI_NAMEREQD)
361 __set_errno (serrno);
362 return EAI_NONAME;
365 strncpy (host, "localhost", hostlen);
366 break;
368 default:
369 return EAI_FAMILY;
372 if (serv && (servlen > 0))
373 switch (sa->sa_family)
375 case AF_INET:
376 case AF_INET6:
377 if (!(flags & NI_NUMERICSERV))
379 struct servent *s, ts;
380 while (__getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
381 ((flags & NI_DGRAM) ? "udp" : "tcp"),
382 &ts, tmpbuf, tmpbuflen, &s))
384 if (herrno == NETDB_INTERNAL)
386 if (errno == ERANGE)
388 tmpbuflen *= 2;
389 tmpbuf = __alloca (tmpbuflen);
391 else
393 __set_errno (serrno);
394 return EAI_SYSTEM;
397 else
399 break;
402 if (s)
404 strncpy (serv, s->s_name, servlen);
405 break;
408 __snprintf (serv, servlen, "%d",
409 ntohs (((const struct sockaddr_in *) sa)->sin_port));
410 break;
412 case AF_LOCAL:
413 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
414 break;
417 if (host && (hostlen > 0))
418 host[hostlen-1] = 0;
419 if (serv && (servlen > 0))
420 serv[servlen-1] = 0;
421 errno = serrno;
422 return 0;
424 libc_hidden_def (getnameinfo)