Add address sorting submodule for use in c-ares wrapper

pull/13290/head
Alexander Polcyn 7 years ago
parent 8327acd9a2
commit 690dde672a
  1. 1
      BUILD
  2. 489
      CMakeLists.txt
  3. 459
      Makefile
  4. 2
      bazel/grpc_build_system.bzl
  5. 14
      build.yaml
  6. 4
      config.m4
  7. 4
      config.w32
  8. 5
      grpc.gemspec
  9. 11
      grpc.gyp
  10. 5
      package.xml
  11. 3
      setup.py
  12. 4
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  13. 49
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
  14. 5
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
  15. 3
      src/python/grpcio/grpc_core_dependencies.py
  16. 6
      templates/CMakeLists.txt.template
  17. 18
      templates/Makefile.template
  18. 627
      test/cpp/naming/address_sorting_test.cc
  19. 19
      test/cpp/naming/gen_build_yaml.py
  20. 18
      test/cpp/naming/generate_resolver_component_tests.bzl
  21. 57
      third_party/address_sorting/BUILD
  22. 6101
      third_party/address_sorting/LICENSE
  23. 342
      third_party/address_sorting/address_sorting.c
  24. 112
      third_party/address_sorting/address_sorting.h
  25. 65
      third_party/address_sorting/address_sorting_internal.h
  26. 97
      third_party/address_sorting/address_sorting_posix.c
  27. 55
      third_party/address_sorting/address_sorting_windows.c
  28. 2
      tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
  29. 53
      tools/run_tests/generated/sources_and_headers.json
  30. 44
      tools/run_tests/generated/tests.json

@ -1290,6 +1290,7 @@ grpc_cc_library(
], ],
external_deps = [ external_deps = [
"cares", "cares",
"address_sorting",
], ],
language = "c++", language = "c++",
deps = [ deps = [

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -41,6 +41,8 @@ def _get_external_deps(external_deps):
elif dep == "cares": elif dep == "cares":
ret += select({"//:grpc_no_ares": [], ret += select({"//:grpc_no_ares": [],
"//conditions:default": ["//external:cares"],}) "//conditions:default": ["//external:cares"],})
elif dep == "address_sorting":
ret += ["//third_party/address_sorting"]
else: else:
ret += ["//external:" + dep] ret += ["//external:" + dep]
return ret return ret

@ -1312,6 +1312,17 @@ filegroups:
- grpc++ - grpc++
- grpc - grpc
libs: libs:
- name: address_sorting
build: all
language: c
headers:
- third_party/address_sorting/address_sorting.h
- third_party/address_sorting/address_sorting_internal.h
src:
- third_party/address_sorting/address_sorting.c
- third_party/address_sorting/address_sorting_posix.c
- third_party/address_sorting/address_sorting_windows.c
secure: false
- name: alts_test_util - name: alts_test_util
build: private build: private
language: c language: c
@ -5467,6 +5478,7 @@ php_config_m4:
- gpr - gpr
- boringssl - boringssl
- z - z
- address_sorting
headers: headers:
- src/php/ext/grpc/byte_buffer.h - src/php/ext/grpc/byte_buffer.h
- src/php/ext/grpc/call.h - src/php/ext/grpc/call.h
@ -5498,6 +5510,7 @@ python_dependencies:
- ares - ares
- boringssl - boringssl
- z - z
- address_sorting
ruby_gem: ruby_gem:
deps: deps:
- grpc - grpc
@ -5505,3 +5518,4 @@ ruby_gem:
- ares - ares
- boringssl - boringssl
- z - z
- address_sorting

@ -39,6 +39,9 @@ if test "$PHP_GRPC" != "no"; then
src/php/ext/grpc/server.c \ src/php/ext/grpc/server.c \
src/php/ext/grpc/server_credentials.c \ src/php/ext/grpc/server_credentials.c \
src/php/ext/grpc/timeval.c \ src/php/ext/grpc/timeval.c \
third_party/address_sorting/address_sorting.c \
third_party/address_sorting/address_sorting_posix.c \
third_party/address_sorting/address_sorting_windows.c \
src/core/lib/gpr/alloc.cc \ src/core/lib/gpr/alloc.cc \
src/core/lib/gpr/arena.cc \ src/core/lib/gpr/arena.cc \
src/core/lib/gpr/atm.cc \ src/core/lib/gpr/atm.cc \
@ -704,6 +707,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/handshaker) PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/handshaker)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/zero_copy_frame_protector) PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/zero_copy_frame_protector)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/ssl/session_cache) PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/ssl/session_cache)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/address_sorting)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/base64) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/base64)

