Chromium Code Reviews| Index: ppapi/shared_impl/private/flash_net_address_impl.cc |
| diff --git a/ppapi/shared_impl/private/flash_net_address_impl.cc b/ppapi/shared_impl/private/flash_net_address_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0fd0d0fb9e4b6db9b6924d9610d81f384168f699 |
| --- /dev/null |
| +++ b/ppapi/shared_impl/private/flash_net_address_impl.cc |
| @@ -0,0 +1,175 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ppapi/shared_impl/private/flash_net_address_impl.h" |
| + |
| +#include <string.h> |
| + |
| +#include <string> |
| + |
| +#include "base/basictypes.h" |
| +#include "build/build_config.h" |
| +#include "net/base/net_util.h" |
| +#include "net/base/sys_addrinfo.h" |
| +#include "net/base/sys_byteorder.h" |
| +#include "ppapi/c/pp_var.h" |
| +#include "ppapi/c/private/ppb_flash_net_address.h" |
| +#include "ppapi/shared_impl/var.h" |
| +#include "ppapi/thunk/thunk.h" |
| + |
| +// The Flash net address interface doesn't have a normal C -> C++ thunk since it |
| +// doesn't actually have any proxy wrapping or associated objects; it's just a |
| +// call into base. So we implement the entire interface here, using the thunk |
| +// namespace so it magically gets hooked up in the proper places. |
| + |
| +namespace ppapi { |
| + |
| +namespace { |
| + |
| +#if defined(OS_WIN) |
| +// The type of |sockaddr::sa_family|. |
| +typedef ADDRESS_FAMILY sa_family_t; |
| +#endif |
| + |
| +inline sa_family_t GetFamily(const PP_Flash_NetAddress& addr) { |
| + return reinterpret_cast<const sockaddr*>(addr.data)->sa_family; |
| +} |
| + |
| +PP_Bool AreHostsEqual(const PP_Flash_NetAddress* addr1, |
| + const PP_Flash_NetAddress* addr2) { |
| + if (!FlashNetAddressImpl::ValidateNetAddress(*addr1) || |
| + !FlashNetAddressImpl::ValidateNetAddress(*addr2)) |
| + return PP_FALSE; |
| + |
| + if (GetFamily(*addr1) != GetFamily(*addr2)) |
| + return PP_FALSE; |
| + |
| + if (GetFamily(*addr1) == AF_INET) { |
| + const sockaddr_in* a1 = reinterpret_cast<const sockaddr_in*>(addr1->data); |
| + const sockaddr_in* a2 = reinterpret_cast<const sockaddr_in*>(addr2->data); |
| + return PP_FromBool(a1->sin_addr.s_addr == a2->sin_addr.s_addr); |
| + } |
| + |
| + if (GetFamily(*addr1) == AF_INET6) { |
| + const sockaddr_in6* a1 = reinterpret_cast<const sockaddr_in6*>(addr1->data); |
| + const sockaddr_in6* a2 = reinterpret_cast<const sockaddr_in6*>(addr2->data); |
| + return PP_FromBool(a1->sin6_flowinfo == a2->sin6_flowinfo && |
| + memcmp(&a1->sin6_addr, &a2->sin6_addr, |
| + sizeof(a1->sin6_addr)) == 0 && |
| + a1->sin6_scope_id == a2->sin6_scope_id); |
| + } |
| + |
| + return PP_FALSE; |
| +} |
| + |
| +PP_Bool AreEqual(const PP_Flash_NetAddress* addr1, |
| + const PP_Flash_NetAddress* addr2) { |
| + // |AreHostsEqual()| will also validate the addresses and return false if |
| + // either is invalid. |
| + if (!AreHostsEqual(addr1, addr2)) |
| + return PP_FALSE; |
| + |
| + // Note: Here, we know that |addr1| and |addr2| have the same family. |
| + if (GetFamily(*addr1) == AF_INET) { |
| + const sockaddr_in* a1 = reinterpret_cast<const sockaddr_in*>(addr1->data); |
| + const sockaddr_in* a2 = reinterpret_cast<const sockaddr_in*>(addr2->data); |
| + return PP_FromBool(a1->sin_port == a2->sin_port); |
| + } |
| + |
| + if (GetFamily(*addr1) == AF_INET6) { |
| + const sockaddr_in6* a1 = reinterpret_cast<const sockaddr_in6*>(addr1->data); |
| + const sockaddr_in6* a2 = reinterpret_cast<const sockaddr_in6*>(addr2->data); |
| + return PP_FromBool(a1->sin6_port == a2->sin6_port); |
| + } |
| + |
| + return PP_FALSE; |
| +} |
| + |
| +PP_Var Describe(PP_Module module, |
| + const struct PP_Flash_NetAddress* addr, |
| + PP_Bool include_port) { |
| + if (!FlashNetAddressImpl::ValidateNetAddress(*addr)) |
| + return PP_MakeUndefined(); |
| + |
| + const sockaddr* a = reinterpret_cast<const sockaddr*>(addr->data); |
| + socklen_t l = addr->size; |
| + std::string description = |
| + include_port ? net::NetAddressToStringWithPort(a, l) : |
| + net::NetAddressToString(a, l); |
| + return StringVar::StringToPPVar(module, description); |
| +} |
| + |
| +PP_Bool ReplacePort(const struct PP_Flash_NetAddress* src_addr, |
| + uint16_t port, |
| + struct PP_Flash_NetAddress* dest_addr) { |
| + if (!FlashNetAddressImpl::ValidateNetAddress(*src_addr)) |
| + return PP_FALSE; |
| + |
| + if (GetFamily(*src_addr) == AF_INET) { |
| + memmove(dest_addr, src_addr, sizeof(*src_addr)); |
| + reinterpret_cast<sockaddr_in*>(dest_addr->data)->sin_port = htons(port); |
| + return PP_TRUE; |
| + } |
| + |
| + if (GetFamily(*src_addr) == AF_INET6) { |
| + memmove(dest_addr, src_addr, sizeof(*src_addr)); |
| + reinterpret_cast<sockaddr_in6*>(dest_addr->data)->sin6_port = htons(port); |
| + return PP_TRUE; |
| + } |
| + |
| + return PP_FALSE; |
| +} |
| + |
| +void GetAnyAddress(PP_Bool is_ipv6, struct PP_Flash_NetAddress* addr) { |
| + memset(addr->data, 0, arraysize(addr->data) * sizeof(addr->data[0])); |
| + if (is_ipv6) { |
| + sockaddr_in6* a = reinterpret_cast<sockaddr_in6*>(addr->data); |
| + addr->size = sizeof(*a); |
| + a->sin6_family = AF_INET6; |
| + a->sin6_addr = in6addr_any; |
| + } else { |
| + sockaddr_in* a = reinterpret_cast<sockaddr_in*>(addr->data); |
| + addr->size = sizeof(*a); |
| + a->sin_family = AF_INET; |
| + a->sin_addr.s_addr = INADDR_ANY; |
| + } |
| +} |
| + |
| +const PPB_Flash_NetAddress flash_net_address_interface = { |
| + &AreEqual, |
| + &AreHostsEqual, |
| + &Describe, |
| + &ReplacePort, |
| + &GetAnyAddress |
| +}; |
| + |
| +} // namespace |
| + |
| +namespace thunk { |
| + |
| +PPAPI_THUNK_EXPORT const PPB_Flash_NetAddress* GetPPB_Flash_NetAddress_Thunk() { |
|
yzshen1
2011/11/07 23:58:36
I personally think that it may be better to have t
viettrungluu
2011/11/08 00:12:43
There's no real thunking involved; see the comment
|
| + return &flash_net_address_interface; |
| +} |
| + |
| +} // namespace thunk |
| + |
| +// static |
| +bool FlashNetAddressImpl::ValidateNetAddress(const PP_Flash_NetAddress& addr) { |
| + if (addr.size < sizeof(reinterpret_cast<sockaddr*>(0)->sa_family)) |
| + return false; |
| + |
| + // TODO(viettrungluu): more careful validation? |
| + // Just do a size check for AF_INET. |
| + if (GetFamily(addr) == AF_INET && addr.size >= sizeof(sockaddr_in)) |
| + return true; |
| + |
| + // Ditto for AF_INET6. |
| + if (GetFamily(addr) == AF_INET6 && addr.size >= sizeof(sockaddr_in6)) |
| + return true; |
| + |
| + // Reject everything else. |
| + return false; |
| +} |
| + |
| +} // namespace ppapi |