]> git.mxchange.org Git - simgear.git/blob - 3rdparty/udns/inet_XtoX.c
Initial commit for a DNS service resolver
[simgear.git] / 3rdparty / udns / inet_XtoX.c
1 /* inet_XtoX.c
2  * Simple implementation of the following functions:
3  *  inet_ntop(), inet_ntoa(), inet_pton(), inet_aton().
4  *
5  * Differences from traditional implementaitons:
6  *  o modifies destination buffers even on error return.
7  *  o no fancy (hex, or 1.2) input support in inet_aton()
8  *  o inet_aton() does not accept junk after an IP address.
9  *  o inet_ntop(AF_INET) requires at least 16 bytes in dest,
10  *    and inet_ntop(AF_INET6) at least 40 bytes
11  *    (traditional inet_ntop() will try to fit anyway)
12  *
13  * Compile with -Dinet_XtoX_prefix=pfx_ to have pfx_*() instead of inet_*()
14  * Compile with -Dinet_XtoX_no_ntop or -Dinet_XtoX_no_pton
15  *  to disable net2str or str2net conversions.
16  *
17  * #define inet_XtoX_prototypes and #include "this_file.c"
18  * to get function prototypes only (but not for inet_ntoa()).
19  * #define inet_XtoX_decl to be `static' for static visibility,
20  * or use __declspec(dllexport) or somesuch...
21  *
22  * Compile with -DTEST to test against stock implementation.
23  *
24  * Written by Michael Tokarev.  Public domain.
25  */
26
27 #ifdef inet_XtoX_prototypes
28
29 struct in_addr;
30
31 #else
32
33 #include <errno.h>
34
35 #ifdef TEST
36
37 # include <netinet/in.h>
38 # include <sys/socket.h>
39 # include <arpa/inet.h>
40 # include <stdio.h>
41 # include <stdlib.h>
42 # include <unistd.h>
43 # include <string.h>
44 # undef inet_XtoX_prefix
45 # define inet_XtoX_prefix mjt_inet_
46 # undef inet_XtoX_no_ntop
47 # undef inet_XtoX_no_pton
48
49 #else /* !TEST */
50
51 struct in_addr {        /* declare it here to avoid messing with headers */
52   unsigned char x[4];
53 };
54
55 #endif /* TEST */
56
57 #endif /* inet_XtoX_prototypes */
58
59 #ifndef inet_XtoX_prefix
60 # define inet_XtoX_prefix inet_
61 #endif
62 #ifndef inet_XtoX_decl
63 # define inet_XtoX_decl /*empty*/
64 #endif
65
66 #define cc2_(x,y) cc2__(x,y)
67 #define cc2__(x,y) x##y
68 #define fn(x) cc2_(inet_XtoX_prefix,x)
69
70 #ifndef inet_XtoX_no_ntop
71
72 inet_XtoX_decl const char *
73 fn(ntop)(int af, const void *src, char *dst, unsigned size);
74
75 #ifndef inet_XtoX_prototypes
76
77 static int mjt_ntop4(const void *_src, char *dst, int size) {
78   unsigned i, x, r;
79   char *p;
80   const unsigned char *s = _src;
81   if (size < 4*4)       /* for simplicity, disallow non-max-size buffer */
82     return 0;
83   for (i = 0, p = dst; i < 4; ++i) {
84     if (i) *p++ = '.';
85     x = r = s[i];
86     if (x > 99) { *p++ = (char)(r / 100 + '0'); r %= 100; }
87     if (x > 9) { *p++ = (char)(r / 10 + '0'); r %= 10; }
88     *p++ = (char)(r + '0');
89   }
90   *p = '\0';
91   return 1;
92 }
93
94 static char *hexc(char *p, unsigned x) {
95   static char hex[16] = "0123456789abcdef";
96   if (x > 0x0fff) *p++ = hex[(x >>12) & 15];
97   if (x > 0x00ff) *p++ = hex[(x >> 8) & 15];
98   if (x > 0x000f) *p++ = hex[(x >> 4) & 15];
99   *p++ = hex[x & 15];
100   return p;
101 }
102
103 static int mjt_ntop6(const void *_src, char *dst, int size) {
104   unsigned i;
105   unsigned short w[8];
106   unsigned bs = 0, cs = 0;
107   unsigned bl = 0, cl = 0;
108   char *p;
109   const unsigned char *s = _src;
110
111   if (size < 40)        /* for simplicity, disallow non-max-size buffer */
112     return 0;
113
114   for(i = 0; i < 8; ++i, s += 2) {
115     w[i] = (((unsigned short)(s[0])) << 8) | s[1];
116     if (!w[i]) {
117       if (!cl++) cs = i;
118     }
119     else {
120       if (cl > bl) bl = cl, bs = cs;
121     }
122   }
123   if (cl > bl) bl = cl, bs = cs;
124   p = dst;
125   if (bl == 1)
126     bl = 0;
127   if (bl) {
128     for(i = 0; i < bs; ++i) {
129       if (i) *p++ = ':';
130       p = hexc(p, w[i]);
131     }
132     *p++ = ':';
133     i += bl;
134     if (i == 8)
135       *p++ = ':';
136   }
137   else
138     i = 0;
139   for(; i < 8; ++i) {
140     if (i) *p++ = ':';
141     if (i == 6 && !bs && (bl == 6 || (bl == 5 && w[5] == 0xffff)))
142       return mjt_ntop4(s - 4, p, size - (p - dst));
143     p = hexc(p, w[i]);
144   }
145   *p = '\0';
146   return 1;
147 }
148
149 inet_XtoX_decl const char *
150 fn(ntop)(int af, const void *src, char *dst, unsigned size) {
151   switch(af) {
152   /* don't use AF_*: don't mess with headers */
153   case 2:  /* AF_INET */  if (mjt_ntop4(src, dst, size)) return dst; break;
154   case 10: /* AF_INET6 */ if (mjt_ntop6(src, dst, size)) return dst; break;
155   default: errno = EAFNOSUPPORT; return (char*)0;
156   }
157   errno = ENOSPC;
158   return (char*)0;
159 }
160
161 inet_XtoX_decl const char *
162 fn(ntoa)(struct in_addr addr) {
163   static char buf[4*4];
164   mjt_ntop4(&addr, buf, sizeof(buf));
165   return buf;
166 }
167
168 #endif /* inet_XtoX_prototypes */
169 #endif /* inet_XtoX_no_ntop */
170
171 #ifndef inet_XtoX_no_pton
172
173 inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst);
174 inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr);
175
176 #ifndef inet_XtoX_prototypes
177
178 static int mjt_pton4(const char *c, void *dst) {
179   unsigned char *a = dst;
180   unsigned n, o;
181   for (n = 0; n < 4; ++n) {
182     if (*c < '0' || *c > '9')
183       return 0;
184     o = *c++ - '0';
185     while(*c >= '0' && *c <= '9')
186       if ((o = o * 10 + (*c++ - '0')) > 255)
187         return 0;
188     if (*c++ != (n == 3 ? '\0' : '.'))
189       return 0;
190     *a++ = (unsigned char)o;
191   }
192   return 1;
193 }
194
195 static int mjt_pton6(const char *c, void *dst) {
196   unsigned short w[8], *a = w, *z, *i;
197   unsigned v, o;
198   const char *sc;
199   unsigned char *d = dst;
200   if (*c != ':') z = (unsigned short*)0;
201   else if (*++c != ':') return 0;
202   else ++c, z = a;
203   i = 0;
204   for(;;) {
205     v = 0;
206     sc = c;
207     for(;;) {
208       if (*c >= '0' && *c <= '9') o = *c - '0';
209       else if (*c >= 'a' && *c <= 'f') o = *c - 'a' + 10;
210       else if (*c >= 'A' && *c <= 'F') o = *c - 'A' + 10;
211       else break;
212       v = (v << 4) | o;
213       if (v > 0xffff) return 0;
214       ++c;
215     }
216     if (sc == c) {
217       if (z == a && !*c)
218         break;
219       else
220         return 0;
221     }
222     if (*c == ':') {
223       if (a >= w + 8)
224         return 0;
225       *a++ = v;
226       if (*++c == ':') {
227         if (z)
228           return 0;
229         z = a;
230         if (!*++c)
231           break;
232       }
233     }
234     else if (!*c) {
235       if (a >= w + 8)
236         return 0;
237       *a++ = v;
238       break;
239     }
240     else if (*c == '.') {
241       if (a > w + 6)
242         return 0;
243       if (!mjt_pton4(sc, d))
244         return 0;
245       *a++ = ((unsigned)(d[0]) << 8) | d[1];
246       *a++ = ((unsigned)(d[2]) << 8) | d[3];
247       break;
248     }
249     else
250       return 0;
251   }
252   v = w + 8 - a;
253   if ((v && !z) || (!v && z))
254     return 0;
255   for(i = w; ; ++i) {
256     if (i == z)
257       while(v--) { *d++ = '\0'; *d++ = '\0'; }
258     if (i >= a)
259       break;
260     *d++ = (unsigned char)((*i >> 8) & 255);
261     *d++ = (unsigned char)(*i & 255);
262   }
263   return 1;
264 }
265
266 inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst) {
267   switch(af) {
268   /* don't use AF_*: don't mess with headers */
269   case 2  /* AF_INET  */: return mjt_pton4(src, dst);
270   case 10 /* AF_INET6 */: return mjt_pton6(src, dst);
271   default: errno = EAFNOSUPPORT; return -1;
272   }
273 }
274
275 inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr) {
276   return mjt_pton4(src, addr);
277 }
278
279 #endif /* inet_XtoX_prototypes */
280
281 #endif /* inet_XtoX_no_pton */
282
283 #ifdef TEST
284
285 int main(int argc, char **argv) {
286   int i;
287   char n0[16], n1[16];
288   char p0[64], p1[64];
289   int af = AF_INET;
290   int pl = sizeof(p0);
291   int r0, r1;
292   const char *s0, *s1;
293
294   while((i = getopt(argc, argv, "46a:p:")) != EOF) switch(i) {
295   case '4': af = AF_INET;  break;
296   case '6': af = AF_INET6; break;
297   case 'a': case 'p': pl = atoi(optarg); break;
298   default: return 1;
299   }
300   for(i = optind; i < argc; ++i) {
301     char *a = argv[i];
302
303     printf("%s:\n", a);
304     r0 = inet_pton(af, a, n0);
305     printf(" p2n stock: %s\n",
306      (r0 < 0 ? "(notsupp)" : !r0 ? "(inval)" : fn(ntop)(af,n0,p0,sizeof(p0))));
307     r1 = fn(pton)(af, a, n1);
308     printf(" p2n this : %s\n",
309      (r1 < 0 ? "(notsupp)" : !r1 ? "(inval)" : fn(ntop)(af,n1,p1,sizeof(p1))));
310
311     if ((r0 > 0) != (r1 > 0) ||
312         (r0 > 0 && r1 > 0 && memcmp(n0, n1, af == AF_INET ? 4 : 16) != 0))
313       printf(" DIFFER!\n");
314
315     s0 = inet_ntop(af, n1, p0, pl);
316     printf(" n2p stock: %s\n", s0 ? s0 : "(inval)");
317     s1 = fn(ntop)(af, n1, p1, pl);
318     printf(" n2p this : %s\n", s1 ? s1 : "(inval)");
319     if ((s0 != 0) != (s1 != 0) ||
320         (s0 && s1 && strcmp(s0, s1) != 0))
321       printf(" DIFFER!\n");
322
323   }
324   return 0;
325 }
326
327 #endif /* TEST */