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