@ -16,6 +16,9 @@ if (PHP_GRPC != "no") {
"src\\php\\ext\\grpc\\server.c " + "src\\php\\ext\\grpc\\server.c " +
"src\\php\\ext\\grpc\\server_credentials.c " + "src\\php\\ext\\grpc\\server_credentials.c " +
"src\\php\\ext\\grpc\\timeval.c " + "src\\php\\ext\\grpc\\timeval.c " +
"third_party\\address_sorting\\address_sorting.c " +
"third_party\\address_sorting\\address_sorting_posix.c " +
"third_party\\address_sorting\\address_sorting_windows.c " +
"src\\core\\lib\\gpr\\alloc.cc " + "src\\core\\lib\\gpr\\alloc.cc " +
"src\\core\\lib\\gpr\\arena.cc " + "src\\core\\lib\\gpr\\arena.cc " +
"src\\core\\lib\\gpr\\atm.cc " + "src\\core\\lib\\gpr\\atm.cc " +
@ -723,6 +726,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext\\grpc"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext\\grpc");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\address_sorting");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto\\asn1"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto\\asn1");

@ -44,6 +44,11 @@ Gem::Specification.new do |s|
s.extensions = %w(src/ruby/ext/grpc/extconf.rb) s.extensions = %w(src/ruby/ext/grpc/extconf.rb)
s.files += %w( third_party/address_sorting/address_sorting.h )
s.files += %w( third_party/address_sorting/address_sorting_internal.h )
s.files += %w( third_party/address_sorting/address_sorting.c )
s.files += %w( third_party/address_sorting/address_sorting_posix.c )
s.files += %w( third_party/address_sorting/address_sorting_windows.c )
s.files += %w( include/grpc/support/alloc.h ) s.files += %w( include/grpc/support/alloc.h )
s.files += %w( include/grpc/support/atm.h ) s.files += %w( include/grpc/support/atm.h )
s.files += %w( include/grpc/support/atm_gcc_atomic.h ) s.files += %w( include/grpc/support/atm_gcc_atomic.h )

