OSDN Git Service

ifdef out check which always fails
[uclinux-h8/uClibc.git] / libc / inet / ntop.c
1 /*
2  * Copyright (c) 1996-1999 by Internet Software Consortium.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  */
17
18 #define __FORCE_GLIBC
19 #include <features.h>
20 #include <sys/param.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <arpa/nameser.h>
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32
33
34 /*
35  * WARNING: Don't even consider trying to compile this on a system where
36  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
37  */
38
39
40 /* const char *
41  * inet_ntop4(src, dst, size)
42  *      format an IPv4 address
43  * return:
44  *      `dst' (as a const)
45  * notes:
46  *      (1) uses no statics
47  *      (2) takes a u_char* not an in_addr as input
48  * author:
49  *      Paul Vixie, 1996.
50  */
51 static const char *
52 inet_ntop4(const u_char *src, char *dst, size_t size)
53 {
54         char tmp[sizeof ("255.255.255.255") + 1] = "\0";
55         int octet;
56         int i;
57
58         i = 0;
59         for (octet = 0; octet <= 3; octet++) {
60
61 #if 0   /* since src is unsigned char, it will never be > 255 ... */
62                 if (src[octet] > 255) {
63                         __set_errno (ENOSPC);
64                         return (NULL);
65                 }
66 #endif
67                 tmp[i++] = '0' + src[octet] / 100;
68                 if (tmp[i - 1] == '0') {
69                         tmp[i - 1] = '0' + (src[octet] / 10 % 10);
70                         if (tmp[i - 1] == '0') i--;
71                 } else {
72                         tmp[i++] = '0' + (src[octet] / 10 % 10);
73                 }
74                 tmp[i++] = '0' + src[octet] % 10;
75                 tmp[i++] = '.';
76         }
77         tmp[i - 1] = '\0';
78
79         if (strlen (tmp) > size) {
80                 __set_errno (ENOSPC);
81                 return (NULL);
82         }
83
84         return strcpy(dst, tmp);
85 }
86
87
88 /* const char *
89  * inet_ntop6(src, dst, size)
90  *      convert IPv6 binary address into presentation (printable) format
91  * author:
92  *      Paul Vixie, 1996.
93  */
94
95 #ifdef __UCLIBC_HAS_IPV6__
96
97 static const char *
98 inet_ntop6(const u_char *src, char *dst, size_t size)
99 {
100         /*
101          * Note that int32_t and int16_t need only be "at least" large enough
102          * to contain a value of the specified size.  On some systems, like
103          * Crays, there is no such thing as an integer variable with 16 bits.
104          * Keep this in mind if you think this function should have been coded
105          * to use pointer overlays.  All the world's not a VAX.
106          */
107         char tmp[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp;
108         struct { int base, len; } best, cur;
109         u_int words[8];
110         int i;
111
112         /*
113          * Preprocess:
114          *      Copy the input (bytewise) array into a wordwise array.
115          *      Find the longest run of 0x00's in src[] for :: shorthanding.
116          */
117         memset(words, '\0', sizeof words);
118         for (i = 0; i < 16; i += 2)
119                 words[i / 2] = (src[i] << 8) | src[i + 1];
120         best.base = -1;
121         cur.base = -1;
122         for (i = 0; i < 8; i++) {
123                 if (words[i] == 0) {
124                         if (cur.base == -1)
125                                 cur.base = i, cur.len = 1;
126                         else
127                                 cur.len++;
128                 } else {
129                         if (cur.base != -1) {
130                                 if (best.base == -1 || cur.len > best.len)
131                                         best = cur;
132                                 cur.base = -1;
133                         }
134                 }
135         }
136         if (cur.base != -1) {
137                 if (best.base == -1 || cur.len > best.len)
138                         best = cur;
139         }
140         if (best.base != -1 && best.len < 2)
141                 best.base = -1;
142
143         /*
144          * Format the result.
145          */
146         tp = tmp;
147         for (i = 0; i < 8; i++) {
148                 /* Are we inside the best run of 0x00's? */
149                 if (best.base != -1 && i >= best.base &&
150                     i < (best.base + best.len)) {
151                         if (i == best.base)
152                                 *tp++ = ':';
153                         continue;
154                 }
155                 /* Are we following an initial run of 0x00s or any real hex? */
156                 if (i != 0)
157                         *tp++ = ':';
158                 /* Is this address an encapsulated IPv4? */
159                 if (i == 6 && best.base == 0 &&
160                     (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
161                         if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
162                                 return (NULL);
163                         tp += strlen(tp);
164                         break;
165                 }
166                 tp += sprintf(tp, "%x", words[i]);
167         }
168         /* Was it a trailing run of 0x00's? */
169         if (best.base != -1 && (best.base + best.len) == 8)
170                 *tp++ = ':';
171         *tp++ = '\0';
172
173         /*
174          * Check for overflow, copy, and we're done.
175          */
176         if ((size_t)(tp - tmp) > size) {
177                 __set_errno (ENOSPC);
178                 return (NULL);
179         }
180         return strcpy(dst, tmp);
181 }
182 #endif /* __UCLIBC_HAS_IPV6__ */
183
184
185 /* int
186  * inet_pton4(src, dst)
187  *      like inet_aton() but without all the hexadecimal and shorthand.
188  * return:
189  *      1 if `src' is a valid dotted quad, else 0.
190  * notice:
191  *      does not touch `dst' unless it's returning 1.
192  * author:
193  *      Paul Vixie, 1996.
194  */
195 static int
196 inet_pton4(const char *src, u_char *dst)
197 {
198         int saw_digit, octets, ch;
199         u_char tmp[4], *tp;
200
201         saw_digit = 0;
202         octets = 0;
203         *(tp = tmp) = 0;
204         while ((ch = *src++) != '\0') {
205
206                 if (ch >= '0' && ch <= '9') {
207                         u_int new = *tp * 10 + (ch - '0');
208
209                         if (new > 255)
210                                 return (0);
211                         *tp = new;
212                         if (! saw_digit) {
213                                 if (++octets > 4)
214                                         return (0);
215                                 saw_digit = 1;
216                         }
217                 } else if (ch == '.' && saw_digit) {
218                         if (octets == 4)
219                                 return (0);
220                         *++tp = 0;
221                         saw_digit = 0;
222                 } else
223                         return (0);
224         }
225         if (octets < 4)
226                 return (0);
227         memcpy(dst, tmp, 4);
228         return (1);
229 }
230
231 /* int
232  * inet_pton6(src, dst)
233  *      convert presentation level address to network order binary form.
234  * return:
235  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
236  * notice:
237  *      (1) does not touch `dst' unless it's returning 1.
238  *      (2) :: in a full address is silently ignored.
239  * credit:
240  *      inspired by Mark Andrews.
241  * author:
242  *      Paul Vixie, 1996.
243  */
244
245 #ifdef __UCLIBC_HAS_IPV6__
246
247 /* We cannot use the macro version of tolower() or very bad
248  * things happen when '*src++' gets evaluated multiple times.  
249  * So * undef it here so we get the function version of tolower
250  * instead.
251  */
252 #undef tolower
253
254 static int
255 inet_pton6(const char *src, u_char *dst)
256 {
257         static const char xdigits[] = "0123456789abcdef";
258         u_char tmp[16], *tp, *endp, *colonp;
259         const char *curtok;
260         int ch, saw_xdigit;
261         u_int val;
262
263
264         tp = memset(tmp, '\0', 16);
265         endp = tp + 16;
266         colonp = NULL;
267         /* Leading :: requires some special handling. */
268         if (*src == ':')
269                 if (*++src != ':')
270                         return (0);
271         curtok = src;
272         saw_xdigit = 0;
273         val = 0;
274         while ((ch = tolower (*src++)) != '\0') {
275                 const char *pch;
276
277                 pch = strchr(xdigits, ch);
278                 if (pch != NULL) {
279                         val <<= 4;
280                         val |= (pch - xdigits);
281                         if (val > 0xffff)
282                                 return (0);
283                         saw_xdigit = 1;
284                         continue;
285                 }
286                 if (ch == ':') {
287                         curtok = src;
288                         if (!saw_xdigit) {
289                                 if (colonp)
290                                         return (0);
291                                 colonp = tp;
292                                 continue;
293                         } else if (*src == '\0') {
294                                 return (0);
295                         }
296                         if (tp + 2 > endp)
297                                 return (0);
298                         *tp++ = (u_char) (val >> 8) & 0xff;
299                         *tp++ = (u_char) val & 0xff;
300                         saw_xdigit = 0;
301                         val = 0;
302                         continue;
303                 }
304                 if (ch == '.' && ((tp + 4) <= endp) &&
305                     inet_pton4(curtok, tp) > 0) {
306                         tp += 4;
307                         saw_xdigit = 0;
308                         break;  /* '\0' was seen by inet_pton4(). */
309                 }
310                 return (0);
311         }
312         if (saw_xdigit) {
313                 if (tp + 2 > endp)
314                         return (0);
315                 *tp++ = (u_char) (val >> 8) & 0xff;
316                 *tp++ = (u_char) val & 0xff;
317         }
318         if (colonp != NULL) {
319                 /*
320                  * Since some memmove()'s erroneously fail to handle
321                  * overlapping regions, we'll do the shift by hand.
322                  */
323                 const int n = tp - colonp;
324                 int i;
325
326                 if (tp == endp)
327                         return (0);
328                 for (i = 1; i <= n; i++) {
329                         endp[- i] = colonp[n - i];
330                         colonp[n - i] = 0;
331                 }
332                 tp = endp;
333         }
334         if (tp != endp)
335                 return (0);
336         memcpy(dst, tmp, 16);
337         return (1);
338 }
339
340 #endif /* __UCLIBC_HAS_IPV6__ */
341
342
343
344 /* char *
345  * inet_ntop(af, src, dst, size)
346  *      convert a network format address to presentation format.
347  * return:
348  *      pointer to presentation format address (`dst'), or NULL (see errno).
349  * author:
350  *      Paul Vixie, 1996.
351  */
352 extern const char *
353 inet_ntop(af, src, dst, size)
354         int af;
355         const void *src;
356         char *dst;
357         socklen_t size;
358 {
359         switch (af) {
360         case AF_INET:
361                 return (inet_ntop4(src, dst, size));
362 #ifdef __UCLIBC_HAS_IPV6__
363         case AF_INET6:
364                 return (inet_ntop6(src, dst, size));
365 #endif
366         default:
367                 __set_errno (EAFNOSUPPORT);
368                 return (NULL);
369         }
370         /* NOTREACHED */
371 }
372
373
374 /* int
375  * inet_pton(af, src, dst)
376  *      convert from presentation format (which usually means ASCII printable)
377  *      to network format (which is usually some kind of binary format).
378  * return:
379  *      1 if the address was valid for the specified address family
380  *      0 if the address wasn't valid (`dst' is untouched in this case)
381  *      -1 if some other error occurred (`dst' is untouched in this case, too)
382  * author:
383  *      Paul Vixie, 1996.
384  */
385 extern int
386 inet_pton(af, src, dst)
387         int af;
388         const char *src;
389         void *dst;
390 {
391         switch (af) {
392         case AF_INET:
393                 return (inet_pton4(src, dst));
394 #ifdef __UCLIBC_HAS_IPV6__
395         case AF_INET6:
396                 return (inet_pton6(src, dst));
397 #endif
398         default:
399                 __set_errno (EAFNOSUPPORT);
400                 return (-1);
401         }
402         /* NOTREACHED */
403 }
404