Chromium Code Reviews| Index: native_client_sdk/src/libraries/nacl_io/syscalls/inet_pton.cc |
| diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/inet_pton.cc b/native_client_sdk/src/libraries/nacl_io/syscalls/inet_pton.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..08ad0778b5979417f1e3ae1a82d8f72ae7ee9683 |
| --- /dev/null |
| +++ b/native_client_sdk/src/libraries/nacl_io/syscalls/inet_pton.cc |
| @@ -0,0 +1,149 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "nacl_io/ossocket.h" |
| +#if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) |
| + |
| +#include <errno.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| + |
| +#include <iostream> |
| +#include <sstream> |
| +#include <string> |
|
Sam Clegg
2013/12/06 02:31:36
Are you using any of these C++ headers?
If not ca
Sergey Ulanov
2013/12/06 20:20:22
No, removed.
|
| + |
| +#include "sdk_util/macros.h" |
| + |
| +// Helper function for inet_pton() for IPv4 addresses. |
| +static int inet_pton_v4(const char* src, void* dst) { |
| + const int kIpv4AddressSize = 4; |
| + const char* pos = src; |
| + uint8_t result[kIpv4AddressSize] = {0}; |
| + |
| + for (int i = 0; i < kIpv4AddressSize; ++i) { |
| + // strtol() won't treat whitespace characters in the beginning as an error, |
| + // so check to ensure this is started with digit before passing to strtol(). |
| + if (isspace(*pos)) |
| + return 0; |
| + char* end_pos; |
| + unsigned long value = strtoul(pos, &end_pos, 10); |
| + if (value > 255 || pos == end_pos) |
| + return 0; |
| + result[i] = static_cast<unsigned char>(value); |
| + pos = end_pos; |
| + |
| + if (i < (kIpv4AddressSize - 1)) { |
| + if (*pos != '.') |
| + return 0; |
| + ++pos; |
| + } |
| + } |
| + if (*pos != '\0') |
| + return 0; |
| + memcpy(dst, result, sizeof(result)); |
| + return 1; |
| +} |
| + |
| +// Helper function for inet_pton() for IPv6 addresses. |
| +int inet_pton_v6(const char* src, void* dst) { |
| + // strtol() skips 0x in from of a number, while it's not allowed in IPv6 |
| + // addresses. Check that there is no 'x' in the string. |
| + const char* pos = src; |
| + while (*pos != '\0') { |
| + if (*pos == 'x') |
| + return 0; |
| + pos++; |
| + } |
| + pos = src; |
| + |
| + int kIpv6AddressSize = 16; |
| + uint8_t result[kIpv6AddressSize]; |
| + memset(&result, 0, sizeof(result)); |
| + int double_colon_pos = -1; |
| + int result_pos = 0; |
| + |
| + if (*pos == ':') { |
| + if (*(pos + 1) != ':') |
| + return 0; |
| + pos += 2; |
| + double_colon_pos = 0; |
| + } |
| + |
| + while (*pos != '\0') { |
| + // strtol() won't treat whitespace characters in the beginning as an error, |
| + // so check to ensure this is started with digit before passing to strtol(). |
| + if (isspace(*pos)) |
| + return 0; |
| + char* end_pos; |
| + unsigned long word = strtoul(pos, &end_pos, 16); |
| + if (word > 0xffff || pos == end_pos) |
| + return 0; |
| + |
| + if (*end_pos == '.') { |
| + if (result_pos + 4 > kIpv6AddressSize) |
| + return 0; |
| + // Parse rest of address as IPv4 address. |
| + if (!inet_pton_v4(pos, result + result_pos)) |
| + return 0; |
| + result_pos += 4; |
| + break; |
| + } |
| + |
| + if (result_pos > kIpv6AddressSize - 2) |
| + return 0; |
| + result[result_pos] = (word & 0xFF00) >> 8; |
| + result[result_pos + 1] = word & 0xFF; |
| + result_pos += 2; |
| + |
| + if (*end_pos == '\0') |
| + break; |
| + |
| + if (*end_pos != ':') |
| + return 0; |
| + |
| + pos = end_pos + 1; |
| + if (*pos == ':') { |
| + if (double_colon_pos != -1) |
| + return 0; |
| + double_colon_pos = result_pos; |
| + ++pos; |
| + } |
| + } |
| + |
| + // Finally move the data to the end in case the address contained '::'. |
| + if (result_pos < kIpv6AddressSize) { |
| + if (double_colon_pos == -1) |
| + return 0; |
| + int move_size = result_pos - double_colon_pos; |
| + int gap_size = kIpv6AddressSize - result_pos; |
| + memmove(result + kIpv6AddressSize - move_size, |
| + result + double_colon_pos, move_size); |
| + memset(result + double_colon_pos, 0, gap_size); |
| + } |
| + |
| + // Finally copy the result to the output buffer. |
| + memcpy(dst, result, sizeof(result)); |
| + |
| + return 1; |
| +} |
| + |
| +EXTERN_C_BEGIN |
| + |
| +int inet_pton(int af, const char *src, void *dst) { |
| + if (!src || !dst) { |
| + return 0; |
| + } |
| + if (af == AF_INET) { |
| + return inet_pton_v4(src, dst); |
| + } else if (af == AF_INET6) { |
| + return inet_pton_v6(src, dst); |
| + } |
| + errno = EAFNOSUPPORT; |
| + return -1; |
| +} |
| + |
| +EXTERN_C_END |
| + |
| +#endif // defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__) |
| + |