91d3c6cef56cccbc8544ff2b936d2ab51da04657
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / syscalls / inet_pton.c
1 /* Copyright 2013 The Chromium Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file. */
4
5 #include "nacl_io/ossocket.h"
6 #if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
7
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "sdk_util/macros.h"
14
15 enum {
16   kIpv4AddressSize = sizeof(in_addr_t),
17   kIpv6AddressSize = sizeof(struct in6_addr),
18 };
19
20 /* Helper function for inet_pton() for IPv4 addresses. */
21 static int inet_pton_v4(const char* src, void* dst) {
22   const char* pos = src;
23   uint8_t result[kIpv4AddressSize] = {0};
24
25   int i;
26   for (i = 0; i < kIpv4AddressSize; ++i) {
27     /* strtol() won't treat whitespace characters in the beginning as an error,
28      * so check to ensure this is started with digit before passing to strtol().
29      */
30     if (isspace((int)(*pos)))
31       return 0;
32     char* end_pos;
33     unsigned long value = strtoul(pos, &end_pos, 10);
34     if (value > 255 || pos == end_pos)
35       return 0;
36     result[i] = (unsigned char)value;
37     pos = end_pos;
38
39     if (i < (kIpv4AddressSize - 1)) {
40       if (*pos != '.')
41         return 0;
42       ++pos;
43     }
44   }
45   if (*pos != '\0')
46     return 0;
47   memcpy(dst, result, sizeof(result));
48   return 1;
49 }
50
51 /* Helper function for inet_pton() for IPv6 addresses. */
52 int inet_pton_v6(const char* src, void* dst) {
53   /* strtol() skips 0x in from of a number, while it's not allowed in IPv6
54    * addresses. Check that there is no 'x' in the string. */
55   const char* pos = src;
56   while (*pos != '\0') {
57     if (*pos == 'x')
58       return 0;
59     pos++;
60   }
61   pos = src;
62
63   uint8_t result[kIpv6AddressSize];
64   memset(&result, 0, sizeof(result));
65   int double_colon_pos = -1;
66   int result_pos = 0;
67
68   if (*pos == ':') {
69     if (*(pos + 1) != ':')
70       return 0;
71     pos += 2;
72     double_colon_pos = 0;
73   }
74
75   while (*pos != '\0') {
76     /* strtol() won't treat whitespace characters in the beginning as an error,
77      * so check to ensure this is started with digit before passing to strtol().
78      */
79     if (isspace((int)(*pos)))
80       return 0;
81     char* end_pos;
82     unsigned long word = strtoul(pos, &end_pos, 16);
83     if (word > 0xffff || pos == end_pos)
84       return 0;
85
86     if (*end_pos == '.')  {
87       if (result_pos + kIpv4AddressSize > kIpv6AddressSize)
88         return 0;
89       /* Parse rest of address as IPv4 address. */
90       if (!inet_pton_v4(pos, result + result_pos))
91         return 0;
92       result_pos += 4;
93       break;
94     }
95
96     if (result_pos > kIpv6AddressSize - 2)
97       return 0;
98     result[result_pos] = (word & 0xFF00) >> 8;
99     result[result_pos + 1] = word & 0xFF;
100     result_pos += 2;
101
102     if (*end_pos == '\0')
103       break;
104
105     if (*end_pos != ':')
106       return 0;
107
108     pos = end_pos + 1;
109     if (*pos == ':') {
110       if (double_colon_pos != -1)
111         return 0;
112       double_colon_pos = result_pos;
113       ++pos;
114     }
115   }
116
117   /* Finally move the data to the end in case the address contained '::'. */
118   if (result_pos < kIpv6AddressSize) {
119     if (double_colon_pos == -1)
120       return 0;
121     int move_size = result_pos - double_colon_pos;
122     int gap_size = kIpv6AddressSize - result_pos;
123     memmove(result + kIpv6AddressSize - move_size,
124             result + double_colon_pos, move_size);
125     memset(result + double_colon_pos, 0, gap_size);
126   }
127
128   /* Finally copy the result to the output buffer. */
129   memcpy(dst, result, sizeof(result));
130
131   return 1;
132 }
133
134 int inet_pton(int af, const char *src, void *dst) {
135   if (!src || !dst) {
136     return 0;
137   }
138   if (af == AF_INET) {
139     return inet_pton_v4(src, dst);
140   } else if (af == AF_INET6) {
141     return inet_pton_v6(src, dst);
142   }
143   errno = EAFNOSUPPORT;
144   return -1;
145 }
146
147 #endif  /* defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) */