Delete references to MAXHOSTNAMELEN.
[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 static const char *domain;
80
81 static char *nrl_domainname(void)
82 {
83   static int first = 1;
84
85   if (first) {
86
87     __libc_lock_define_initialized (static, lock);
88     __libc_lock_lock (lock);
89
90     if (first) {
91       char *c;
92       struct hostent *h, th;
93       int tmpbuflen = 1024;
94       char *tmpbuf = __alloca(tmpbuflen);
95       int herror;
96
97       first = 0;
98
99       while (__gethostbyname_r("localhost", &th, tmpbuf, tmpbuflen, &h,
100                                &herror)) {
101         if (herror == NETDB_INTERNAL) {
102           if (errno == ERANGE) {
103             tmpbuflen *= 2;
104             tmpbuf = __alloca(tmpbuflen);
105           }
106         } else {
107           break;
108         }
109       }
110
111       if (h && (c = strchr(h->h_name, '.'))) {
112         domain = __strdup (++c);
113         goto ret;
114       }
115
116       while (gethostname (tmpbuf, tmpbuflen)) {
117         tmpbuflen *= 2;
118         tmpbuf = __alloca (tmpbuflen);
119       }
120       if (c = strchr(tmpbuf, '.')) {
121         domain = __strdup(++c);
122         goto ret;
123       }
124
125       while (__gethostbyname_r(tmpbuf, &th, tmpbuf, tmpbuflen, &h,
126                                &herror)) {
127         if (herror == NETDB_INTERNAL) {
128           if (errno == ERANGE) {
129             tmpbuflen *= 2;
130             tmpbuf = __alloca(tmpbuflen);
131           }
132         } else {
133           break;
134         }
135       }
136
137       if (h && (c = strchr(h->h_name, '.'))) {
138         domain = __strdup(++c);
139         goto ret;
140       }
141
142       {
143         struct in_addr in_addr;
144
145         in_addr.s_addr = htonl(0x7f000001);
146
147         while (__gethostbyaddr_r((const char *)&in_addr,
148                                  sizeof(struct in_addr), AF_INET, &th, tmpbuf,
149                                  tmpbuflen, &h, &herror)) {
150           if (herror == NETDB_INTERNAL) {
151             if (errno == ERANGE) {
152               tmpbuflen *= 2;
153               tmpbuf = __alloca(tmpbuflen);
154             }
155           } else {
156             break;
157           }
158         }
159
160         if (h && (c = strchr(h->h_name, '.'))) {
161           domain = __strdup(++c);
162           goto ret;
163         }
164       }
165
166     }
167
168   ret:
169     __libc_lock_unlock (lock);
170   }
171
172   return domain;
173 };
174
175 int getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
176 {
177   int serrno = errno;
178   int tmpbuflen = 1024;
179   int herrno;
180   char *tmpbuf = __alloca(tmpbuflen);
181   struct hostent th;
182
183   if (!sa)
184     return -1;
185
186   if (host && (hostlen > 0))
187     switch(sa->sa_family) {
188       case AF_INET:
189 #if INET6
190       case AF_INET6:
191 #endif /* INET6 */
192         if (!(flags & NI_NUMERICHOST)) {
193           struct hostent *h = NULL;
194 #if HOSTTABLE
195 #if INET6
196           if (sa->sa_family == AF_INET6)
197             h = _addr2hostname_hosts((void *)&(((struct sockaddr_in6 *)sa)->sin6_addr), sizeof(struct in6_addr), AF_INET6);
198           else
199 #endif /* INET6 */
200             h = _addr2hostname_hosts((void *)&(((struct sockaddr_in *)sa)->sin_addr), sizeof(struct in_addr), AF_INET);
201 #endif /* HOSTTABLE */
202
203 #if RESOLVER
204           if (!h) {
205 #if INET6
206             if (sa->sa_family == AF_INET6) {
207               while (__gethostbyaddr_r((void *)&(((struct sockaddr_in6 *)sa)->sin6_addr), sizeof(struct in6_addr), AF_INET6, &th, tmpbuf, tmpbuflen, &h, &herrno)) {
208                 if (herrno == NETDB_INTERNAL) {
209                   if (errno == ERANGE) {
210                     tmpbuflen *= 2;
211                     tmpbuf = __alloca(tmpbuflen);
212                   } else {
213                     __set_h_errno(herrno);
214                     goto fail;
215                   }
216                 } else {
217                   break;
218                 }
219               }
220             } else {
221 #endif /* INET6 */
222               while (__gethostbyaddr_r((void *)&(((struct sockaddr_in *)sa)->sin_addr), sizeof(struct in_addr), AF_INET, &th, tmpbuf, tmpbuflen, &h, &herrno)) {
223                 if (errno == ERANGE) {
224                   tmpbuflen *= 2;
225                   tmpbuf = __alloca(tmpbuflen);
226                 } else {
227                   break;
228                 }
229               }
230             }
231           }
232 #endif /* RESOLVER */
233
234           if (h) {
235             if (flags & NI_NOFQDN) {
236               char *c;
237               if ((c = nrl_domainname()) && (c = strstr(h->h_name, c)) && (c != h->h_name) && (*(--c) == '.')) {
238                 strncpy(host, h->h_name, min(hostlen, (size_t) (c - h->h_name)));
239                 break;
240               };
241             };
242             strncpy(host, h->h_name, hostlen);
243             break;
244           };
245         };
246
247         if (flags & NI_NAMEREQD)
248           goto fail;
249
250         {
251           const char *c;
252 #if INET6
253           if (sa->sa_family == AF_INET6)
254             c = inet_ntop(AF_INET6, (void *)&(((struct sockaddr_in6 *)sa)->sin6_addr), host, hostlen);
255           else
256 #endif /* INET6 */
257             c = inet_ntop(AF_INET, (void *)&(((struct sockaddr_in *)sa)->sin_addr), host, hostlen);
258
259           if (!c)
260             goto fail;
261         };
262         break;
263 #if LOCAL
264       case AF_LOCAL:
265         if (!(flags & NI_NUMERICHOST)) {
266           struct utsname utsname;
267
268           if (!uname(&utsname)) {
269             strncpy(host, utsname.nodename, hostlen);
270             break;
271           };
272         };
273
274         if (flags & NI_NAMEREQD)
275           goto fail;
276
277         strncpy(host, "localhost", hostlen);
278         break;
279 #endif /* LOCAL */
280       default:
281         return -1;
282     };
283
284   if (serv && (servlen > 0))
285     switch(sa->sa_family) {
286       case AF_INET:
287 #if INET6
288       case AF_INET6:
289 #endif /* INET6 */
290         if (!(flags & NI_NUMERICSERV)) {
291           struct servent *s, ts;
292           while (__getservbyport_r(((struct sockaddr_in *)sa)->sin_port, ((flags & NI_DGRAM) ? "udp" : "tcp"), &ts, tmpbuf, tmpbuflen, &s)) {
293             if (herrno == NETDB_INTERNAL) {
294               if (errno == ERANGE) {
295                 tmpbuflen *= 2;
296                 tmpbuf = __alloca(tmpbuflen);
297               } else {
298                 goto fail;
299               }
300             } else {
301               break;
302             }
303           }
304           if (s) {
305             strncpy(serv, s->s_name, servlen);
306             break;
307           };
308         };
309         snprintf(serv, servlen, "%d", ntohs(((struct sockaddr_in *)sa)->sin_port));
310         break;
311 #if LOCAL
312       case AF_LOCAL:
313         strncpy(serv, ((struct sockaddr_un *)sa)->sun_path, servlen);
314         break;
315 #endif /* LOCAL */
316     };
317   if (host && (hostlen > 0))
318     host[hostlen-1] = 0;
319   if (serv && (servlen > 0))
320     serv[servlen-1] = 0;
321   errno = serrno;
322   return 0;
323
324 fail:
325   errno = serrno;
326   return -1;
327 };