net_address_private_impl.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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 "ppapi/shared_impl/private/net_address_private_impl.h"
6
7#if defined(OS_WIN)
8#include <windows.h>
9#include <winsock2.h>
10#include <ws2tcpip.h>
11#elif defined(OS_POSIX) && !defined(OS_NACL)
12#include <arpa/inet.h>
13#include <sys/socket.h>
14#include <sys/types.h>
15#endif
16
17#include <string.h>
18
19#include <string>
20
21#include "base/basictypes.h"
22#include "base/logging.h"
23#include "base/stringprintf.h"
24#include "build/build_config.h"
25#include "ppapi/c/pp_var.h"
26#include "ppapi/c/private/ppb_net_address_private.h"
27#include "ppapi/shared_impl/var.h"
28#include "ppapi/thunk/thunk.h"
29
30#if defined(OS_MACOSX)
31// This is a bit evil, but it's standard operating procedure for |s6_addr|....
32#define s6_addr16 __u6_addr.__u6_addr16
33#endif
34
35#if defined(OS_WIN)
36// The type of |sockaddr::sa_family|.
37typedef ADDRESS_FAMILY sa_family_t;
38
39#define s6_addr16 u.Word
40#define ntohs(x) _byteswap_ushort(x)
41#define htons(x) _byteswap_ushort(x)
42#endif  // defined(OS_WIN)
43
44// The net address interface doesn't have a normal C -> C++ thunk since it
45// doesn't actually have any proxy wrapping or associated objects; it's just a
46// call into base. So we implement the entire interface here, using the thunk
47// namespace so it magically gets hooked up in the proper places.
48
49namespace ppapi {
50
51namespace {
52
53// Define our own net-host-net conversion, rather than reuse the one in
54// base/sys_byteorder.h, to simplify the NaCl port. NaCl has no byte swap
55// primitives.
56uint16 ConvertNetEndian16(uint16 x) {
57#if defined(ARCH_CPU_LITTLE_ENDIAN)
58  return (x << 8) | (x >> 8);
59#else
60  return x;
61#endif
62}
63
64static const size_t kIPv4AddressSize = 4;
65static const size_t kIPv6AddressSize = 16;
66
67// This structure is a platform-independent representation of a network address.
68// It is a private format that we embed in PP_NetAddress_Private and is NOT part
69// of the stable Pepper API.
70struct NetAddress {
71  bool is_valid;
72  bool is_ipv6;  // if true, IPv6, otherwise IPv4.
73  uint16_t port;  // host order, not network order.
74  int32_t flow_info;  // 0 for IPv4
75  int32_t scope_id;   // 0 for IPv4
76  // IPv4 addresses are 4 bytes. IPv6 are 16 bytes. Addresses are stored in net
77  // order (big-endian), which only affects IPv6 addresses, which consist of 8
78  // 16-bit components. These will be byte-swapped on small-endian hosts.
79  uint8_t address[kIPv6AddressSize];
80};
81
82// Make sure that sizeof(NetAddress) is the same for all compilers. This ensures
83// that the alignment is the same on both sides of the NaCl proxy, which is
84// important because we serialize and deserialize PP_NetAddress_Private by
85// simply copying the raw bytes.
86COMPILE_ASSERT(sizeof(NetAddress) == 28,
87               NetAddress_different_for_compiler);
88
89// Make sure the storage in |PP_NetAddress_Private| is big enough. (Do it here
90// since the data is opaque elsewhere.)
91COMPILE_ASSERT(sizeof(reinterpret_cast<PP_NetAddress_Private*>(0)->data) >=
92               sizeof(NetAddress),
93               PP_NetAddress_Private_data_too_small);
94
95size_t GetAddressSize(const NetAddress* net_addr) {
96  return net_addr->is_ipv6 ? kIPv6AddressSize : kIPv4AddressSize;
97}
98
99// Convert to embedded struct if it has been initialized.
100NetAddress* ToNetAddress(PP_NetAddress_Private* addr) {
101  if (!addr || addr->size != sizeof(NetAddress))
102    return NULL;
103  return reinterpret_cast<NetAddress*>(addr->data);
104}
105
106const NetAddress* ToNetAddress(const PP_NetAddress_Private* addr) {
107  return ToNetAddress(const_cast<PP_NetAddress_Private*>(addr));
108}
109
110// Initializes the NetAddress struct embedded in a PP_NetAddress_Private struct.
111// Zeroes the memory, so net_addr->is_valid == false.
112NetAddress* InitNetAddress(PP_NetAddress_Private* addr) {
113  addr->size = sizeof(NetAddress);
114  NetAddress* net_addr = ToNetAddress(addr);
115  DCHECK(net_addr);
116  memset(net_addr, 0, sizeof(NetAddress));
117  return net_addr;
118}
119
120bool IsValid(const NetAddress* net_addr) {
121  return net_addr && net_addr->is_valid;
122}
123
124PP_NetAddressFamily_Private GetFamily(const PP_NetAddress_Private* addr) {
125  const NetAddress* net_addr = ToNetAddress(addr);
126  if (!IsValid(net_addr))
127    return PP_NETADDRESSFAMILY_UNSPECIFIED;
128  return net_addr->is_ipv6 ?
129         PP_NETADDRESSFAMILY_IPV6 : PP_NETADDRESSFAMILY_IPV4;
130}
131
132uint16_t GetPort(const PP_NetAddress_Private* addr) {
133  const NetAddress* net_addr = ToNetAddress(addr);
134  if (!IsValid(net_addr))
135    return 0;
136  return net_addr->port;
137}
138
139PP_Bool GetAddress(const PP_NetAddress_Private* addr,
140                   void* address,
141                   uint16_t address_size) {
142  const NetAddress* net_addr = ToNetAddress(addr);
143  if (!IsValid(net_addr))
144    return PP_FALSE;
145  size_t net_addr_size = GetAddressSize(net_addr);
146  // address_size must be big enough.
147  if (net_addr_size > address_size)
148    return PP_FALSE;
149  memcpy(address, net_addr->address, net_addr_size);
150  return PP_TRUE;
151}
152
153uint32_t GetScopeID(const PP_NetAddress_Private* addr) {
154  const NetAddress* net_addr = ToNetAddress(addr);
155  if (!IsValid(net_addr))
156    return 0;
157  return net_addr->scope_id;
158}
159
160PP_Bool AreHostsEqual(const PP_NetAddress_Private* addr1,
161                      const PP_NetAddress_Private* addr2) {
162  const NetAddress* net_addr1 = ToNetAddress(addr1);
163  const NetAddress* net_addr2 = ToNetAddress(addr2);
164  if (!IsValid(net_addr1) || !IsValid(net_addr2))
165    return PP_FALSE;
166
167  if ((net_addr1->is_ipv6 != net_addr2->is_ipv6) ||
168      (net_addr1->flow_info != net_addr2->flow_info) ||
169      (net_addr1->scope_id != net_addr2->scope_id))
170    return PP_FALSE;
171
172  size_t net_addr_size = GetAddressSize(net_addr1);
173  for (size_t i = 0; i < net_addr_size; i++) {
174    if (net_addr1->address[i] != net_addr2->address[i])
175      return PP_FALSE;
176  }
177
178  return PP_TRUE;
179}
180
181PP_Bool AreEqual(const PP_NetAddress_Private* addr1,
182                 const PP_NetAddress_Private* addr2) {
183  // |AreHostsEqual()| will also validate the addresses and return false if
184  // either is invalid.
185  if (!AreHostsEqual(addr1, addr2))
186    return PP_FALSE;
187
188  // AreHostsEqual has validated these net addresses.
189  const NetAddress* net_addr1 = ToNetAddress(addr1);
190  const NetAddress* net_addr2 = ToNetAddress(addr2);
191  return PP_FromBool(net_addr1->port == net_addr2->port);
192}
193
194std::string ConvertIPv4AddressToString(const NetAddress* net_addr,
195                                       bool include_port) {
196  std::string description = base::StringPrintf(
197      "%u.%u.%u.%u",
198      net_addr->address[0], net_addr->address[1],
199      net_addr->address[2], net_addr->address[3]);
200  if (include_port)
201    base::StringAppendF(&description, ":%u", net_addr->port);
202  return description;
203}
204
205// Format an IPv6 address for human consumption, basically according to RFC
206// 5952.
207//  - If the scope is nonzero, it is appended to the address as "%<scope>" (this
208//    is not in RFC 5952, but consistent with |getnameinfo()| on Linux and
209//    Windows).
210//  - If |include_port| is true, the address (possibly including the scope) is
211//    enclosed in square brackets and ":<port>" is appended, i.e., the overall
212//    format is "[<address>]:<port>".
213//  - If the address is an IPv4 address embedded IPv6 (per RFC 4291), then the
214//    mixed format is used, e.g., "::ffff:192.168.1.2". This is optional per RFC
215//    5952, but consistent with |getnameinfo()|.
216std::string ConvertIPv6AddressToString(const NetAddress* net_addr,
217                                       bool include_port) {
218  std::string description(include_port ? "[" : "");
219
220  const uint16_t* address16 =
221      reinterpret_cast<const uint16_t*>(net_addr->address);
222  // IPv4 address embedded in IPv6.
223  if (address16[0] == 0 && address16[1] == 0 &&
224      address16[2] == 0 && address16[3] == 0 &&
225      address16[4] == 0 &&
226      (address16[5] == 0 || address16[5] == 0xffff)) {
227    base::StringAppendF(
228        &description,
229        address16[5] == 0 ? "::%u.%u.%u.%u" : "::ffff:%u.%u.%u.%u",
230        net_addr->address[12],
231        net_addr->address[13],
232        net_addr->address[14],
233        net_addr->address[15]);
234
235  // "Real" IPv6 addresses.
236  } else {
237    // Find the first longest run of 0s (of length > 1), to collapse to "::".
238    int longest_start = 0;
239    int longest_length = 0;
240    int curr_start = 0;
241    int curr_length = 0;
242    for (int i = 0; i < 8; i++) {
243      if (address16[i] != 0) {
244        curr_length = 0;
245      } else {
246        if (!curr_length)
247          curr_start = i;
248        curr_length++;
249        if (curr_length > longest_length) {
250          longest_start = curr_start;
251          longest_length = curr_length;
252        }
253      }
254    }
255
256    bool need_sep = false;  // Whether the next item needs a ':' to separate.
257    for (int i = 0; i < 8;) {
258      if (longest_length > 1 && i == longest_start) {
259        description.append("::");
260        need_sep = false;
261        i += longest_length;
262      } else {
263        uint16_t v = ConvertNetEndian16(address16[i]);
264        base::StringAppendF(&description, need_sep ? ":%x" : "%x", v);
265        need_sep = true;
266        i++;
267      }
268    }
269  }
270
271  // Nonzero scopes, e.g., 123, are indicated by appending, e.g., "%123".
272  if (net_addr->scope_id != 0)
273    base::StringAppendF(&description, "%%%u", net_addr->scope_id);
274
275  if (include_port)
276    base::StringAppendF(&description, "]:%u", net_addr->port);
277
278  return description;
279}
280
281PP_Var Describe(PP_Module /*module*/,
282                const struct PP_NetAddress_Private* addr,
283                PP_Bool include_port) {
284  std::string str = NetAddressPrivateImpl::DescribeNetAddress(
285      *addr, PP_ToBool(include_port));
286  if (str.empty())
287    return PP_MakeUndefined();
288  return StringVar::StringToPPVar(str);
289}
290
291PP_Bool ReplacePort(const struct PP_NetAddress_Private* src_addr,
292                    uint16_t port,
293                    struct PP_NetAddress_Private* dest_addr) {
294  const NetAddress* src_net_addr = ToNetAddress(src_addr);
295  if (!IsValid(src_net_addr) || !dest_addr)
296    return PP_FALSE;
297  dest_addr->size = sizeof(NetAddress);  // make sure 'size' is valid.
298  NetAddress* dest_net_addr = ToNetAddress(dest_addr);
299  *dest_net_addr = *src_net_addr;
300  dest_net_addr->port = port;
301  return PP_TRUE;
302}
303
304void GetAnyAddress(PP_Bool is_ipv6, PP_NetAddress_Private* addr) {
305  if (addr) {
306    NetAddress* net_addr = InitNetAddress(addr);
307    net_addr->is_valid = true;
308    net_addr->is_ipv6 = (is_ipv6 == PP_TRUE);
309  }
310}
311
312void CreateFromIPv4Address(const uint8_t ip[4],
313                           uint16_t port,
314                           struct PP_NetAddress_Private* addr) {
315  if (addr) {
316    NetAddress* net_addr = InitNetAddress(addr);
317    net_addr->is_valid = true;
318    net_addr->is_ipv6 = false;
319    net_addr->port = port;
320    memcpy(net_addr->address, ip, kIPv4AddressSize);
321  }
322}
323
324void CreateFromIPv6Address(const uint8_t ip[16],
325                           uint32_t scope_id,
326                           uint16_t port,
327                           struct PP_NetAddress_Private* addr) {
328  if (addr) {
329    NetAddress* net_addr = InitNetAddress(addr);
330    net_addr->is_valid = true;
331    net_addr->is_ipv6 = true;
332    net_addr->port = port;
333    net_addr->scope_id = scope_id;
334    memcpy(net_addr->address, ip, kIPv6AddressSize);
335  }
336}
337
338const PPB_NetAddress_Private_0_1 net_address_private_interface_0_1 = {
339  &AreEqual,
340  &AreHostsEqual,
341  &Describe,
342  &ReplacePort,
343  &GetAnyAddress
344};
345
346const PPB_NetAddress_Private_1_0 net_address_private_interface_1_0 = {
347  &AreEqual,
348  &AreHostsEqual,
349  &Describe,
350  &ReplacePort,
351  &GetAnyAddress,
352  &GetFamily,
353  &GetPort,
354  &GetAddress
355};
356
357const PPB_NetAddress_Private_1_1 net_address_private_interface_1_1 = {
358  &AreEqual,
359  &AreHostsEqual,
360  &Describe,
361  &ReplacePort,
362  &GetAnyAddress,
363  &GetFamily,
364  &GetPort,
365  &GetAddress,
366  &GetScopeID,
367  &CreateFromIPv4Address,
368  &CreateFromIPv6Address
369};
370
371}  // namespace
372
373namespace thunk {
374
375PPAPI_THUNK_EXPORT const PPB_NetAddress_Private_0_1*
376GetPPB_NetAddress_Private_0_1_Thunk() {
377  return &net_address_private_interface_0_1;
378}
379
380PPAPI_THUNK_EXPORT const PPB_NetAddress_Private_1_0*
381GetPPB_NetAddress_Private_1_0_Thunk() {
382  return &net_address_private_interface_1_0;
383}
384
385PPAPI_THUNK_EXPORT const PPB_NetAddress_Private_1_1*
386GetPPB_NetAddress_Private_1_1_Thunk() {
387  return &net_address_private_interface_1_1;
388}
389
390}  // namespace thunk
391
392// For the NaCl target, all we need are the API functions and the thunk.
393#if !defined(OS_NACL)
394// static
395const PP_NetAddress_Private NetAddressPrivateImpl::kInvalidNetAddress = { 0 };
396
397// static
398bool NetAddressPrivateImpl::ValidateNetAddress(
399    const PP_NetAddress_Private& addr) {
400  return IsValid(ToNetAddress(&addr));
401}
402
403// static
404bool NetAddressPrivateImpl::SockaddrToNetAddress(
405    const sockaddr* sa,
406    uint32_t sa_length,
407    PP_NetAddress_Private* addr) {
408  if (!sa || sa_length == 0 || !addr)
409    return false;
410
411  // Our platform neutral format stores ports in host order, not net order,
412  // so convert them here.
413  NetAddress* net_addr = InitNetAddress(addr);
414  switch (sa->sa_family) {
415    case AF_INET: {
416      const struct sockaddr_in* addr4 =
417          reinterpret_cast<const struct sockaddr_in*>(sa);
418      net_addr->is_valid = true;
419      net_addr->is_ipv6 = false;
420      net_addr->port = ConvertNetEndian16(addr4->sin_port);
421      memcpy(net_addr->address, &addr4->sin_addr.s_addr, kIPv4AddressSize);
422      break;
423    }
424    case AF_INET6: {
425      const struct sockaddr_in6* addr6 =
426          reinterpret_cast<const struct sockaddr_in6*>(sa);
427      net_addr->is_valid = true;
428      net_addr->is_ipv6 = true;
429      net_addr->port = ConvertNetEndian16(addr6->sin6_port);
430      net_addr->flow_info = addr6->sin6_flowinfo;
431      net_addr->scope_id = addr6->sin6_scope_id;
432      memcpy(net_addr->address, addr6->sin6_addr.s6_addr, kIPv6AddressSize);
433      break;
434    }
435    default:
436      // InitNetAddress sets net_addr->is_valid to false.
437      return false;
438  }
439  return true;}
440
441// static
442bool NetAddressPrivateImpl::IPEndPointToNetAddress(
443    const std::vector<unsigned char>& address,
444    int port,
445    PP_NetAddress_Private* addr) {
446  if (!addr)
447    return false;
448
449  NetAddress* net_addr = InitNetAddress(addr);
450  switch (address.size()) {
451    case kIPv4AddressSize: {
452      net_addr->is_valid = true;
453      net_addr->is_ipv6 = false;
454      net_addr->port = static_cast<uint16_t>(port);
455      std::copy(address.begin(), address.end(), net_addr->address);
456      break;
457    }
458    case kIPv6AddressSize: {
459      net_addr->is_valid = true;
460      net_addr->is_ipv6 = true;
461      net_addr->port = static_cast<uint16_t>(port);
462      std::copy(address.begin(), address.end(), net_addr->address);
463      break;
464    }
465    default:
466      // InitNetAddress sets net_addr->is_valid to false.
467      return false;
468  }
469
470  return true;
471}
472
473// static
474bool NetAddressPrivateImpl::NetAddressToIPEndPoint(
475    const PP_NetAddress_Private& addr,
476    std::vector<unsigned char>* address,
477    int* port) {
478  if (!address || !port)
479    return false;
480
481  const NetAddress* net_addr = ToNetAddress(&addr);
482  if (!IsValid(net_addr))
483    return false;
484
485  *port = net_addr->port;
486  size_t address_size = GetAddressSize(net_addr);
487  address->assign(&net_addr->address[0], &net_addr->address[address_size]);
488
489  return true;
490}
491#endif  // !defined(OS_NACL)
492
493// static
494std::string NetAddressPrivateImpl::DescribeNetAddress(
495    const PP_NetAddress_Private& addr,
496    bool include_port) {
497  const NetAddress* net_addr = ToNetAddress(&addr);
498  if (!IsValid(net_addr))
499    return std::string();
500
501  // On Windows, |NetAddressToString()| doesn't work in the sandbox. On Mac,
502  // the output isn't consistent with RFC 5952, at least on Mac OS 10.6:
503  // |getnameinfo()| collapses length-one runs of zeros (and also doesn't
504  // display the scope).
505  if (net_addr->is_ipv6)
506    return ConvertIPv6AddressToString(net_addr, include_port);
507  return ConvertIPv4AddressToString(net_addr, include_port);
508}
509
510}  // namespace ppapi
511