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