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