Major hostip.c cleanup and split into multiple files and easier #ifdef
[platform/upstream/curl.git] / lib / inet_ntop.c
1 /*
2  * Original code by Paul Vixie. "curlified" by Gisle Vanem.
3  */
4
5 #include "setup.h"
6
7 #ifndef HAVE_INET_NTOP
8
9 #ifdef HAVE_SYS_PARAM_H
10 #include <sys/param.h>
11 #endif
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15 #ifdef HAVE_SYS_SOCKET_H
16 #include <sys/socket.h>
17 #endif
18 #ifdef HAVE_NETINET_IN_H
19 #include <netinet/in.h>
20 #endif
21 #ifdef HAVE_ARPA_INET_H
22 #include <arpa/inet.h>
23 #endif
24 #include <string.h>
25 #include <errno.h>
26
27 #include "inet_ntop.h"
28
29 #define IN6ADDRSZ       16
30 #define INADDRSZ         4
31 #define INT16SZ          2
32
33 #ifdef WIN32
34 #define EAFNOSUPPORT    WSAEAFNOSUPPORT
35 #define SET_ERRNO(e)    WSASetLastError(errno = (e))
36 #else
37 #define SET_ERRNO(e)    errno = e
38 #endif
39
40 /*
41  * Format an IPv4 address, more or less like inet_ntoa().
42  *
43  * Returns `dst' (as a const)
44  * Note:
45  *  - uses no statics
46  *  - takes a u_char* not an in_addr as input
47  */
48 static const char *inet_ntop4 (const u_char *src, char *dst, size_t size)
49 {
50 #ifdef HAVE_INET_NTOA_R
51   return inet_ntoa_r(*(struct in_addr*)src, dst, size);
52 #else
53   const char *addr = inet_ntoa(*(struct in_addr*)src);
54
55   if (strlen(addr) >= size)
56   {
57     SET_ERRNO(ENOSPC);
58     return (NULL);
59   }
60   return strcpy(dst, addr);
61 #endif
62 }
63
64 #ifdef ENABLE_IPV6
65 /*
66  * Convert IPv6 binary address into presentation (printable) format.
67  */
68 static const char *inet_ntop6 (const u_char *src, char *dst, size_t size)
69 {
70   /*
71    * Note that int32_t and int16_t need only be "at least" large enough
72    * to contain a value of the specified size.  On some systems, like
73    * Crays, there is no such thing as an integer variable with 16 bits.
74    * Keep this in mind if you think this function should have been coded
75    * to use pointer overlays.  All the world's not a VAX.
76    */
77   char  tmp [sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
78   char *tp;
79   struct {
80     long base;
81     long len;
82   } best, cur;
83   u_long words [IN6ADDRSZ / INT16SZ];
84   int    i;
85
86   /* Preprocess:
87    *  Copy the input (bytewise) array into a wordwise array.
88    *  Find the longest run of 0x00's in src[] for :: shorthanding.
89    */
90   memset(words, 0, sizeof(words));
91   for (i = 0; i < IN6ADDRSZ; i++)
92       words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
93
94   best.base = -1;
95   cur.base  = -1;
96   for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
97   {
98     if (words[i] == 0)
99     {
100       if (cur.base == -1)
101         cur.base = i, cur.len = 1;
102       else
103         cur.len++;
104     }
105     else if (cur.base != -1)
106     {
107       if (best.base == -1 || cur.len > best.len)
108          best = cur;
109       cur.base = -1;
110     }
111   }
112   if ((cur.base != -1) && (best.base == -1 || cur.len > best.len))
113      best = cur;
114   if (best.base != -1 && best.len < 2)
115      best.base = -1;
116
117   /* Format the result.
118    */
119   tp = tmp;
120   for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
121   {
122     /* Are we inside the best run of 0x00's?
123      */
124     if (best.base != -1 && i >= best.base && i < (best.base + best.len))
125     {
126       if (i == best.base)
127          *tp++ = ':';
128       continue;
129     }
130
131     /* Are we following an initial run of 0x00s or any real hex?
132      */
133     if (i != 0)
134        *tp++ = ':';
135
136     /* Is this address an encapsulated IPv4?
137      */
138     if (i == 6 && best.base == 0 &&
139         (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
140     {
141       if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp)))
142       {
143         SET_ERRNO(ENOSPC);
144         return (NULL);
145       }
146       tp += strlen(tp);
147       break;
148     }
149     tp += sprintf (tp, "%lx", words[i]);
150   }
151
152   /* Was it a trailing run of 0x00's?
153    */
154   if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
155      *tp++ = ':';
156   *tp++ = '\0';
157
158   /* Check for overflow, copy, and we're done.
159    */
160   if ((size_t)(tp - tmp) > size)
161   {
162     SET_ERRNO(ENOSPC);
163     return (NULL);
164   }
165   return strcpy (dst, tmp);
166 }
167 #endif  /* ENABLE_IPV6 */
168
169 /*
170  * Convert a network format address to presentation format.
171  *
172  * Returns pointer to presentation format address (`dst'),
173  * Returns NULL on error (see errno).
174  */
175 const char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
176 {
177   switch (af) {
178   case AF_INET:
179     return inet_ntop4((const u_char*)src, buf, size);
180 #ifdef ENABLE_IPV6
181   case AF_INET6:
182     return inet_ntop6((const u_char*)src, buf, size);
183 #endif
184   default:
185     SET_ERRNO(EAFNOSUPPORT);
186     return NULL;
187   }
188 }
189 #endif  /* HAVE_INET_NTOP */