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