mirror of https://github.com/grpc/grpc.git
parent
8327acd9a2
commit
690dde672a
30 changed files with 8518 additions and 156 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,627 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/host_port.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/string_util.h> |
||||||
|
#include <grpc/support/sync.h> |
||||||
|
#include <grpc/support/time.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <arpa/inet.h> |
||||||
|
#include <gflags/gflags.h> |
||||||
|
#include <gmock/gmock.h> |
||||||
|
#include <sys/socket.h> |
||||||
|
#include <sys/types.h> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include <address_sorting.h> |
||||||
|
#include "test/cpp/util/subprocess.h" |
||||||
|
#include "test/cpp/util/test_config.h" |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/client_channel.h" |
||||||
|
#include "src/core/ext/filters/client_channel/resolver.h" |
||||||
|
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" |
||||||
|
#include "src/core/ext/filters/client_channel/resolver_registry.h" |
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
#include "src/core/lib/iomgr/combiner.h" |
||||||
|
#include "src/core/lib/iomgr/executor.h" |
||||||
|
#include "src/core/lib/iomgr/iomgr.h" |
||||||
|
#include "src/core/lib/iomgr/resolve_address.h" |
||||||
|
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||||
|
#include "src/core/lib/support/env.h" |
||||||
|
#include "src/core/lib/support/string.h" |
||||||
|
#include "test/core/util/port.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
struct TestAddress { |
||||||
|
std::string dest_addr; |
||||||
|
int family; |
||||||
|
}; |
||||||
|
|
||||||
|
grpc_resolved_address TestAddressToGrpcResolvedAddress(TestAddress test_addr) { |
||||||
|
char* host; |
||||||
|
char* port; |
||||||
|
grpc_resolved_address resolved_addr; |
||||||
|
gpr_split_host_port(test_addr.dest_addr.c_str(), &host, &port); |
||||||
|
if (test_addr.family == AF_INET) { |
||||||
|
sockaddr_in in_dest; |
||||||
|
memset(&in_dest, 0, sizeof(sockaddr_in)); |
||||||
|
in_dest.sin_port = htons(atoi(port)); |
||||||
|
in_dest.sin_family = AF_INET; |
||||||
|
GPR_ASSERT(inet_pton(AF_INET, host, &in_dest.sin_addr) == 1); |
||||||
|
memcpy(&resolved_addr.addr, &in_dest, sizeof(sockaddr_in)); |
||||||
|
resolved_addr.len = sizeof(sockaddr_in); |
||||||
|
} else { |
||||||
|
GPR_ASSERT(test_addr.family == AF_INET6); |
||||||
|
sockaddr_in6 in6_dest; |
||||||
|
memset(&in6_dest, 0, sizeof(sockaddr_in6)); |
||||||
|
in6_dest.sin6_port = htons(atoi(port)); |
||||||
|
in6_dest.sin6_family = AF_INET6; |
||||||
|
GPR_ASSERT(inet_pton(AF_INET6, host, &in6_dest.sin6_addr) == 1); |
||||||
|
memcpy(&resolved_addr.addr, &in6_dest, sizeof(sockaddr_in6)); |
||||||
|
resolved_addr.len = sizeof(sockaddr_in6); |
||||||
|
} |
||||||
|
gpr_free(host); |
||||||
|
gpr_free(port); |
||||||
|
return resolved_addr; |
||||||
|
} |
||||||
|
|
||||||
|
class MockSourceAddrFactory : public address_sorting_source_addr_factory { |
||||||
|
public: |
||||||
|
MockSourceAddrFactory( |
||||||
|
bool ipv4_supported, bool ipv6_supported, |
||||||
|
const std::map<std::string, TestAddress>& dest_addr_to_src_addr) |
||||||
|
: ipv4_supported_(ipv4_supported), |
||||||
|
ipv6_supported_(ipv6_supported), |
||||||
|
dest_addr_to_src_addr_(dest_addr_to_src_addr) {} |
||||||
|
|
||||||
|
bool GetSourceAddr(const address_sorting_address* dest_addr, |
||||||
|
address_sorting_address* source_addr) { |
||||||
|
if ((address_sorting_abstract_get_family(dest_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET && |
||||||
|
!ipv4_supported_) || |
||||||
|
(address_sorting_abstract_get_family(dest_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET6 && |
||||||
|
!ipv6_supported_)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
char* ip_addr_str; |
||||||
|
grpc_resolved_address dest_addr_as_resolved_addr; |
||||||
|
memcpy(&dest_addr_as_resolved_addr.addr, dest_addr, dest_addr->len); |
||||||
|
dest_addr_as_resolved_addr.len = dest_addr->len; |
||||||
|
grpc_sockaddr_to_string(&ip_addr_str, &dest_addr_as_resolved_addr, |
||||||
|
false /* normalize */); |
||||||
|
auto it = dest_addr_to_src_addr_.find(ip_addr_str); |
||||||
|
if (it == dest_addr_to_src_addr_.end()) { |
||||||
|
gpr_log(GPR_DEBUG, "can't find |%s| in dest to src map", ip_addr_str); |
||||||
|
gpr_free(ip_addr_str); |
||||||
|
return false; |
||||||
|
} |
||||||
|
gpr_free(ip_addr_str); |
||||||
|
grpc_resolved_address source_addr_as_resolved_addr = |
||||||
|
TestAddressToGrpcResolvedAddress(it->second); |
||||||
|
memcpy(source_addr->addr, &source_addr_as_resolved_addr.addr, |
||||||
|
source_addr_as_resolved_addr.len); |
||||||
|
source_addr->len = source_addr_as_resolved_addr.len; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
// user provided test config
|
||||||
|
bool ipv4_supported_; |
||||||
|
bool ipv6_supported_; |
||||||
|
std::map<std::string, TestAddress> dest_addr_to_src_addr_; |
||||||
|
}; |
||||||
|
|
||||||
|
static bool mock_source_addr_factory_wrapper_get_source_addr( |
||||||
|
address_sorting_source_addr_factory* factory, |
||||||
|
const address_sorting_address* dest_addr, |
||||||
|
address_sorting_address* source_addr) { |
||||||
|
MockSourceAddrFactory* mock = |
||||||
|
reinterpret_cast<MockSourceAddrFactory*>(factory); |
||||||
|
return mock->GetSourceAddr(dest_addr, source_addr); |
||||||
|
} |
||||||
|
|
||||||
|
void mock_source_addr_factory_wrapper_destroy( |
||||||
|
address_sorting_source_addr_factory* factory) { |
||||||
|
MockSourceAddrFactory* mock = |
||||||
|
reinterpret_cast<MockSourceAddrFactory*>(factory); |
||||||
|
delete mock; |
||||||
|
} |
||||||
|
|
||||||
|
const address_sorting_source_addr_factory_vtable kMockSourceAddrFactoryVtable = |
||||||
|
{ |
||||||
|
mock_source_addr_factory_wrapper_get_source_addr, |
||||||
|
mock_source_addr_factory_wrapper_destroy, |
||||||
|
}; |
||||||
|
|
||||||
|
void OverrideAddressSortingSourceAddrFactory( |
||||||
|
bool ipv4_supported, bool ipv6_supported, |
||||||
|
const std::map<std::string, TestAddress>& dest_addr_to_src_addr) { |
||||||
|
address_sorting_source_addr_factory* factory = new MockSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, dest_addr_to_src_addr); |
||||||
|
factory->vtable = &kMockSourceAddrFactoryVtable; |
||||||
|
address_sorting_override_source_addr_factory_for_testing(factory); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_lb_addresses* BuildLbAddrInputs(std::vector<TestAddress> test_addrs) { |
||||||
|
grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, NULL); |
||||||
|
lb_addrs->addresses = |
||||||
|
(grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size()); |
||||||
|
lb_addrs->num_addresses = test_addrs.size(); |
||||||
|
for (size_t i = 0; i < test_addrs.size(); i++) { |
||||||
|
lb_addrs->addresses[i].address = |
||||||
|
TestAddressToGrpcResolvedAddress(test_addrs[i]); |
||||||
|
} |
||||||
|
return lb_addrs; |
||||||
|
} |
||||||
|
|
||||||
|
void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, |
||||||
|
std::vector<std::string> expected_addrs) { |
||||||
|
EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size()); |
||||||
|
for (size_t i = 0; i < lb_addrs->num_addresses; i++) { |
||||||
|
char* ip_addr_str; |
||||||
|
grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address, |
||||||
|
false /* normalize */); |
||||||
|
EXPECT_EQ(expected_addrs[i], ip_addr_str); |
||||||
|
gpr_free(ip_addr_str); |
||||||
|
} |
||||||
|
grpc_core::ExecCtx exec_ctx; |
||||||
|
grpc_lb_addresses_destroy(lb_addrs); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
/* Tests for rule 1 */ |
||||||
|
TEST(AddressSortingTest, TestDepriotizesUnreachableAddresses) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"1.2.3.4:443", {"4.3.2.1:443", AF_INET}}, |
||||||
|
}); |
||||||
|
auto* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"1.2.3.4:443", AF_INET}, |
||||||
|
{"5.6.7.8:443", AF_INET}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"1.2.3.4:443", |
||||||
|
"5.6.7.8:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = false; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, |
||||||
|
}); |
||||||
|
auto lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[2607:f8b0:400a:801::1002]:443", AF_INET6}, |
||||||
|
{"1.2.3.4:443", AF_INET}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"1.2.3.4:443", |
||||||
|
"[2607:f8b0:400a:801::1002]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { |
||||||
|
bool ipv4_supported = false; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, |
||||||
|
{"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[2607:f8b0:400a:801::1002]:443", AF_INET6}, |
||||||
|
{"1.2.3.4:443", AF_INET}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[2607:f8b0:400a:801::1002]:443", |
||||||
|
"1.2.3.4:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* Tests for rule 2 */ |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestDepriotizesNonMatchingScope) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[2000:f8b0:400a:801::1002]:443", |
||||||
|
{"[fec0::1000]:0", AF_INET6}}, // global and site-local scope
|
||||||
|
{"[fec0::5000]:443", |
||||||
|
{"[fec0::5001]:0", AF_INET6}}, // site-local and site-local scope
|
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[2000:f8b0:400a:801::1002]:443", AF_INET6}, |
||||||
|
{"[fec0::5000]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[fec0::5000]:443", |
||||||
|
"[2000:f8b0:400a:801::1002]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* Tests for rule 5 */ |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestUsesLabelFromDefaultTable) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[2002::5001]:443", {"[2001::5002]:0", AF_INET6}}, |
||||||
|
{"[2001::5001]:443", |
||||||
|
{"[2001::5002]:0", AF_INET6}}, // matching labels
|
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[2002::5001]:443", AF_INET6}, |
||||||
|
{"[2001::5001]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[2001::5001]:443", |
||||||
|
"[2002::5001]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* Tests for rule 6 */ |
||||||
|
|
||||||
|
TEST(AddressSortingTest, |
||||||
|
TestUsesDestinationWithHigherPrecedenceWithAnIpv4Address) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, |
||||||
|
{"1.2.3.4:443", {"5.6.7.8:0", AF_INET}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe::5001]:443", AF_INET6}, |
||||||
|
{"1.2.3.4:443", AF_INET}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs( |
||||||
|
lb_addrs, { |
||||||
|
// The AF_INET address should be IPv4-mapped by the sort,
|
||||||
|
// and IPv4-mapped
|
||||||
|
// addresses have higher precedence than 3ffe::/16 by spec.
|
||||||
|
"1.2.3.4:443", |
||||||
|
"[3ffe::5001]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, |
||||||
|
TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddress) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}}, |
||||||
|
{"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[2001::1234]:443", AF_INET6}, |
||||||
|
{"[2000::5001]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs( |
||||||
|
lb_addrs, { |
||||||
|
// The 2000::/16 address should match the ::/0 prefix rule
|
||||||
|
"[2000::5001]:443", |
||||||
|
"[2001::1234]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST( |
||||||
|
AddressSortingTest, |
||||||
|
TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddressEnsurePrefixMatchHasNoEffect) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}}, |
||||||
|
{"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[2001::1231]:443", AF_INET6}, |
||||||
|
{"[2000::5001]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[2000::5001]:443", |
||||||
|
"[2001::1231]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, |
||||||
|
TestUsesDestinationWithHigherPrecedenceWithLinkAndSiteLocalAddresses) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, |
||||||
|
{"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[fec0::1234]:443", AF_INET6}, |
||||||
|
{"[fc00::5001]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[fc00::5001]:443", |
||||||
|
"[fec0::1234]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* Tests for rule 8 */ |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestPrefersSmallerScope) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
// Both of these destinations have the same precedence in default
|
||||||
|
// policy
|
||||||
|
// table.
|
||||||
|
{"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, |
||||||
|
{"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe::5001]:443", AF_INET6}, |
||||||
|
{"[fec0::1234]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[fec0::1234]:443", |
||||||
|
"[3ffe::5001]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* Tests for rule 9 */ |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
// Both of these destinations have the same precedence in default
|
||||||
|
// policy
|
||||||
|
// table.
|
||||||
|
{"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}}, |
||||||
|
{"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe:5001::]:443", AF_INET6}, |
||||||
|
{"[3ffe:1234::]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe:1234::]:443", |
||||||
|
"[3ffe:5001::]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, |
||||||
|
TestPrefersLongestMatchingSrcDstPrefixMatchesWholeAddress) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}}, |
||||||
|
{"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe::5001]:443", AF_INET6}, |
||||||
|
{"[3ffe::1234]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe::1234]:443", |
||||||
|
"[3ffe::5001]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}}, |
||||||
|
{"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe:8000::]:443", AF_INET6}, |
||||||
|
{"[3ffe:2000::]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe:2000::]:443", |
||||||
|
"[3ffe:8000::]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}}, |
||||||
|
{"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe:6::]:443", AF_INET6}, |
||||||
|
{"[3ffe:c::]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe:c::]:443", |
||||||
|
"[3ffe:6::]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe:1111:1111:1111::]:443", |
||||||
|
{"[3ffe:1111:1111:1111::]:0", AF_INET6}}, |
||||||
|
{"[3ffe:1111:1111:1110::]:443", |
||||||
|
{"[3ffe:1111:1111:1111::]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe:1111:1111:1110::]:443", AF_INET6}, |
||||||
|
{"[3ffe:1111:1111:1111::]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe:1111:1111:1111::]:443", |
||||||
|
"[3ffe:1111:1111:1110::]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* Tests for rule 10 */ |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestStableSort) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}}, |
||||||
|
{"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe::1234]:443", AF_INET6}, |
||||||
|
{"[3ffe::1235]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe::1234]:443", |
||||||
|
"[3ffe::1235]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestStableSortFiveElements) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory( |
||||||
|
ipv4_supported, ipv6_supported, |
||||||
|
{ |
||||||
|
{"[3ffe::1231]:443", {"[3ffe::1201]:0", AF_INET6}}, |
||||||
|
{"[3ffe::1232]:443", {"[3ffe::1202]:0", AF_INET6}}, |
||||||
|
{"[3ffe::1233]:443", {"[3ffe::1203]:0", AF_INET6}}, |
||||||
|
{"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}}, |
||||||
|
{"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}}, |
||||||
|
}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe::1231]:443", AF_INET6}, |
||||||
|
{"[3ffe::1232]:443", AF_INET6}, |
||||||
|
{"[3ffe::1233]:443", AF_INET6}, |
||||||
|
{"[3ffe::1234]:443", AF_INET6}, |
||||||
|
{"[3ffe::1235]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe::1231]:443", |
||||||
|
"[3ffe::1232]:443", |
||||||
|
"[3ffe::1233]:443", |
||||||
|
"[3ffe::1234]:443", |
||||||
|
"[3ffe::1235]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestStableSortNoSrcAddrsExist) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[3ffe::1231]:443", AF_INET6}, |
||||||
|
{"[3ffe::1232]:443", AF_INET6}, |
||||||
|
{"[3ffe::1233]:443", AF_INET6}, |
||||||
|
{"[3ffe::1234]:443", AF_INET6}, |
||||||
|
{"[3ffe::1235]:443", AF_INET6}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[3ffe::1231]:443", |
||||||
|
"[3ffe::1232]:443", |
||||||
|
"[3ffe::1233]:443", |
||||||
|
"[3ffe::1234]:443", |
||||||
|
"[3ffe::1235]:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { |
||||||
|
bool ipv4_supported = true; |
||||||
|
bool ipv6_supported = true; |
||||||
|
OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); |
||||||
|
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||||
|
{"[::ffff:5.6.7.8]:443", AF_INET6}, |
||||||
|
{"1.2.3.4:443", AF_INET}, |
||||||
|
}); |
||||||
|
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||||
|
VerifyLbAddrOutputs(lb_addrs, { |
||||||
|
"[::ffff:5.6.7.8]:443", |
||||||
|
"1.2.3.4:443", |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
const char* resolver = gpr_getenv("GRPC_DNS_RESOLVER"); |
||||||
|
if (resolver == NULL || strlen(resolver) == 0) { |
||||||
|
gpr_setenv("GRPC_DNS_RESOLVER", "ares"); |
||||||
|
} else if (strcmp("ares", resolver)) { |
||||||
|
gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver); |
||||||
|
} |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
grpc_init(); |
||||||
|
auto result = RUN_ALL_TESTS(); |
||||||
|
grpc_shutdown(); |
||||||
|
return result; |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
# $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||||
|
# $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||||
|
# |
||||||
|
# Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions |
||||||
|
# are met: |
||||||
|
# 1. Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer in the |
||||||
|
# documentation and/or other materials provided with the distribution. |
||||||
|
# 3. Neither the name of the project nor the names of its contributors |
||||||
|
# may be used to endorse or promote products derived from this software |
||||||
|
# without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||||
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||||
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
# SUCH DAMAGE. |
||||||
|
|
||||||
|
package( |
||||||
|
default_visibility = ["//visibility:public"], |
||||||
|
features = [ |
||||||
|
"-layering_check", |
||||||
|
"-parse_headers", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
licenses(["notice"]) # BSD |
||||||
|
|
||||||
|
exports_files(["LICENSE"]) |
||||||
|
|
||||||
|
cc_library( |
||||||
|
name = "address_sorting", |
||||||
|
srcs = [ |
||||||
|
"address_sorting.c", |
||||||
|
"address_sorting_posix.c", |
||||||
|
"address_sorting_windows.c", |
||||||
|
], |
||||||
|
hdrs = [ |
||||||
|
"address_sorting.h", |
||||||
|
"address_sorting_internal.h", |
||||||
|
], |
||||||
|
includes = [ |
||||||
|
".", |
||||||
|
], |
||||||
|
) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,342 @@ |
|||||||
|
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||||
|
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* 3. Neither the name of the project nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
* SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an adaptation of Android's implementation of RFC 6724 |
||||||
|
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||||
|
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||||
|
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||||
|
* this was written. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "address_sorting_internal.h" |
||||||
|
|
||||||
|
#include <errno.h> |
||||||
|
#include <inttypes.h> |
||||||
|
#include <limits.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <sys/types.h> |
||||||
|
|
||||||
|
// Scope values increase with increase in scope.
|
||||||
|
static const int kIPv6AddrScopeLinkLocal = 1; |
||||||
|
static const int kIPv6AddrScopeSiteLocal = 2; |
||||||
|
static const int kIPv6AddrScopeGlobal = 3; |
||||||
|
|
||||||
|
static address_sorting_source_addr_factory* g_current_source_addr_factory = |
||||||
|
NULL; |
||||||
|
|
||||||
|
static int address_sorting_get_source_addr(const address_sorting_address* dest, |
||||||
|
address_sorting_address* source) { |
||||||
|
return g_current_source_addr_factory->vtable->get_source_addr( |
||||||
|
g_current_source_addr_factory, dest, source); |
||||||
|
} |
||||||
|
|
||||||
|
static int ipv6_prefix_match_length(const struct sockaddr_in6* sa, |
||||||
|
const struct sockaddr_in6* sb) { |
||||||
|
unsigned char* a = (unsigned char*)&sa->sin6_addr; |
||||||
|
unsigned char* b = (unsigned char*)&sb->sin6_addr; |
||||||
|
int cur_bit = 0; |
||||||
|
while (cur_bit < 128) { |
||||||
|
int high_bit = 1 << (CHAR_BIT - 1); |
||||||
|
int a_val = a[cur_bit / CHAR_BIT] & (high_bit >> (cur_bit % CHAR_BIT)); |
||||||
|
int b_val = b[cur_bit / CHAR_BIT] & (high_bit >> (cur_bit % CHAR_BIT)); |
||||||
|
if (a_val == b_val) { |
||||||
|
cur_bit++; |
||||||
|
} else { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return cur_bit; |
||||||
|
} |
||||||
|
|
||||||
|
static int in6_is_addr_6to4(const struct in6_addr* ipv6_address) { |
||||||
|
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||||
|
return bytes[0] == 0x20 && bytes[1] == 0x02; |
||||||
|
} |
||||||
|
|
||||||
|
static int in6_is_addr_ula(const struct in6_addr* ipv6_address) { |
||||||
|
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||||
|
return (bytes[0] & 0xfe) == 0xfc; |
||||||
|
} |
||||||
|
|
||||||
|
static int in6_is_addr_teredo(const struct in6_addr* ipv6_address) { |
||||||
|
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||||
|
return bytes[0] == 0x20 && bytes[1] == 0x01 && bytes[2] == 0x00 && |
||||||
|
bytes[3] == 0x00; |
||||||
|
} |
||||||
|
|
||||||
|
static int in6_is_addr_6bone(const struct in6_addr* ipv6_address) { |
||||||
|
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||||
|
return bytes[0] == 0x3f && bytes[1] == 0xfe; |
||||||
|
} |
||||||
|
|
||||||
|
address_sorting_family address_sorting_abstract_get_family( |
||||||
|
const address_sorting_address* address) { |
||||||
|
switch (((struct sockaddr*)address)->sa_family) { |
||||||
|
case AF_INET: |
||||||
|
return ADDRESS_SORTING_AF_INET; |
||||||
|
case AF_INET6: |
||||||
|
return ADDRESS_SORTING_AF_INET6; |
||||||
|
default: |
||||||
|
return ADDRESS_SORTING_UNKNOWN_FAMILY; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static int get_label_value(const address_sorting_address* resolved_addr) { |
||||||
|
if (address_sorting_abstract_get_family(resolved_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET) { |
||||||
|
return 4; |
||||||
|
} else if (address_sorting_abstract_get_family(resolved_addr) != |
||||||
|
ADDRESS_SORTING_AF_INET6) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr; |
||||||
|
if (IN6_IS_ADDR_LOOPBACK(&ipv6_addr->sin6_addr)) { |
||||||
|
return 0; |
||||||
|
} else if (IN6_IS_ADDR_V4MAPPED(&ipv6_addr->sin6_addr)) { |
||||||
|
return 4; |
||||||
|
} else if (in6_is_addr_6to4(&ipv6_addr->sin6_addr)) { |
||||||
|
return 2; |
||||||
|
} else if (in6_is_addr_teredo(&ipv6_addr->sin6_addr)) { |
||||||
|
return 5; |
||||||
|
} else if (in6_is_addr_ula(&ipv6_addr->sin6_addr)) { |
||||||
|
return 13; |
||||||
|
} else if (IN6_IS_ADDR_V4COMPAT(&ipv6_addr->sin6_addr)) { |
||||||
|
return 3; |
||||||
|
} else if (IN6_IS_ADDR_SITELOCAL(&ipv6_addr->sin6_addr)) { |
||||||
|
return 11; |
||||||
|
} else if (in6_is_addr_6bone(&ipv6_addr->sin6_addr)) { |
||||||
|
return 12; |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
static int get_precedence_value(const address_sorting_address* resolved_addr) { |
||||||
|
if (address_sorting_abstract_get_family(resolved_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET) { |
||||||
|
return 35; |
||||||
|
} else if (address_sorting_abstract_get_family(resolved_addr) != |
||||||
|
ADDRESS_SORTING_AF_INET6) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr; |
||||||
|
if (IN6_IS_ADDR_LOOPBACK(&ipv6_addr->sin6_addr)) { |
||||||
|
return 50; |
||||||
|
} else if (IN6_IS_ADDR_V4MAPPED(&ipv6_addr->sin6_addr)) { |
||||||
|
return 35; |
||||||
|
} else if (in6_is_addr_6to4(&ipv6_addr->sin6_addr)) { |
||||||
|
return 30; |
||||||
|
} else if (in6_is_addr_teredo(&ipv6_addr->sin6_addr)) { |
||||||
|
return 5; |
||||||
|
} else if (in6_is_addr_ula(&ipv6_addr->sin6_addr)) { |
||||||
|
return 3; |
||||||
|
} else if (IN6_IS_ADDR_V4COMPAT(&ipv6_addr->sin6_addr) || |
||||||
|
IN6_IS_ADDR_SITELOCAL(&ipv6_addr->sin6_addr) || |
||||||
|
in6_is_addr_6bone(&ipv6_addr->sin6_addr)) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return 40; |
||||||
|
} |
||||||
|
|
||||||
|
static int sockaddr_get_scope(const address_sorting_address* resolved_addr) { |
||||||
|
if (address_sorting_abstract_get_family(resolved_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET) { |
||||||
|
return kIPv6AddrScopeGlobal; |
||||||
|
} else if (address_sorting_abstract_get_family(resolved_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET6) { |
||||||
|
struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr; |
||||||
|
if (IN6_IS_ADDR_LOOPBACK(&ipv6_addr->sin6_addr) || |
||||||
|
IN6_IS_ADDR_LINKLOCAL(&ipv6_addr->sin6_addr)) { |
||||||
|
return kIPv6AddrScopeLinkLocal; |
||||||
|
} |
||||||
|
if (IN6_IS_ADDR_SITELOCAL(&ipv6_addr->sin6_addr)) { |
||||||
|
return kIPv6AddrScopeSiteLocal; |
||||||
|
} |
||||||
|
return kIPv6AddrScopeGlobal; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int compare_source_addr_exists(const address_sorting_sortable* first, |
||||||
|
const address_sorting_sortable* second) { |
||||||
|
if (first->source_addr_exists != second->source_addr_exists) { |
||||||
|
return first->source_addr_exists ? -1 : 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int compare_source_dest_scope_matches( |
||||||
|
const address_sorting_sortable* first, |
||||||
|
const address_sorting_sortable* second) { |
||||||
|
int first_src_dst_scope_matches = 0; |
||||||
|
if (sockaddr_get_scope(&first->dest_addr) == |
||||||
|
sockaddr_get_scope(&first->source_addr)) { |
||||||
|
first_src_dst_scope_matches = 1; |
||||||
|
} |
||||||
|
int second_src_dst_scope_matches = 0; |
||||||
|
if (sockaddr_get_scope(&second->dest_addr) == |
||||||
|
sockaddr_get_scope(&second->source_addr)) { |
||||||
|
second_src_dst_scope_matches = 1; |
||||||
|
} |
||||||
|
if (first_src_dst_scope_matches != second_src_dst_scope_matches) { |
||||||
|
return first_src_dst_scope_matches ? -1 : 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int compare_source_dest_labels_match( |
||||||
|
const address_sorting_sortable* first, |
||||||
|
const address_sorting_sortable* second) { |
||||||
|
int first_label_matches = 0; |
||||||
|
if (get_label_value(&first->dest_addr) == |
||||||
|
get_label_value(&first->source_addr)) { |
||||||
|
first_label_matches = 1; |
||||||
|
} |
||||||
|
int second_label_matches = 0; |
||||||
|
if (get_label_value(&second->dest_addr) == |
||||||
|
get_label_value(&second->source_addr)) { |
||||||
|
second_label_matches = 1; |
||||||
|
} |
||||||
|
if (first_label_matches != second_label_matches) { |
||||||
|
return first_label_matches ? 1 : 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int compare_dest_precedence(const address_sorting_sortable* first, |
||||||
|
const address_sorting_sortable* second) { |
||||||
|
return get_precedence_value(&second->dest_addr) - |
||||||
|
get_precedence_value(&first->dest_addr); |
||||||
|
} |
||||||
|
|
||||||
|
static int compare_dest_scope(const address_sorting_sortable* first, |
||||||
|
const address_sorting_sortable* second) { |
||||||
|
return sockaddr_get_scope(&first->dest_addr) - |
||||||
|
sockaddr_get_scope(&second->dest_addr); |
||||||
|
} |
||||||
|
|
||||||
|
static int compare_source_dest_prefix_match_lengths( |
||||||
|
const address_sorting_sortable* first, |
||||||
|
const address_sorting_sortable* second) { |
||||||
|
if (first->source_addr_exists && |
||||||
|
address_sorting_abstract_get_family(&first->source_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET6 && |
||||||
|
second->source_addr_exists && |
||||||
|
address_sorting_abstract_get_family(&second->source_addr) == |
||||||
|
ADDRESS_SORTING_AF_INET6) { |
||||||
|
int first_match_length = |
||||||
|
ipv6_prefix_match_length((struct sockaddr_in6*)&first->source_addr.addr, |
||||||
|
(struct sockaddr_in6*)&first->dest_addr.addr); |
||||||
|
int second_match_length = ipv6_prefix_match_length( |
||||||
|
(struct sockaddr_in6*)&second->source_addr.addr, |
||||||
|
(struct sockaddr_in6*)&second->dest_addr.addr); |
||||||
|
return second_match_length - first_match_length; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int rfc_6724_compare(const void* a, const void* b) { |
||||||
|
const address_sorting_sortable* first = (address_sorting_sortable*)a; |
||||||
|
const address_sorting_sortable* second = (address_sorting_sortable*)b; |
||||||
|
int out = 0; |
||||||
|
if ((out = compare_source_addr_exists(first, second))) { |
||||||
|
return out; |
||||||
|
} |
||||||
|
if ((out = compare_source_dest_scope_matches(first, second))) { |
||||||
|
return out; |
||||||
|
} |
||||||
|
if ((out = compare_source_dest_labels_match(first, second))) { |
||||||
|
return out; |
||||||
|
} |
||||||
|
// TODO: Implement rule 3; avoid deprecated addresses.
|
||||||
|
// TODO: Implement rule 4; avoid temporary addresses.
|
||||||
|
if ((out = compare_dest_precedence(first, second))) { |
||||||
|
return out; |
||||||
|
} |
||||||
|
// TODO: Implement rule 7; prefer native transports.
|
||||||
|
if ((out = compare_dest_scope(first, second))) { |
||||||
|
return out; |
||||||
|
} |
||||||
|
if ((out = compare_source_dest_prefix_match_lengths(first, second))) { |
||||||
|
return out; |
||||||
|
} |
||||||
|
// Prefer that the sort be stable otherwise
|
||||||
|
return (int)(first->original_index - second->original_index); |
||||||
|
} |
||||||
|
|
||||||
|
void address_sorting_override_source_addr_factory_for_testing( |
||||||
|
address_sorting_source_addr_factory* factory) { |
||||||
|
if (g_current_source_addr_factory == NULL) { |
||||||
|
abort(); |
||||||
|
} |
||||||
|
g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory); |
||||||
|
g_current_source_addr_factory = factory; |
||||||
|
} |
||||||
|
|
||||||
|
static void sanity_check_private_fields_are_unused( |
||||||
|
const address_sorting_sortable* sortable) { |
||||||
|
address_sorting_address expected_source_addr; |
||||||
|
memset(&expected_source_addr, 0, sizeof(expected_source_addr)); |
||||||
|
if (memcmp(&expected_source_addr, &sortable->source_addr, |
||||||
|
sizeof(address_sorting_address)) || |
||||||
|
sortable->original_index || sortable->source_addr_exists) { |
||||||
|
abort(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void address_sorting_rfc_6724_sort(address_sorting_sortable* sortables, |
||||||
|
size_t sortables_len) { |
||||||
|
for (size_t i = 0; i < sortables_len; i++) { |
||||||
|
sanity_check_private_fields_are_unused(&sortables[i]); |
||||||
|
sortables[i].original_index = i; |
||||||
|
sortables[i].source_addr_exists = address_sorting_get_source_addr( |
||||||
|
&sortables[i].dest_addr, &sortables[i].source_addr); |
||||||
|
} |
||||||
|
qsort(sortables, sortables_len, sizeof(address_sorting_sortable), |
||||||
|
rfc_6724_compare); |
||||||
|
} |
||||||
|
|
||||||
|
void address_sorting_init() { |
||||||
|
if (g_current_source_addr_factory != NULL) { |
||||||
|
abort(); |
||||||
|
} |
||||||
|
g_current_source_addr_factory = |
||||||
|
address_sorting_create_source_addr_factory_for_current_platform(); |
||||||
|
} |
||||||
|
|
||||||
|
void address_sorting_shutdown() { |
||||||
|
if (g_current_source_addr_factory == NULL) { |
||||||
|
abort(); |
||||||
|
} |
||||||
|
g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory); |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||||
|
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* 3. Neither the name of the project nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
* SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an adaptation of Android's implementation of RFC 6724 |
||||||
|
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||||
|
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||||
|
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||||
|
* this was written. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef ADDRESS_SORTING_H |
||||||
|
#define ADDRESS_SORTING_H |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
typedef struct address_sorting_address { |
||||||
|
char addr[128]; |
||||||
|
size_t len; |
||||||
|
} address_sorting_address; |
||||||
|
|
||||||
|
/* address_sorting_sortable represents one entry in a list of destination
|
||||||
|
* IP addresses to sort. It contains the destination IP address |
||||||
|
* "sorting key", along with placeholder and scratch fields. */ |
||||||
|
typedef struct address_sorting_sortable { |
||||||
|
// input data; sorting key
|
||||||
|
address_sorting_address dest_addr; |
||||||
|
// input data; optional value to attach to the sorting key
|
||||||
|
void* user_data; |
||||||
|
// internal fields, these must be zero'd when passed to sort function
|
||||||
|
address_sorting_address source_addr; |
||||||
|
bool source_addr_exists; |
||||||
|
size_t original_index; |
||||||
|
} address_sorting_sortable; |
||||||
|
|
||||||
|
void address_sorting_rfc_6724_sort(address_sorting_sortable* sortables, |
||||||
|
size_t sortables_len); |
||||||
|
|
||||||
|
void address_sorting_init(); |
||||||
|
void address_sorting_shutdown(); |
||||||
|
|
||||||
|
struct address_sorting_source_addr_factory; |
||||||
|
|
||||||
|
/* The interfaces below are exposed only for testing */ |
||||||
|
typedef struct { |
||||||
|
/* Gets the source address that would be used for the passed-in destination
|
||||||
|
* address, and fills in *source_addr* with it if one exists. |
||||||
|
* Returns true if a source address exists for the destination address, |
||||||
|
* and false otherwise. */ |
||||||
|
bool (*get_source_addr)(struct address_sorting_source_addr_factory* factory, |
||||||
|
const address_sorting_address* dest_addr, |
||||||
|
address_sorting_address* source_addr); |
||||||
|
void (*destroy)(struct address_sorting_source_addr_factory* factory); |
||||||
|
} address_sorting_source_addr_factory_vtable; |
||||||
|
|
||||||
|
typedef struct address_sorting_source_addr_factory { |
||||||
|
const address_sorting_source_addr_factory_vtable* vtable; |
||||||
|
} address_sorting_source_addr_factory; |
||||||
|
|
||||||
|
/* Platform-compatible address family types */ |
||||||
|
typedef enum { |
||||||
|
ADDRESS_SORTING_AF_INET, |
||||||
|
ADDRESS_SORTING_AF_INET6, |
||||||
|
ADDRESS_SORTING_UNKNOWN_FAMILY, |
||||||
|
} address_sorting_family; |
||||||
|
|
||||||
|
/* Indicates whether the address is AF_INET, AF_INET6, or another address
|
||||||
|
* family. */ |
||||||
|
address_sorting_family address_sorting_abstract_get_family( |
||||||
|
const address_sorting_address* address); |
||||||
|
|
||||||
|
void address_sorting_override_source_addr_factory_for_testing( |
||||||
|
address_sorting_source_addr_factory* factory); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // ADDRESS_SORTING_H
|
@ -0,0 +1,65 @@ |
|||||||
|
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||||
|
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* 3. Neither the name of the project nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
* SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an adaptation of Android's implementation of RFC 6724 |
||||||
|
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||||
|
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||||
|
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||||
|
* this was written. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef ADDRESS_SORTING_INTERNAL_H |
||||||
|
#define ADDRESS_SORTING_INTERNAL_H |
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) |
||||||
|
#include <winsock2.h> |
||||||
|
#include <ws2tcpip.h> |
||||||
|
// comment to prevent formatter from moving mswock.h upwards
|
||||||
|
#include <mswsock.h> |
||||||
|
#define ADDRESS_SORTING_WINDOWS 1 |
||||||
|
#else |
||||||
|
/* Workaround for issue described in
|
||||||
|
* |
||||||
|
* https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/1187301 */
|
||||||
|
#define _GNU_SOURCE |
||||||
|
#include <netinet/in.h> |
||||||
|
#include <sys/socket.h> |
||||||
|
#define ADDRESS_SORTING_POSIX 1 |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "address_sorting.h" |
||||||
|
|
||||||
|
address_sorting_source_addr_factory* |
||||||
|
address_sorting_create_source_addr_factory_for_current_platform(); |
||||||
|
|
||||||
|
#endif // ADDRESS_SORTING_INTERNAL_H
|
@ -0,0 +1,97 @@ |
|||||||
|
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||||
|
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* 3. Neither the name of the project nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
* SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an adaptation of Android's implementation of RFC 6724 |
||||||
|
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||||
|
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||||
|
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||||
|
* this was written. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "address_sorting_internal.h" |
||||||
|
|
||||||
|
#if defined(ADDRESS_SORTING_POSIX) |
||||||
|
|
||||||
|
#include <errno.h> |
||||||
|
#include <inttypes.h> |
||||||
|
#include <limits.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <sys/types.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
static bool posix_source_addr_factory_get_source_addr( |
||||||
|
address_sorting_source_addr_factory* factory, |
||||||
|
const address_sorting_address* dest_addr, |
||||||
|
address_sorting_address* source_addr) { |
||||||
|
bool source_addr_exists = false; |
||||||
|
// Android sets SOCK_CLOEXEC. Don't set this here for portability.
|
||||||
|
int s = socket(((struct sockaddr*)dest_addr)->sa_family, SOCK_DGRAM, 0); |
||||||
|
if (s != -1) { |
||||||
|
if (connect(s, (const struct sockaddr*)&dest_addr->addr, |
||||||
|
(socklen_t)dest_addr->len) != -1) { |
||||||
|
address_sorting_address found_source_addr; |
||||||
|
memset(&found_source_addr, 0, sizeof(found_source_addr)); |
||||||
|
found_source_addr.len = sizeof(found_source_addr.addr); |
||||||
|
if (getsockname(s, (struct sockaddr*)&found_source_addr.addr, |
||||||
|
(socklen_t*)&found_source_addr.len) != -1) { |
||||||
|
source_addr_exists = true; |
||||||
|
*source_addr = found_source_addr; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
close(s); |
||||||
|
return source_addr_exists; |
||||||
|
} |
||||||
|
|
||||||
|
static void posix_source_addr_factory_destroy( |
||||||
|
address_sorting_source_addr_factory* self) { |
||||||
|
free(self); |
||||||
|
} |
||||||
|
|
||||||
|
static const address_sorting_source_addr_factory_vtable |
||||||
|
posix_source_addr_factory_vtable = { |
||||||
|
posix_source_addr_factory_get_source_addr, |
||||||
|
posix_source_addr_factory_destroy, |
||||||
|
}; |
||||||
|
|
||||||
|
address_sorting_source_addr_factory* |
||||||
|
address_sorting_create_source_addr_factory_for_current_platform() { |
||||||
|
address_sorting_source_addr_factory* factory = |
||||||
|
malloc(sizeof(address_sorting_source_addr_factory)); |
||||||
|
memset(factory, 0, sizeof(address_sorting_source_addr_factory)); |
||||||
|
factory->vtable = &posix_source_addr_factory_vtable; |
||||||
|
return factory; |
||||||
|
} |
||||||
|
|
||||||
|
#endif // defined(ADDRESS_SORTING_POSIX)
|
@ -0,0 +1,55 @@ |
|||||||
|
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||||
|
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* 3. Neither the name of the project nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
* SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an adaptation of Android's implementation of RFC 6724 |
||||||
|
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||||
|
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||||
|
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||||
|
* this was written. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "address_sorting_internal.h" |
||||||
|
|
||||||
|
#if defined(ADDRESS_SORTING_WINDOWS) |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
/* TODO : Add address sorting functionality to work on windows. */ |
||||||
|
|
||||||
|
address_sorting_source_addr_factory* |
||||||
|
address_sorting_create_source_addr_factory_for_current_platform() { |
||||||
|
abort(); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
#endif // defined(ADDRESS_SORTING_WINDOWS)
|
Loading…
Reference in new issue