@ -156,6 +156,17 @@
] ]
}, },
'targets': [ 'targets': [
{
'target_name': 'address_sorting',
'type': 'static_library',
'dependencies': [
],
'sources': [
'third_party/address_sorting/address_sorting.c',
'third_party/address_sorting/address_sorting_posix.c',
'third_party/address_sorting/address_sorting_windows.c',
],
},
{ {
'target_name': 'alts_test_util', 'target_name': 'alts_test_util',
'type': 'static_library', 'type': 'static_library',

@ -51,6 +51,11 @@
<file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/timeval.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/timeval.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/version.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/version.h" role="src" />
<file baseinstalldir="/" name="third_party/address_sorting/address_sorting.h" role="src" />
<file baseinstalldir="/" name="third_party/address_sorting/address_sorting_internal.h" role="src" />
<file baseinstalldir="/" name="third_party/address_sorting/address_sorting.c" role="src" />
<file baseinstalldir="/" name="third_party/address_sorting/address_sorting_posix.c" role="src" />
<file baseinstalldir="/" name="third_party/address_sorting/address_sorting_windows.c" role="src" />
<file baseinstalldir="/" name="include/grpc/support/alloc.h" role="src" /> <file baseinstalldir="/" name="include/grpc/support/alloc.h" role="src" />
<file baseinstalldir="/" name="include/grpc/support/atm.h" role="src" /> <file baseinstalldir="/" name="include/grpc/support/atm.h" role="src" />
<file baseinstalldir="/" name="include/grpc/support/atm_gcc_atomic.h" role="src" /> <file baseinstalldir="/" name="include/grpc/support/atm_gcc_atomic.h" role="src" />

@ -48,6 +48,7 @@ if 'linux' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),) CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
if 'openbsd' in sys.platform: if 'openbsd' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_openbsd'),) CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_openbsd'),)
ADDRESS_SORTING_INCLUDE = (os.path.join('third_party', 'address_sorting'),)
README = os.path.join(PYTHON_STEM, 'README.rst') README = os.path.join(PYTHON_STEM, 'README.rst')
# Ensure we're in the proper directory whether or not we're being used by pip. # Ensure we're in the proper directory whether or not we're being used by pip.
@ -149,7 +150,7 @@ if "win32" in sys.platform:
EXTENSION_INCLUDE_DIRECTORIES = ( EXTENSION_INCLUDE_DIRECTORIES = (
(PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE + (PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE +
CARES_INCLUDE) CARES_INCLUDE + ADDRESS_SORTING_INCLUDE)
EXTENSION_LIBRARIES = () EXTENSION_LIBRARIES = ()
if "linux" in sys.platform: if "linux" in sys.platform:

@ -28,6 +28,8 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <address_sorting.h>
#include "src/core/ext/filters/client_channel/http_connect_handshaker.h" #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
#include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
@ -458,6 +460,7 @@ void grpc_resolver_dns_ares_init() {
/* TODO(zyc): Turn on c-ares based resolver by default after the address /* TODO(zyc): Turn on c-ares based resolver by default after the address
sorter and the CNAME support are added. */ sorter and the CNAME support are added. */
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) { if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
address_sorting_init();
grpc_error* error = grpc_ares_init(); grpc_error* error = grpc_ares_init();
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
GRPC_LOG_IF_ERROR("ares_library_init() failed", error); GRPC_LOG_IF_ERROR("ares_library_init() failed", error);
@ -475,6 +478,7 @@ void grpc_resolver_dns_ares_init() {
void grpc_resolver_dns_ares_shutdown() { void grpc_resolver_dns_ares_shutdown() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) { if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
address_sorting_shutdown();
grpc_ares_cleanup(); grpc_ares_cleanup();
} }
gpr_free(resolver_env); gpr_free(resolver_env);

@ -33,6 +33,7 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include <address_sorting.h>
#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
#include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/host_port.h"
@ -46,6 +47,9 @@
static gpr_once g_basic_init = GPR_ONCE_INIT; static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu; static gpr_mu g_init_mu;
grpc_core::TraceFlag grpc_trace_cares_address_sorting(false,
"cares_address_sorting");
struct grpc_ares_request { struct grpc_ares_request {
/** indicates the DNS server to use, if specified */ /** indicates the DNS server to use, if specified */
struct ares_addr_port_node dns_server_addr; struct ares_addr_port_node dns_server_addr;
@ -96,11 +100,54 @@ static void grpc_ares_request_ref(grpc_ares_request* r) {
gpr_ref(&r->pending_queries); gpr_ref(&r->pending_queries);
} }
static void log_address_sorting_list(grpc_lb_addresses* lb_addrs,
const char* input_output_str) {
for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
char* addr_str;
if (grpc_sockaddr_to_string(&addr_str, &lb_addrs->addresses[i].address,
true)) {
gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s",
input_output_str, i, addr_str);
gpr_free(addr_str);
} else {
gpr_log(GPR_DEBUG,
"c-ares address sorting: %s[%" PRIuPTR "]=<unprintable>",
input_output_str, i);
}
}
}
void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) {
if (grpc_trace_cares_address_sorting.enabled()) {
log_address_sorting_list(lb_addrs, "input");
}
address_sorting_sortable* sortables = (address_sorting_sortable*)gpr_zalloc(
sizeof(address_sorting_sortable) * lb_addrs->num_addresses);
for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
sortables[i].user_data = &lb_addrs->addresses[i];
memcpy(&sortables[i].dest_addr.addr, &lb_addrs->addresses[i].address.addr,
lb_addrs->addresses[i].address.len);
sortables[i].dest_addr.len = lb_addrs->addresses[i].address.len;
}
address_sorting_rfc_6724_sort(sortables, lb_addrs->num_addresses);
grpc_lb_address* sorted_lb_addrs = (grpc_lb_address*)gpr_zalloc(
sizeof(grpc_lb_address) * lb_addrs->num_addresses);
for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
sorted_lb_addrs[i] = *(grpc_lb_address*)sortables[i].user_data;
}
gpr_free(sortables);
gpr_free(lb_addrs->addresses);
lb_addrs->addresses = sorted_lb_addrs;
if (grpc_trace_cares_address_sorting.enabled()) {
log_address_sorting_list(lb_addrs, "output");
}
}
static void grpc_ares_request_unref(grpc_ares_request* r) { static void grpc_ares_request_unref(grpc_ares_request* r) {
/* If there are no pending queries, invoke on_done callback and destroy the /* If there are no pending queries, invoke on_done callback and destroy the
request */ request */
if (gpr_unref(&r->pending_queries)) { if (gpr_unref(&r->pending_queries)) {
/* TODO(zyc): Sort results with RFC6724 before invoking on_done. */ grpc_cares_wrapper_address_sorting_sort(*(r->lb_addrs_out));
GRPC_CLOSURE_SCHED(r->on_done, r->error); GRPC_CLOSURE_SCHED(r->on_done, r->error);
gpr_mu_destroy(&r->mu); gpr_mu_destroy(&r->mu);
grpc_ares_ev_driver_destroy(r->ev_driver); grpc_ares_ev_driver_destroy(r->ev_driver);

@ -26,6 +26,8 @@
#include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/resolve_address.h"
extern grpc_core::TraceFlag grpc_trace_cares_address_sorting;
typedef struct grpc_ares_request grpc_ares_request; typedef struct grpc_ares_request grpc_ares_request;
/* Asynchronously resolve \a name. Use \a default_port if a port isn't /* Asynchronously resolve \a name. Use \a default_port if a port isn't
@ -64,5 +66,8 @@ grpc_error* grpc_ares_init(void);
it has been called the same number of times as grpc_ares_init(). */ it has been called the same number of times as grpc_ares_init(). */
void grpc_ares_cleanup(void); void grpc_ares_cleanup(void);
/* Exposed only for testing */
void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \ #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \
*/ */

@ -15,6 +15,9 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!! # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!!
CORE_SOURCE_FILES = [ CORE_SOURCE_FILES = [
'third_party/address_sorting/address_sorting.c',
'third_party/address_sorting/address_sorting_posix.c',
'third_party/address_sorting/address_sorting_windows.c',
'src/core/lib/gpr/alloc.cc', 'src/core/lib/gpr/alloc.cc',
'src/core/lib/gpr/arena.cc', 'src/core/lib/gpr/arena.cc',
'src/core/lib/gpr/atm.cc', 'src/core/lib/gpr/atm.cc',

@ -46,6 +46,7 @@
if target_dict['name'] in ['grpc', 'grpc_cronet', 'grpc_unsecure']: if target_dict['name'] in ['grpc', 'grpc_cronet', 'grpc_unsecure']:
deps.append("${_gRPC_ZLIB_LIBRARIES}") deps.append("${_gRPC_ZLIB_LIBRARIES}")
deps.append("${_gRPC_CARES_LIBRARIES}") deps.append("${_gRPC_CARES_LIBRARIES}")
deps.append("${_gRPC_ADDRESS_SORTING_LIBRARIES}")
deps.append("${_gRPC_ALLTARGETS_LIBRARIES}") deps.append("${_gRPC_ALLTARGETS_LIBRARIES}")
for d in target_dict.get('deps', []): for d in target_dict.get('deps', []):
if d == 'benchmark': if d == 'benchmark':
@ -166,6 +167,9 @@
include(cmake/gflags.cmake) include(cmake/gflags.cmake)
include(cmake/benchmark.cmake) include(cmake/benchmark.cmake)
include_directories(<%text>${CMAKE_CURRENT_SOURCE_DIR}/third_party/address_sorting</%text>)
set(_gRPC_ADDRESS_SORTING_LIBRARIES address_sorting)
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_C_FLAGS "<%text>${CMAKE_C_FLAGS}</%text> -std=c99") set(CMAKE_C_FLAGS "<%text>${CMAKE_C_FLAGS}</%text> -std=c99")
set(CMAKE_CXX_FLAGS "<%text>${CMAKE_CXX_FLAGS}</%text> -std=c++11") set(CMAKE_CXX_FLAGS "<%text>${CMAKE_CXX_FLAGS}</%text> -std=c++11")
@ -375,6 +379,7 @@
PRIVATE <%text>${_gRPC_BENCHMARK_INCLUDE_DIR}</%text> PRIVATE <%text>${_gRPC_BENCHMARK_INCLUDE_DIR}</%text>
PRIVATE <%text>${_gRPC_CARES_INCLUDE_DIR}</%text> PRIVATE <%text>${_gRPC_CARES_INCLUDE_DIR}</%text>
PRIVATE <%text>${_gRPC_GFLAGS_INCLUDE_DIR}</%text> PRIVATE <%text>${_gRPC_GFLAGS_INCLUDE_DIR}</%text>
PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/address_sorting
% if lib.build in ['test', 'private'] and lib.language == 'c++': % if lib.build in ['test', 'private'] and lib.language == 'c++':
PRIVATE third_party/googletest/googletest/include PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest PRIVATE third_party/googletest/googletest
@ -455,6 +460,7 @@
PRIVATE <%text>${_gRPC_BENCHMARK_INCLUDE_DIR}</%text> PRIVATE <%text>${_gRPC_BENCHMARK_INCLUDE_DIR}</%text>
PRIVATE <%text>${_gRPC_CARES_INCLUDE_DIR}</%text> PRIVATE <%text>${_gRPC_CARES_INCLUDE_DIR}</%text>
PRIVATE <%text>${_gRPC_GFLAGS_INCLUDE_DIR}</%text> PRIVATE <%text>${_gRPC_GFLAGS_INCLUDE_DIR}</%text>
PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/address_sorting
% if tgt.build in ['test', 'private'] and tgt.language == 'c++': % if tgt.build in ['test', 'private'] and tgt.language == 'c++':
PRIVATE third_party/googletest/googletest/include PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest PRIVATE third_party/googletest/googletest

@ -590,6 +590,11 @@
EMBED_CARES ?= false EMBED_CARES ?= false
endif endif
ADDRESS_SORTING_DEP = $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
ADDRESS_SORTING_MERGE_OBJS = $(LIBADDRESS_SORTING_OBJS)
ADDRESS_SORTING_MERGE_LIBS = $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
CPPFLAGS := -Ithird_party/address_sorting $(CPPFLAGS)
ifeq ($(EMBED_CARES),true) ifeq ($(EMBED_CARES),true)
CARES_DEP = $(LIBDIR)/$(CONFIG)/libares.a CARES_DEP = $(LIBDIR)/$(CONFIG)/libares.a
CARES_MERGE_OBJS = $(LIBARES_OBJS) CARES_MERGE_OBJS = $(LIBARES_OBJS)
@ -1480,7 +1485,7 @@
else else
% endif % endif
$(LIBDIR)/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP)\ $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)\
## The else here corresponds to the if secure earlier. ## The else here corresponds to the if secure earlier.
% else: % else:
% if lib.language == 'c++': % if lib.language == 'c++':
@ -1504,6 +1509,9 @@
% if lib.name != 'ares': % if lib.name != 'ares':
$(CARES_DEP) \ $(CARES_DEP) \
% endif % endif
% if lib.name != 'address_sorting':
$(ADDRESS_SORTING_DEP) \
% endif
% endif % endif
% if lib.language == 'c++': % if lib.language == 'c++':
$(PROTOBUF_DEP)\ $(PROTOBUF_DEP)\
@ -1513,6 +1521,7 @@
$(LIBGPR_OBJS) \ $(LIBGPR_OBJS) \
$(ZLIB_MERGE_OBJS) \ $(ZLIB_MERGE_OBJS) \
$(CARES_MERGE_OBJS) \ $(CARES_MERGE_OBJS) \
$(ADDRESS_SORTING_MERGE_OBJS) \
% if lib.get('secure', 'check') == True: % if lib.get('secure', 'check') == True:
$(OPENSSL_MERGE_OBJS) \ $(OPENSSL_MERGE_OBJS) \
% endif % endif
@ -1526,6 +1535,7 @@
$(LIBGPR_OBJS) \ $(LIBGPR_OBJS) \
$(ZLIB_MERGE_OBJS) \ $(ZLIB_MERGE_OBJS) \
$(CARES_MERGE_OBJS) \ $(CARES_MERGE_OBJS) \
$(ADDRESS_SORTING_MERGE_OBJS) \
% if lib.get('secure', 'check') == True: % if lib.get('secure', 'check') == True:
$(OPENSSL_MERGE_OBJS) \ $(OPENSSL_MERGE_OBJS) \
% endif % endif
@ -1548,9 +1558,9 @@
common = '$(LIB' + lib.name.upper() + '_OBJS)' common = '$(LIB' + lib.name.upper() + '_OBJS)'
link_libs = '' link_libs = ''
lib_deps = ' $(ZLIB_DEP) $(CARES_DEP)' lib_deps = ' $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)'
mingw_libs = '' mingw_libs = ''
mingw_lib_deps = ' $(ZLIB_DEP) $(CARES_DEP)' mingw_lib_deps = ' $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)'
if lib.language == 'c++': if lib.language == 'c++':
lib_deps += ' $(PROTOBUF_DEP)' lib_deps += ' $(PROTOBUF_DEP)'
mingw_lib_deps += ' $(PROTOBUF_DEP)' mingw_lib_deps += ' $(PROTOBUF_DEP)'
@ -1575,7 +1585,7 @@
security = lib.get('secure', 'check') security = lib.get('secure', 'check')
if security == True: if security == True:
common = common + ' $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE)' common = common + ' $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE)'
common = common + ' $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS)' common = common + ' $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS)'
if security in [True, 'check']: if security in [True, 'check']:
for src in lib.src: for src in lib.src:

@ -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;
}

@ -182,6 +182,25 @@ def main():
'--running_under_bazel=false', '--running_under_bazel=false',
], ],
} for unsecure_build_config_suffix in ['_unsecure', ''] } for unsecure_build_config_suffix in ['_unsecure', '']
] + [
{
'name': 'address_sorting_test' + unsecure_build_config_suffix,
'build': 'test',
'language': 'c++',
'gtest': True,
'run': True,
'src': ['test/cpp/naming/address_sorting_test.cc'],
'platforms': ['linux', 'posix', 'mac'],
'deps': [
'grpc++_test_util' + unsecure_build_config_suffix,
'grpc_test_util' + unsecure_build_config_suffix,
'gpr_test_util',
'grpc++' + unsecure_build_config_suffix,
'grpc' + unsecure_build_config_suffix,
'gpr',
'grpc++_test_config',
],
} for unsecure_build_config_suffix in ['_unsecure', '']
] ]
} }

