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