(nrl_domainname): Change return type to const char *.
[kopensolaris-gnu/glibc.git] / inet / getnameinfo.c
1 /* The Inner Net License, Version 2.00
2
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:
6
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. All advertising materials mentioning features or use of this software
19    must display the following acknowledgement with the name(s) of the
20    authors as specified in the copyright notice(s) substituted where
21    indicated:
22
23         This product includes software developed by <name(s)>, The Inner
24         Net, and other contributors.
25
26 5. Neither the name(s) of the author(s) nor the names of its contributors
27    may be used to endorse or promote products derived from this software
28    without specific prior written permission.
29
30 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
37 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
41   If these license terms cause you a real problem, contact the author.  */
42
43 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved.  */
44
45 #define INET6 1
46 #define LOCAL 1
47 #define HOSTTABLE 0
48 #define RESOLVER 1
49
50 #include <sys/types.h>
51 #include <sys/socket.h>
52
53 #include <netinet/in.h>
54 #if LOCAL
55 #include <sys/un.h>
56 #include <sys/utsname.h>
57 #endif /* LOCAL */
58 #include <netdb.h>
59 #include <errno.h>
60 #include <string.h>
61 #include <stdio.h>
62 #include <unistd.h>
63 #include <alloca.h>
64 #include <bits/libc-lock.h>
65 #include <arpa/inet.h>
66
67 #ifndef AF_LOCAL
68 # define AF_LOCAL AF_UNIX
69 #endif /* AF_LOCAL */
70
71 #if HOSTTABLE
72 struct hostent *_addr2hostname_hosts (const char *, int, int);
73 #endif /* HOSTTABLE */
74
75 #ifndef min
76 # define min(x,y) (((x) > (y)) ? (y) : (x))
77 #endif /* min */
78
79
80 static const char *
81 nrl_domainname (void)
82 {
83   static const char *domain = NULL;
84   static int first = 1;
85
86   if (first)
87     {
88       __libc_lock_define_initialized (static, lock);
89       __libc_lock_lock (lock);
90
91       if (first)
92         {
93           char *c;
94           struct hostent *h, th;
95           int tmpbuflen = 1024;
96           char *tmpbuf = alloca (tmpbuflen);
97           int herror;
98
99           first = 0;
100
101           while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
102                                     &herror))
103             {
104               if (herror == NETDB_INTERNAL && errno == ERANGE)
105                 {
106                   tmpbuflen *= 2;
107                   tmpbuf = alloca (tmpbuflen);
108                 }
109               else
110                 break;
111             }
112
113           if (h && (c = strchr (h->h_name, '.')))
114             domain = __strdup (++c);
115           else
116             {
117               /* The name contains no domain information.  Use the name
118                  now to get more information.  */
119               while (gethostname (tmpbuf, tmpbuflen))
120                 {
121                   tmpbuflen *= 2;
122                   tmpbuf = alloca (tmpbuflen);
123                 }
124
125               if ((c = strchr (tmpbuf, '.')))
126                 domain = __strdup (++c);
127               else
128                 {
129                   /* We need to preserve the hostname.  */
130                   const char *hstname = strdupa (tmpbuf);
131
132                   while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
133                                             &h, &herror))
134                     {
135                       if (herror == NETDB_INTERNAL && errno == ERANGE)
136                         {
137                           tmpbuflen *= 2;
138                           tmpbuf = alloca (tmpbuflen);
139                         }
140                       else
141                         break;
142                     }
143
144                   if (h && (c = strchr(h->h_name, '.')))
145                     domain = __strdup (++c);
146                   else
147                     {
148                       struct in_addr in_addr;
149
150                       in_addr.s_addr = htonl (0x7f000001);
151
152                       while (__gethostbyaddr_r ((const char *) &in_addr,
153                                                 sizeof (struct in_addr),
154                                                 AF_INET, &th, tmpbuf,
155                                                 tmpbuflen, &h, &herror))
156                         {
157                           if (herror == NETDB_INTERNAL && errno == ERANGE)
158                             {
159                               tmpbuflen *= 2;
160                               tmpbuf = alloca (tmpbuflen);
161                             }
162                           else
163                             break;
164                         }
165
166                       if (h && (c = strchr (h->h_name, '.')))
167                         domain = __strdup (++c);
168                     }
169                 }
170             }
171         }
172
173       __libc_lock_unlock (lock);
174     }
175
176   return domain;
177 };
178
179
180 int
181 getnameinfo (const struct sockaddr *sa, size_t addrlen, char *host,
182              size_t hostlen, char *serv, size_t servlen, int flags)
183 {
184   int serrno = errno;
185   int tmpbuflen = 1024;
186   int herrno;
187   char *tmpbuf = alloca (tmpbuflen);
188   struct hostent th;
189
190   if (sa == NULL)
191     return -1;
192
193   if (host != NULL && hostlen > 0)
194     switch(sa->sa_family)
195       {
196       case AF_INET:
197 #if INET6
198       case AF_INET6:
199 #endif /* INET6 */
200         if (!(flags & NI_NUMERICHOST))
201           {
202             struct hostent *h = NULL;
203 #if HOSTTABLE
204 # if INET6
205             if (sa->sa_family == AF_INET6)
206               h = _addr2hostname_hosts ((void *) &(((struct sockaddr_in6 *) sa)->sin6_addr),
207                                         sizeof(struct in6_addr), AF_INET6);
208             else
209 # endif /* INET6 */
210               h = _addr2hostname_hosts ((void *)& (((struct sockaddr_in *) sa)->sin_addr),
211                                         sizeof(struct in_addr), AF_INET);
212 #endif /* HOSTTABLE */
213
214 #if RESOLVER
215             if (h == NULL)
216               {
217 #if INET6
218                 if (sa->sa_family == AF_INET6)
219                   {
220                     while (__gethostbyaddr_r ((void *) &(((struct sockaddr_in6 *) sa)->sin6_addr),
221                                               sizeof(struct in6_addr),
222                                               AF_INET6, &th, tmpbuf, tmpbuflen,
223                                               &h, &herrno))
224                       {
225                         if (herrno == NETDB_INTERNAL)
226                           {
227                             if (errno == ERANGE)
228                               {
229                                 tmpbuflen *= 2;
230                                 tmpbuf = alloca (tmpbuflen);
231                               }
232                             else
233                               {
234                                 __set_h_errno (herrno);
235                                 goto fail;
236                               }
237                           }
238                         else
239                           {
240                             break;
241                           }
242                       }
243                   }
244                 else
245                   {
246 #endif /* INET6 */
247                     while (__gethostbyaddr_r ((void *) &(((struct sockaddr_in *)sa)->sin_addr),
248                                               sizeof(struct in_addr), AF_INET,
249                                               &th, tmpbuf, tmpbuflen,
250                                               &h, &herrno))
251                       {
252                         if (errno == ERANGE)
253                           {
254                             tmpbuflen *= 2;
255                             tmpbuf = alloca (tmpbuflen);
256                           }
257                         else
258                           {
259                             break;
260                           }
261                       }
262                   }
263               }
264 #endif /* RESOLVER */
265
266             if (h)
267               {
268                 if (flags & NI_NOFQDN)
269                   {
270                     const char *c;
271                     if ((c = nrl_domainname ()) && (c = strstr(h->h_name, c))
272                         && (c != h->h_name) && (*(--c) == '.'))
273                       {
274                         strncpy (host, h->h_name,
275                                  min(hostlen, (size_t) (c - h->h_name)));
276                         break;
277                       }
278                   }
279                 strncpy (host, h->h_name, hostlen);
280                 break;
281               }
282           }
283
284         if (flags & NI_NAMEREQD)
285           goto fail;
286         else
287           {
288             const char *c;
289 #if INET6
290             if (sa->sa_family == AF_INET6)
291               c = inet_ntop (AF_INET6,
292                              (void *) &(((struct sockaddr_in6 *) sa)->sin6_addr),
293                              host, hostlen);
294             else
295 #endif /* INET6 */
296               c = inet_ntop (AF_INET,
297                              (void *) &(((struct sockaddr_in *) sa)->sin_addr),
298                              host, hostlen);
299
300             if (!c)
301               goto fail;
302           }
303         break;
304
305 #if LOCAL
306       case AF_LOCAL:
307         if (!(flags & NI_NUMERICHOST))
308           {
309             struct utsname utsname;
310
311             if (!uname (&utsname))
312               {
313                 strncpy (host, utsname.nodename, hostlen);
314                 break;
315               };
316           };
317
318         if (flags & NI_NAMEREQD)
319           goto fail;
320
321         strncpy (host, "localhost", hostlen);
322         break;
323 #endif /* LOCAL */
324
325       default:
326         return -1;
327     }
328
329   if (serv && (servlen > 0))
330     switch(sa->sa_family)
331       {
332       case AF_INET:
333 #if INET6
334       case AF_INET6:
335 #endif /* INET6 */
336         if (!(flags & NI_NUMERICSERV))
337           {
338             struct servent *s, ts;
339             while (__getservbyport_r (((struct sockaddr_in *) sa)->sin_port,
340                                       ((flags & NI_DGRAM) ? "udp" : "tcp"),
341                                       &ts, tmpbuf, tmpbuflen, &s))
342               {
343                 if (herrno == NETDB_INTERNAL)
344                   {
345                     if (errno == ERANGE)
346                       {
347                         tmpbuflen *= 2;
348                         tmpbuf = __alloca(tmpbuflen);
349                       }
350                     else
351                       goto fail;
352                   }
353                 else
354                   {
355                     break;
356                   }
357               }
358             if (s)
359               {
360                 strncpy(serv, s->s_name, servlen);
361                 break;
362               }
363           }
364         snprintf (serv, servlen, "%d",
365                   ntohs (((struct sockaddr_in *) sa)->sin_port));
366         break;
367
368 #if LOCAL
369       case AF_LOCAL:
370         strncpy (serv, ((struct sockaddr_un *) sa)->sun_path, servlen);
371         break;
372 #endif /* LOCAL */
373     }
374
375   if (host && (hostlen > 0))
376     host[hostlen-1] = 0;
377   if (serv && (servlen > 0))
378     serv[servlen-1] = 0;
379   errno = serrno;
380   return 0;
381
382 fail:
383   errno = serrno;
384   return -1;
385 };