Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/shared_impl/private/net_address_private_impl.h" | 5 #include "ppapi/shared_impl/private/net_address_private_impl.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
| 14 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 15 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
| 16 #include "net/base/sys_addrinfo.h" | 16 #include "net/base/sys_addrinfo.h" |
| 17 #include "net/base/sys_byteorder.h" | 17 #include "net/base/sys_byteorder.h" |
| 18 #include "ppapi/c/pp_var.h" | 18 #include "ppapi/c/pp_var.h" |
| 19 #include "ppapi/c/private/ppb_net_address_private.h" | 19 #include "ppapi/c/private/ppb_net_address_private.h" |
| 20 #include "ppapi/shared_impl/var.h" | 20 #include "ppapi/shared_impl/var.h" |
| 21 #include "ppapi/thunk/thunk.h" | 21 #include "ppapi/thunk/thunk.h" |
| 22 | 22 |
| 23 #if defined(OS_MACOSX) | |
| 24 // This is a bit evil, but it's standard operating procedure for |s6_addr|.... | |
| 25 #define s6_addr16 __u6_addr.__u6_addr16 | |
| 26 #endif | |
| 27 | |
| 28 #if defined(OS_WIN) | |
| 29 // The type of |sockaddr::sa_family|. | |
| 30 typedef ADDRESS_FAMILY sa_family_t; | |
| 31 | |
| 32 #define s6_addr16 u.Word | |
| 33 #endif | |
| 34 | |
| 23 // The net address interface doesn't have a normal C -> C++ thunk since it | 35 // The net address interface doesn't have a normal C -> C++ thunk since it |
| 24 // doesn't actually have any proxy wrapping or associated objects; it's just a | 36 // doesn't actually have any proxy wrapping or associated objects; it's just a |
| 25 // call into base. So we implement the entire interface here, using the thunk | 37 // call into base. So we implement the entire interface here, using the thunk |
| 26 // namespace so it magically gets hooked up in the proper places. | 38 // namespace so it magically gets hooked up in the proper places. |
| 27 | 39 |
| 28 namespace ppapi { | 40 namespace ppapi { |
| 29 | 41 |
| 30 namespace { | 42 namespace { |
| 31 | 43 |
| 32 #if defined(OS_WIN) | |
| 33 // The type of |sockaddr::sa_family|. | |
| 34 typedef ADDRESS_FAMILY sa_family_t; | |
| 35 #endif | |
| 36 | |
| 37 inline sa_family_t GetFamily(const PP_NetAddress_Private& addr) { | 44 inline sa_family_t GetFamily(const PP_NetAddress_Private& addr) { |
| 38 return reinterpret_cast<const sockaddr*>(addr.data)->sa_family; | 45 return reinterpret_cast<const sockaddr*>(addr.data)->sa_family; |
| 39 } | 46 } |
| 40 | 47 |
| 41 PP_Bool AreHostsEqual(const PP_NetAddress_Private* addr1, | 48 PP_Bool AreHostsEqual(const PP_NetAddress_Private* addr1, |
| 42 const PP_NetAddress_Private* addr2) { | 49 const PP_NetAddress_Private* addr2) { |
| 43 if (!NetAddressPrivateImpl::ValidateNetAddress(*addr1) || | 50 if (!NetAddressPrivateImpl::ValidateNetAddress(*addr1) || |
| 44 !NetAddressPrivateImpl::ValidateNetAddress(*addr2)) | 51 !NetAddressPrivateImpl::ValidateNetAddress(*addr2)) |
| 45 return PP_FALSE; | 52 return PP_FALSE; |
| 46 | 53 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 | 88 |
| 82 if (GetFamily(*addr1) == AF_INET6) { | 89 if (GetFamily(*addr1) == AF_INET6) { |
| 83 const sockaddr_in6* a1 = reinterpret_cast<const sockaddr_in6*>(addr1->data); | 90 const sockaddr_in6* a1 = reinterpret_cast<const sockaddr_in6*>(addr1->data); |
| 84 const sockaddr_in6* a2 = reinterpret_cast<const sockaddr_in6*>(addr2->data); | 91 const sockaddr_in6* a2 = reinterpret_cast<const sockaddr_in6*>(addr2->data); |
| 85 return PP_FromBool(a1->sin6_port == a2->sin6_port); | 92 return PP_FromBool(a1->sin6_port == a2->sin6_port); |
| 86 } | 93 } |
| 87 | 94 |
| 88 return PP_FALSE; | 95 return PP_FALSE; |
| 89 } | 96 } |
| 90 | 97 |
| 98 #if defined(OS_WIN) || defined(OS_MACOSX) | |
| 99 std::string ConvertIPv4AddressToString(const sockaddr_in* a, | |
| 100 bool include_port) { | |
| 101 unsigned ip = ntohl(a->sin_addr.s_addr); | |
| 102 unsigned port = ntohs(a->sin_port); | |
| 103 std::string description = base::StringPrintf( | |
| 104 "%u.%u.%u.%u", | |
| 105 (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); | |
| 106 if (include_port) | |
| 107 base::StringAppendF(&description, ":%u", port); | |
| 108 return description; | |
| 109 } | |
| 110 | |
| 111 // Format an IPv6 address for human consumption, basically according to RFC | |
| 112 // 5952. | |
| 113 // - If the scope is nonzero, it is appended to the address as "%<scope>" (this | |
| 114 // is not in RFC 5952, but consistent with |getnameinfo()| on Linux and | |
| 115 // Windows). | |
| 116 // - If |include_port| is true, the address (possibly including the scope) is | |
| 117 // enclosed in square brackets and ":<port>" is appended, i.e., the overall | |
| 118 // format is "[<address>]:<port>". | |
| 119 // - If the address is an IPv4 address embedded IPv6 (per RFC 4291), then the | |
| 120 // mixed format is used, e.g., "::ffff:192.168.1.2". This is optional per RFC | |
| 121 // 5952, but consistent with |getnameinfo()|. | |
| 122 std::string ConvertIPv6AddressToString(const sockaddr_in6* a, | |
| 123 bool include_port) { | |
| 124 unsigned port = ntohs(a->sin6_port); | |
| 125 unsigned scope = a->sin6_scope_id; | |
| 126 std::string description(include_port ? "[" : ""); | |
| 127 | |
| 128 // IPv4 address embedded in IPv6. | |
| 129 if (a->sin6_addr.s6_addr16[0] == 0 && a->sin6_addr.s6_addr16[1] == 0 && | |
| 130 a->sin6_addr.s6_addr16[2] == 0 && a->sin6_addr.s6_addr16[3] == 0 && | |
| 131 a->sin6_addr.s6_addr16[4] == 0 && | |
| 132 (a->sin6_addr.s6_addr16[5] == 0 || a->sin6_addr.s6_addr16[5] == 0xffff)) { | |
| 133 base::StringAppendF( | |
| 134 &description, | |
| 135 a->sin6_addr.s6_addr16[5] == 0 ? "::%u.%u.%u.%u" : "::ffff:%u.%u.%u.%u", | |
| 136 static_cast<unsigned>(a->sin6_addr.s6_addr[12]), | |
| 137 static_cast<unsigned>(a->sin6_addr.s6_addr[13]), | |
| 138 static_cast<unsigned>(a->sin6_addr.s6_addr[14]), | |
| 139 static_cast<unsigned>(a->sin6_addr.s6_addr[15])); | |
| 140 | |
| 141 // "Real" IPv6 addresses. | |
| 142 } else { | |
| 143 // Find the first longest run of 0s (of length > 1), to collapse to "::". | |
| 144 int longest_start = 0; | |
| 145 int longest_length = 0; | |
| 146 int curr_start = 0; | |
| 147 int curr_length = 0; | |
| 148 for (int i = 0; i < 8; i++) { | |
| 149 if (ntohs(a->sin6_addr.s6_addr16[i]) != 0) { | |
| 150 curr_length = 0; | |
| 151 continue; | |
|
dmichael (off chromium)
2011/11/21 21:20:46
optional nit: I think the algorithm here would be
viettrungluu
2011/11/21 21:33:48
Done.
| |
| 152 } | |
| 153 if (!curr_length) | |
| 154 curr_start = i; | |
| 155 curr_length++; | |
| 156 if (curr_length > longest_length) { | |
| 157 longest_start = curr_start; | |
| 158 longest_length = curr_length; | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 bool need_sep = false; // Whether the next item needs a ':' to separate. | |
| 163 for (int i = 0; i < 8;) { | |
| 164 if (longest_length > 1 && i == longest_start) { | |
| 165 description.append("::"); | |
| 166 need_sep = false; | |
| 167 i += longest_length; | |
| 168 } else { | |
| 169 unsigned v = ntohs(a->sin6_addr.s6_addr16[i]); | |
| 170 base::StringAppendF(&description, need_sep ? ":%x" : "%x", v); | |
| 171 need_sep = true; | |
| 172 i++; | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 // Nonzero scopes, e.g., 123, are indicated by appending, e.g., "%123". | |
| 178 if (scope != 0) | |
| 179 base::StringAppendF(&description, "%%%u", scope); | |
| 180 | |
| 181 if (include_port) | |
| 182 base::StringAppendF(&description, "]:%u", port); | |
| 183 | |
| 184 return description; | |
| 185 } | |
| 186 #endif // OS_WIN || OS_MAC | |
| 187 | |
| 91 PP_Var Describe(PP_Module module, | 188 PP_Var Describe(PP_Module module, |
| 92 const struct PP_NetAddress_Private* addr, | 189 const struct PP_NetAddress_Private* addr, |
| 93 PP_Bool include_port) { | 190 PP_Bool include_port) { |
| 94 if (!NetAddressPrivateImpl::ValidateNetAddress(*addr)) | 191 if (!NetAddressPrivateImpl::ValidateNetAddress(*addr)) |
| 95 return PP_MakeUndefined(); | 192 return PP_MakeUndefined(); |
| 96 | 193 |
| 97 #if defined(OS_WIN) | 194 #if defined(OS_WIN) || defined(OS_MACOSX) |
| 98 // On Windows, |NetAddressToString()| doesn't work in the sandbox. | 195 // On Windows, |NetAddressToString()| doesn't work in the sandbox. On Mac, |
| 99 // TODO(viettrungluu): Consider switching to this everywhere once it's fully | 196 // the output isn't consistent with RFC 5952, at least on Mac OS 10.6: |
| 100 // implemented. | 197 // |getnameinfo()| collapses length-one runs of zeros (and also doesn't |
| 198 // display the scope). | |
| 199 // TODO(viettrungluu): Consider switching to this on Linux. | |
| 101 switch (GetFamily(*addr)) { | 200 switch (GetFamily(*addr)) { |
| 102 case AF_INET: { | 201 case AF_INET: { |
| 103 const sockaddr_in* a = reinterpret_cast<const sockaddr_in*>(addr->data); | 202 const sockaddr_in* a = reinterpret_cast<const sockaddr_in*>(addr->data); |
| 104 unsigned ip = ntohl(a->sin_addr.s_addr); | 203 return StringVar::StringToPPVar( |
| 105 unsigned port = ntohs(a->sin_port); | 204 module, ConvertIPv4AddressToString(a, !!include_port)); |
| 106 std::string description = base::StringPrintf( | |
| 107 "%u.%u.%u.%u", | |
| 108 (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); | |
| 109 if (include_port) | |
| 110 description.append(base::StringPrintf(":%u", port)); | |
| 111 return StringVar::StringToPPVar(module, description); | |
| 112 } | 205 } |
| 113 case AF_INET6: | 206 case AF_INET6: { |
| 114 // TODO(viettrungluu): crbug.com/103969 | 207 const sockaddr_in6* a = reinterpret_cast<const sockaddr_in6*>(addr->data); |
| 115 NOTIMPLEMENTED(); | 208 return StringVar::StringToPPVar( |
| 116 break; | 209 module, ConvertIPv6AddressToString(a, !!include_port)); |
| 210 } | |
| 117 default: | 211 default: |
| 118 NOTREACHED(); | 212 NOTREACHED(); |
| 119 break; | 213 break; |
| 120 } | 214 } |
| 121 return PP_MakeUndefined(); | 215 return PP_MakeUndefined(); |
| 122 #else | 216 #else |
| 123 const sockaddr* a = reinterpret_cast<const sockaddr*>(addr->data); | 217 const sockaddr* a = reinterpret_cast<const sockaddr*>(addr->data); |
| 124 socklen_t l = addr->size; | 218 socklen_t l = addr->size; |
| 125 std::string description = | 219 std::string description = |
| 126 include_port ? net::NetAddressToStringWithPort(a, l) : | 220 include_port ? net::NetAddressToStringWithPort(a, l) : |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 | 291 |
| 198 // Ditto for AF_INET6. | 292 // Ditto for AF_INET6. |
| 199 if (GetFamily(addr) == AF_INET6 && addr.size >= sizeof(sockaddr_in6)) | 293 if (GetFamily(addr) == AF_INET6 && addr.size >= sizeof(sockaddr_in6)) |
| 200 return true; | 294 return true; |
| 201 | 295 |
| 202 // Reject everything else. | 296 // Reject everything else. |
| 203 return false; | 297 return false; |
| 204 } | 298 } |
| 205 | 299 |
| 206 } // namespace ppapi | 300 } // namespace ppapi |
| OLD | NEW |