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