@ -17,6 +17,24 @@ load("//bazel:grpc_build_system.bzl", "grpc_sh_binary", "grpc_cc_test", "grpc_cc
def generate_resolver_component_tests(): def generate_resolver_component_tests():
for unsecure_build_config_suffix in ['_unsecure', '']: for unsecure_build_config_suffix in ['_unsecure', '']:
grpc_cc_test(
name = "address_sorting_test%s" % unsecure_build_config_suffix,
srcs = [
"address_sorting_test.cc",
],
external_deps = [
"gmock",
],
deps = [
"//test/cpp/util:test_util%s" % unsecure_build_config_suffix,
"//test/core/util:grpc_test_util%s" % unsecure_build_config_suffix,
"//test/core/util:gpr_test_util",
"//:grpc++%s" % unsecure_build_config_suffix,
"//:grpc%s" % unsecure_build_config_suffix,
"//:gpr",
"//test/cpp/util:test_config",
],
)
# meant to be invoked only through the top-level shell script driver # meant to be invoked only through the top-level shell script driver
grpc_cc_binary( grpc_cc_binary(
name = "resolver_component_test%s" % unsecure_build_config_suffix, name = "resolver_component_test%s" % unsecure_build_config_suffix,

@ -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)

@ -16,7 +16,7 @@
set -e set -e
# directories to run against # directories to run against
DIRS="src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby" DIRS="src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby third_party/address_sorting"
# file matching patterns to check # file matching patterns to check
GLOB="*.h *.c *.cc" GLOB="*.h *.c *.cc"

@ -6343,6 +6343,46 @@
"third_party": false, "third_party": false,
"type": "target" "type": "target"
}, },
{
"deps": [
"gpr",
"gpr_test_util",
"grpc++_test_config",
"grpc++_test_util_unsecure",
"grpc++_unsecure",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "address_sorting_test_unsecure",
"src": [
"test/cpp/naming/address_sorting_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc++",
"grpc++_test_config",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "address_sorting_test",
"src": [
"test/cpp/naming/address_sorting_test.cc"
],
"third_party": false,
"type": "target"
},
{ {
"deps": [ "deps": [
"gpr", "gpr",
@ -6577,6 +6617,19 @@
"third_party": false, "third_party": false,
"type": "target" "type": "target"
}, },
{
"deps": [],
"headers": [
"third_party/address_sorting/address_sorting.h",
"third_party/address_sorting/address_sorting_internal.h"
],
"is_filegroup": false,
"language": "c",
"name": "address_sorting",
"src": [],
"third_party": false,
"type": "lib"
},
{ {
"deps": [ "deps": [
"grpc" "grpc"

@ -5484,6 +5484,50 @@
], ],
"uses_polling": true "uses_polling": true
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "address_sorting_test_unsecure",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "address_sorting_test",
"platforms": [
"linux",
"mac",
"posix"
],
"uses_polling": true
},
{ {
"args": [], "args": [],
"boringssl": true, "boringssl": true,

Loading…
Cancel
Save