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