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. */
5 #include "nacl_io/ossocket.h"
6 #if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) && !defined(__BIONIC__)
13 #include "sdk_util/macros.h"
16 kIpv4AddressSize
= sizeof(in_addr_t
),
17 kIpv6AddressSize
= sizeof(struct in6_addr
),
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};
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().
30 if (isspace((int)(*pos
)))
33 unsigned long value
= strtoul(pos
, &end_pos
, 10);
34 if (value
> 255 || pos
== end_pos
)
36 result
[i
] = (unsigned char)value
;
39 if (i
< (kIpv4AddressSize
- 1)) {
47 memcpy(dst
, result
, sizeof(result
));
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') {
63 uint8_t result
[kIpv6AddressSize
];
64 memset(&result
, 0, sizeof(result
));
65 int double_colon_pos
= -1;
69 if (*(pos
+ 1) != ':')
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().
79 if (isspace((int)(*pos
)))
82 unsigned long word
= strtoul(pos
, &end_pos
, 16);
83 if (word
> 0xffff || pos
== end_pos
)
86 if (*end_pos
== '.') {
87 if (result_pos
+ kIpv4AddressSize
> kIpv6AddressSize
)
89 /* Parse rest of address as IPv4 address. */
90 if (!inet_pton_v4(pos
, result
+ result_pos
))
96 if (result_pos
> kIpv6AddressSize
- 2)
98 result
[result_pos
] = (word
& 0xFF00) >> 8;
99 result
[result_pos
+ 1] = word
& 0xFF;
102 if (*end_pos
== '\0')
110 if (double_colon_pos
!= -1)
112 double_colon_pos
= result_pos
;
117 /* Finally move the data to the end in case the address contained '::'. */
118 if (result_pos
< kIpv6AddressSize
) {
119 if (double_colon_pos
== -1)
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
);
128 /* Finally copy the result to the output buffer. */
129 memcpy(dst
, result
, sizeof(result
));
134 int inet_pton(int af
, const char *src
, void *dst
) {
139 return inet_pton_v4(src
, dst
);
140 } else if (af
== AF_INET6
) {
141 return inet_pton_v6(src
, dst
);
143 errno
= EAFNOSUPPORT
;
147 #endif /* defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) ... */