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