Tidy up.
[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 #include <sys/types.h>
46 #include <sys/socket.h>
47
48 #include <netinet/in.h>
49 #include <sys/un.h>
50 #include <sys/utsname.h>
51 #include <netdb.h>
52 #include <errno.h>
53 #include <string.h>
54 #include <stdio.h>
55 #include <unistd.h>
56 #include <alloca.h>
57 #include <bits/libc-lock.h>
58 #include <arpa/inet.h>
59
60 #ifndef min
61 # define min(x,y) (((x) > (y)) ? (y) : (x))
62 #endif /* min */
63
64
65 static char *
66 nrl_domainname (void)
67 {
68   static char *domain = NULL;
69   static int first = 1;
70
71   if (first)
72     {
73       __libc_lock_define_initialized (static, lock);
74       __libc_lock_lock (lock);
75
76       if (first)
77         {
78           char *c;
79           struct hostent *h, th;
80           size_t tmpbuflen = 1024;
81           char *tmpbuf = alloca (tmpbuflen);
82           int herror;
83
84           first = 0;
85
86           while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
87                                     &herror))
88             {
89               if (herror == NETDB_INTERNAL && errno == ERANGE)
90                 {
91                   tmpbuflen *= 2;
92                   tmpbuf = alloca (tmpbuflen);
93                 }
94               else
95                 break;
96             }
97
98           if (h && (c = strchr (h->h_name, '.')))
99             domain = __strdup (++c);
100           else
101             {
102               /* The name contains no domain information.  Use the name
103                  now to get more information.  */
104               while (gethostname (tmpbuf, tmpbuflen))
105                 {
106                   tmpbuflen *= 2;
107                   tmpbuf = alloca (tmpbuflen);
108                 }
109
110               if ((c = strchr (tmpbuf, '.')))
111                 domain = __strdup (++c);
112               else
113                 {
114                   /* We need to preserve the hostname.  */
115                   const char *hstname = strdupa (tmpbuf);
116
117                   while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
118                                             &h, &herror))
119                     {
120                       if (herror == NETDB_INTERNAL && errno == ERANGE)
121                         {
122                           tmpbuflen *= 2;
123                           tmpbuf = alloca (tmpbuflen);
124                         }
125                       else
126                         break;
127                     }
128
129                   if (h && (c = strchr(h->h_name, '.')))
130                     domain = __strdup (++c);
131                   else
132                     {
133                       struct in_addr in_addr;
134
135                       in_addr.s_addr = htonl (0x7f000001);
136
137                       while (__gethostbyaddr_r ((const char *) &in_addr,
138                                                 sizeof (struct in_addr),
139                                                 AF_INET, &th, tmpbuf,
140                                                 tmpbuflen, &h, &herror))
141                         {
142                           if (herror == NETDB_INTERNAL && errno == ERANGE)
143                             {
144                               tmpbuflen *= 2;
145                               tmpbuf = alloca (tmpbuflen);
146                             }
147                           else
148                             break;
149                         }
150
151                       if (h && (c = strchr (h->h_name, '.')))
152                         domain = __strdup (++c);
153                     }
154                 }
155             }
156         }
157
158       __libc_lock_unlock (lock);
159     }
160
161   return domain;
162 };
163
164
165 int
166 getnameinfo (const struct sockaddr *sa, size_t addrlen, char *host,
167              size_t hostlen, char *serv, size_t servlen, int flags)
168 {
169   int serrno = errno;
170   int tmpbuflen = 1024;
171   int herrno;
172   char *tmpbuf = alloca (tmpbuflen);
173   struct hostent th;
174
175   if (sa == NULL)
176     return -1;
177
178   if (host != NULL && hostlen > 0)
179     switch(sa->sa_family)
180       {
181       case AF_INET:
182       case AF_INET6:
183         if (!(flags & NI_NUMERICHOST))
184           {
185             struct hostent *h = NULL;
186             if (h == NULL)
187               {
188                 if (sa->sa_family == AF_INET6)
189                   {
190                     while (__gethostbyaddr_r ((void *) &(((struct sockaddr_in6 *) sa)->sin6_addr),
191                                               sizeof(struct in6_addr),
192                                               AF_INET6, &th, tmpbuf, tmpbuflen,
193                                               &h, &herrno))
194                       {
195                         if (herrno == NETDB_INTERNAL)
196                           {
197                             if (errno == ERANGE)
198                               {
199                                 tmpbuflen *= 2;
200                                 tmpbuf = alloca (tmpbuflen);
201                               }
202                             else
203                               {
204                                 __set_h_errno (herrno);
205                                 __set_errno (serrno);
206                                 return -1;
207                               }
208                           }
209                         else
210                           {
211                             break;
212                           }
213                       }
214                   }
215                 else
216                   {
217                     while (__gethostbyaddr_r ((void *) &(((struct sockaddr_in *)sa)->sin_addr),
218                                               sizeof(struct in_addr), AF_INET,
219                                               &th, tmpbuf, tmpbuflen,
220                                               &h, &herrno))
221                       {
222                         if (errno == ERANGE)
223                           {
224                             tmpbuflen *= 2;
225                             tmpbuf = alloca (tmpbuflen);
226                           }
227                         else
228                           {
229                             break;
230                           }
231                       }
232                   }
233               }
234
235             if (h)
236               {
237                 if (flags & NI_NOFQDN)
238                   {
239                     char *c;
240                     if ((c = nrl_domainname ()) && (c = strstr(h->h_name, c))
241                         && (c != h->h_name) && (*(--c) == '.'))
242                       {
243                         strncpy (host, h->h_name,
244                                  min(hostlen, (size_t) (c - h->h_name)));
245                         break;
246                       }
247                   }
248                 strncpy (host, h->h_name, hostlen);
249                 break;
250               }
251           }
252
253         if (flags & NI_NAMEREQD)
254           {
255             __set_errno (serrno);
256             return -1;
257           }
258         else
259           {
260             const char *c;
261 #if INET6
262             if (sa->sa_family == AF_INET6)
263               c = inet_ntop (AF_INET6,
264                              (void *) &(((struct sockaddr_in6 *) sa)->sin6_addr),
265                              host, hostlen);
266             else
267 #endif /* INET6 */
268               c = inet_ntop (AF_INET,
269                              (void *) &(((struct sockaddr_in *) sa)->sin_addr),
270                              host, hostlen);
271
272             if (c == NULL)
273               {
274                 __set_errno (serrno);
275                 return -1;
276               }
277           }
278         break;
279
280       case AF_LOCAL:
281         if (!(flags & NI_NUMERICHOST))
282           {
283             struct utsname utsname;
284
285             if (!uname (&utsname))
286               {
287                 strncpy (host, utsname.nodename, hostlen);
288                 break;
289               };
290           };
291
292         if (flags & NI_NAMEREQD)
293            {
294             __set_errno (serrno);
295             return -1;
296           }
297
298         strncpy (host, "localhost", hostlen);
299         break;
300
301       default:
302         return -1;
303     }
304
305   if (serv && (servlen > 0))
306     switch(sa->sa_family)
307       {
308       case AF_INET:
309       case AF_INET6:
310         if (!(flags & NI_NUMERICSERV))
311           {
312             struct servent *s, ts;
313             while (__getservbyport_r (((struct sockaddr_in *) sa)->sin_port,
314                                       ((flags & NI_DGRAM) ? "udp" : "tcp"),
315                                       &ts, tmpbuf, tmpbuflen, &s))
316               {
317                 if (herrno == NETDB_INTERNAL)
318                   {
319                     if (errno == ERANGE)
320                       {
321                         tmpbuflen *= 2;
322                         tmpbuf = __alloca (tmpbuflen);
323                       }
324                     else
325                       {
326                         __set_errno (serrno);
327                         return -1;
328                       }
329                   }
330                 else
331                   {
332                     break;
333                   }
334               }
335             if (s)
336               {
337                 strncpy (serv, s->s_name, servlen);
338                 break;
339               }
340           }
341         snprintf (serv, servlen, "%d",
342                   ntohs (((struct sockaddr_in *) sa)->sin_port));
343         break;
344
345       case AF_LOCAL:
346         strncpy (serv, ((struct sockaddr_un *) sa)->sun_path, servlen);
347         break;
348     }
349
350   if (host && (hostlen > 0))
351     host[hostlen-1] = 0;
352   if (serv && (servlen > 0))
353     serv[servlen-1] = 0;
354   errno = serrno;
355   return 0;
356 }