update MAINTAINERS
[uclibc-ng.git] / libc / inet / ntop.c
blob30dde6f9c28bca13f1fc9fe540b148e415c384ee
1 /*
2 * Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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.
18 #include <sys/param.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <arpa/nameser.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
33 * WARNING: Don't even consider trying to compile this on a system where
34 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
38 /* const char *
39 * inet_ntop4(src, dst, size)
40 * format an IPv4 address
41 * return:
42 * `dst' (as a const)
43 * notes:
44 * (1) uses no statics
45 * (2) takes a u_char* not an in_addr as input
46 * author:
47 * Paul Vixie, 1996.
49 static const char *
50 inet_ntop4(const u_char *src, char *dst, size_t size)
52 char tmp[sizeof ("255.255.255.255") + 1];
53 int octet;
54 int i;
56 tmp[0] = '\0';
58 i = 0;
59 for (octet = 0; octet <= 3; octet++) {
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;
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);
74 tmp[i++] = '0' + src[octet] % 10;
75 tmp[i++] = '.';
77 tmp[i - 1] = '\0';
79 if (strlen(tmp) > size) {
80 __set_errno(ENOSPC);
81 return NULL;
84 return strcpy(dst, tmp);
88 /* const char *
89 * inet_ntop6(src, dst, size)
90 * convert IPv6 binary address into presentation (printable) format
91 * author:
92 * Paul Vixie, 1996.
95 #ifdef __UCLIBC_HAS_IPV6__
97 static const char *
98 inet_ntop6(const u_char *src, char *dst, size_t size)
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.
107 char tmp[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp;
108 struct { int base, len; } best = { 0, 0 }, cur = { 0, 0 };
109 u_int words[8];
110 int i;
113 * Preprocess:
114 * Copy the input (bytewise) array into a wordwise array.
115 * Find the longest run of 0x00's in src[] for :: shorthanding.
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 best.len = best.len; /* shutting up compiler warning */
123 cur.len = cur.len; /* shutting up compiler warning */
124 for (i = 0; i < 8; i++) {
125 if (words[i] == 0) {
126 if (cur.base == -1)
127 cur.base = i, cur.len = 1;
128 else
129 cur.len++;
130 } else {
131 if (cur.base != -1) {
132 if (best.base == -1 || cur.len > best.len)
133 best = cur;
134 cur.base = -1;
138 if (cur.base != -1) {
139 if (best.base == -1 || cur.len > best.len)
140 best = cur;
142 if (best.base != -1 && best.len < 2)
143 best.base = -1;
146 * Format the result.
148 tp = tmp;
149 for (i = 0; i < 8; i++) {
150 /* Are we inside the best run of 0x00's? */
151 if (best.base != -1 && i >= best.base &&
152 i < (best.base + best.len)) {
153 if (i == best.base)
154 *tp++ = ':';
155 continue;
157 /* Are we following an initial run of 0x00s or any real hex? */
158 if (i != 0)
159 *tp++ = ':';
160 /* Is this address an encapsulated IPv4? */
161 if (i == 6 && best.base == 0 &&
162 (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
163 if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
164 return NULL;
165 tp += strlen(tp);
166 break;
168 tp += sprintf(tp, "%x", words[i]);
170 /* Was it a trailing run of 0x00's? */
171 if (best.base != -1 && (best.base + best.len) == 8)
172 *tp++ = ':';
173 *tp++ = '\0';
176 * Check for overflow, copy, and we're done.
178 if ((size_t)(tp - tmp) > size) {
179 __set_errno(ENOSPC);
180 return NULL;
182 return strcpy(dst, tmp);
184 #endif /* __UCLIBC_HAS_IPV6__ */
187 /* int
188 * inet_pton4(src, dst)
189 * like inet_aton() but without all the hexadecimal and shorthand.
190 * return:
191 * 1 if `src' is a valid dotted quad, else 0.
192 * notice:
193 * does not touch `dst' unless it's returning 1.
194 * author:
195 * Paul Vixie, 1996.
197 static int
198 inet_pton4(const char *src, u_char *dst)
200 int saw_digit, octets, ch;
201 u_char tmp[4], *tp;
203 saw_digit = 0;
204 octets = 0;
205 *(tp = tmp) = 0;
206 while ((ch = *src++) != '\0') {
208 if (ch >= '0' && ch <= '9') {
209 u_int new = *tp * 10 + (ch - '0');
211 if (new > 255)
212 return 0;
213 *tp = new;
214 if (! saw_digit) {
215 if (++octets > 4)
216 return 0;
217 saw_digit = 1;
219 } else if (ch == '.' && saw_digit) {
220 if (octets == 4)
221 return 0;
222 *++tp = 0;
223 saw_digit = 0;
224 } else
225 return 0;
227 if (octets < 4)
228 return 0;
229 memcpy(dst, tmp, 4);
230 return 1;
233 /* int
234 * inet_pton6(src, dst)
235 * convert presentation level address to network order binary form.
236 * return:
237 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
238 * notice:
239 * (1) does not touch `dst' unless it's returning 1.
240 * (2) :: in a full address is silently ignored.
241 * credit:
242 * inspired by Mark Andrews.
243 * author:
244 * Paul Vixie, 1996.
247 #ifdef __UCLIBC_HAS_IPV6__
249 static int
250 inet_pton6(const char *src, u_char *dst)
252 static const char xdigits[] = "0123456789abcdef";
253 u_char tmp[16], *tp, *endp, *colonp;
254 const char *curtok;
255 int ch, saw_xdigit;
256 u_int val;
259 tp = memset(tmp, '\0', 16);
260 endp = tp + 16;
261 colonp = NULL;
262 /* Leading :: requires some special handling. */
263 if (*src == ':')
264 if (*++src != ':')
265 return 0;
266 curtok = src;
267 saw_xdigit = 0;
268 val = 0;
269 while ((ch = *src++) != '\0') {
270 const char *pch;
272 /* | 0x20 is cheap tolower(), valid for letters/numbers only */
273 pch = strchr(xdigits, (ch | 0x20));
274 if (pch != NULL) {
275 val <<= 4;
276 val |= (pch - xdigits);
277 if (val > 0xffff)
278 return 0;
279 saw_xdigit = 1;
280 continue;
282 if (ch == ':') {
283 curtok = src;
284 if (!saw_xdigit) {
285 if (colonp)
286 return 0;
287 colonp = tp;
288 continue;
290 if (*src == '\0')
291 return 0;
292 if (tp + 2 > endp)
293 return 0;
294 *tp++ = (u_char) (val >> 8);
295 *tp++ = (u_char) val;
296 saw_xdigit = 0;
297 val = 0;
298 continue;
300 if (ch == '.' && ((tp + 4) <= endp) &&
301 inet_pton4(curtok, tp) > 0) {
302 tp += 4;
303 saw_xdigit = 0;
304 break; /* '\0' was seen by inet_pton4(). */
306 return 0;
308 if (saw_xdigit) {
309 if (tp + 2 > endp)
310 return 0;
311 *tp++ = (u_char) (val >> 8);
312 *tp++ = (u_char) val;
314 if (colonp != NULL) {
316 * Since some memmove()'s erroneously fail to handle
317 * overlapping regions, we'll do the shift by hand.
319 const int n = tp - colonp;
320 int i;
322 if (tp == endp)
323 return 0;
324 for (i = 1; i <= n; i++) {
325 endp[- i] = colonp[n - i];
326 colonp[n - i] = 0;
328 tp = endp;
330 if (tp != endp)
331 return 0;
332 memcpy(dst, tmp, 16);
333 return 1;
336 #endif /* __UCLIBC_HAS_IPV6__ */
340 /* char *
341 * inet_ntop(af, src, dst, size)
342 * convert a network format address to presentation format.
343 * return:
344 * pointer to presentation format address (`dst'), or NULL (see errno).
345 * author:
346 * Paul Vixie, 1996.
348 const char *
349 inet_ntop(int af, const void *src, char *dst, socklen_t size)
351 switch (af) {
352 case AF_INET:
353 return inet_ntop4(src, dst, size);
354 #ifdef __UCLIBC_HAS_IPV6__
355 case AF_INET6:
356 return inet_ntop6(src, dst, size);
357 #endif
358 default:
359 __set_errno(EAFNOSUPPORT);
360 return NULL;
362 /* NOTREACHED */
364 libc_hidden_def(inet_ntop)
367 /* int
368 * inet_pton(af, src, dst)
369 * convert from presentation format (which usually means ASCII printable)
370 * to network format (which is usually some kind of binary format).
371 * return:
372 * 1 if the address was valid for the specified address family
373 * 0 if the address wasn't valid (`dst' is untouched in this case)
374 * -1 if some other error occurred (`dst' is untouched in this case, too)
375 * author:
376 * Paul Vixie, 1996.
379 inet_pton(int af, const char *src, void *dst)
381 switch (af) {
382 case AF_INET:
383 return inet_pton4(src, dst);
384 #ifdef __UCLIBC_HAS_IPV6__
385 case AF_INET6:
386 return inet_pton6(src, dst);
387 #endif
388 default:
389 __set_errno(EAFNOSUPPORT);
390 return -1;
392 /* NOTREACHED */
394 libc_hidden_def(inet_pton)