aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD6
-rw-r--r--CMakeLists.txt2
-rw-r--r--Makefile169
-rw-r--r--binding.gyp1
-rw-r--r--build.yaml20
-rw-r--r--config.m41
-rw-r--r--gRPC-Core.podspec3
-rwxr-xr-xgrpc.gemspec2
-rw-r--r--package.xml2
-rw-r--r--src/core/ext/client_config/lb_policy.h11
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c1039
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.h44
-rw-r--r--src/core/ext/lb_policy/grpclb/load_balancer_api.c141
-rw-r--r--src/core/ext/lb_policy/grpclb/load_balancer_api.h36
-rw-r--r--src/core/lib/iomgr/tcp_posix.c2
-rw-r--r--src/core/lib/surface/call.c6
-rw-r--r--src/core/plugin_registry/grpc_plugin_registry.c4
-rw-r--r--src/core/plugin_registry/grpc_unsecure_plugin_registry.c4
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py1
-rw-r--r--test/core/end2end/cq_verifier.c9
-rw-r--r--test/core/end2end/cq_verifier.h3
-rw-r--r--test/core/nanopb/fuzzer_response.c6
-rw-r--r--test/cpp/grpclb/grpclb_api_test.cc18
-rw-r--r--test/cpp/grpclb/grpclb_test.cc688
-rw-r--r--test/cpp/qps/limit_cores.cc4
-rw-r--r--tools/doxygen/Doxyfile.core.internal2
-rwxr-xr-xtools/run_tests/build_python.sh4
-rw-r--r--tools/run_tests/sources_and_headers.json27
-rw-r--r--tools/run_tests/tests.json21
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj3
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj.filters6
-rw-r--r--vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj284
-rw-r--r--vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters629
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj3
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters6
-rw-r--r--vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj215
-rw-r--r--vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters39
37 files changed, 3394 insertions, 67 deletions
diff --git a/BUILD b/BUILD
index 8a6d7fdc0a..3906a8eba9 100644
--- a/BUILD
+++ b/BUILD
@@ -300,6 +300,7 @@ cc_library(
"src/core/ext/client_config/subchannel_call_holder.h",
"src/core/ext/client_config/subchannel_index.h",
"src/core/ext/client_config/uri_parser.h",
+ "src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
"src/core/ext/load_reporting/load_reporting.h",
@@ -476,6 +477,7 @@ cc_library(
"src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
+ "src/core/ext/lb_policy/grpclb/grpclb.c",
"src/core/ext/lb_policy/grpclb/load_balancer_api.c",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
"src/core/ext/lb_policy/pick_first/pick_first.c",
@@ -1021,6 +1023,7 @@ cc_library(
"src/core/ext/client_config/uri_parser.h",
"src/core/ext/load_reporting/load_reporting.h",
"src/core/ext/load_reporting/load_reporting_filter.h",
+ "src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
"src/core/ext/census/aggregation.h",
@@ -1170,6 +1173,7 @@ cc_library(
"src/core/ext/resolver/sockaddr/sockaddr_resolver.c",
"src/core/ext/load_reporting/load_reporting.c",
"src/core/ext/load_reporting/load_reporting_filter.c",
+ "src/core/ext/lb_policy/grpclb/grpclb.c",
"src/core/ext/lb_policy/grpclb/load_balancer_api.c",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
"src/core/ext/lb_policy/pick_first/pick_first.c",
@@ -1956,6 +1960,7 @@ objc_library(
"src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
+ "src/core/ext/lb_policy/grpclb/grpclb.c",
"src/core/ext/lb_policy/grpclb/load_balancer_api.c",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
"src/core/ext/lb_policy/pick_first/pick_first.c",
@@ -2148,6 +2153,7 @@ objc_library(
"src/core/ext/client_config/subchannel_call_holder.h",
"src/core/ext/client_config/subchannel_index.h",
"src/core/ext/client_config/uri_parser.h",
+ "src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
"src/core/ext/load_reporting/load_reporting.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c55825b37d..0d2e276e94 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -442,6 +442,7 @@ add_library(grpc
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
src/core/ext/transport/chttp2/client/insecure/channel_create.c
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
+ src/core/ext/lb_policy/grpclb/grpclb.c
src/core/ext/lb_policy/grpclb/load_balancer_api.c
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
third_party/nanopb/pb_common.c
@@ -899,6 +900,7 @@ add_library(grpc_unsecure
src/core/ext/resolver/sockaddr/sockaddr_resolver.c
src/core/ext/load_reporting/load_reporting.c
src/core/ext/load_reporting/load_reporting_filter.c
+ src/core/ext/lb_policy/grpclb/grpclb.c
src/core/ext/lb_policy/grpclb/load_balancer_api.c
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
third_party/nanopb/pb_common.c
diff --git a/Makefile b/Makefile
index e0be2ffbac..3fd66d5b98 100644
--- a/Makefile
+++ b/Makefile
@@ -1048,6 +1048,7 @@ grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin
grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test
+grpclb_test: $(BINDIR)/$(CONFIG)/grpclb_test
hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
interop_client: $(BINDIR)/$(CONFIG)/interop_client
interop_server: $(BINDIR)/$(CONFIG)/interop_server
@@ -1403,6 +1404,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
+ $(BINDIR)/$(CONFIG)/grpclb_test \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
$(BINDIR)/$(CONFIG)/interop_client \
$(BINDIR)/$(CONFIG)/interop_server \
@@ -1487,6 +1489,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
$(BINDIR)/$(CONFIG)/grpclb_api_test \
+ $(BINDIR)/$(CONFIG)/grpclb_test \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
$(BINDIR)/$(CONFIG)/interop_client \
$(BINDIR)/$(CONFIG)/interop_server \
@@ -1774,6 +1777,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
$(E) "[RUN] Testing grpclb_api_test"
$(Q) $(BINDIR)/$(CONFIG)/grpclb_api_test || ( echo test grpclb_api_test failed ; exit 1 )
+ $(E) "[RUN] Testing grpclb_test"
+ $(Q) $(BINDIR)/$(CONFIG)/grpclb_test || ( echo test grpclb_test failed ; exit 1 )
$(E) "[RUN] Testing hybrid_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/hybrid_end2end_test || ( echo test hybrid_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing interop_test"
@@ -2681,6 +2686,7 @@ LIBGRPC_SRC = \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
+ src/core/ext/lb_policy/grpclb/grpclb.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
@@ -3056,8 +3062,123 @@ LIBGRPC_TEST_UTIL_SRC = \
test/core/util/port_server_client.c \
test/core/util/port_windows.c \
test/core/util/slice_splitter.c \
+ src/core/lib/channel/channel_args.c \
+ src/core/lib/channel/channel_stack.c \
+ src/core/lib/channel/channel_stack_builder.c \
+ src/core/lib/channel/compress_filter.c \
+ src/core/lib/channel/connected_channel.c \
+ src/core/lib/channel/handshaker.c \
+ src/core/lib/channel/http_client_filter.c \
+ src/core/lib/channel/http_server_filter.c \
+ src/core/lib/compression/compression.c \
+ src/core/lib/compression/message_compress.c \
+ src/core/lib/debug/trace.c \
+ src/core/lib/http/format_request.c \
+ src/core/lib/http/httpcli.c \
+ src/core/lib/http/parser.c \
+ src/core/lib/iomgr/closure.c \
+ src/core/lib/iomgr/endpoint.c \
+ src/core/lib/iomgr/endpoint_pair_posix.c \
+ src/core/lib/iomgr/endpoint_pair_windows.c \
+ src/core/lib/iomgr/error.c \
+ src/core/lib/iomgr/ev_epoll_linux.c \
+ src/core/lib/iomgr/ev_poll_and_epoll_posix.c \
+ src/core/lib/iomgr/ev_poll_posix.c \
+ src/core/lib/iomgr/ev_posix.c \
+ src/core/lib/iomgr/exec_ctx.c \
+ src/core/lib/iomgr/executor.c \
+ src/core/lib/iomgr/iocp_windows.c \
+ src/core/lib/iomgr/iomgr.c \
+ src/core/lib/iomgr/iomgr_posix.c \
+ src/core/lib/iomgr/iomgr_windows.c \
+ src/core/lib/iomgr/load_file.c \
+ src/core/lib/iomgr/network_status_tracker.c \
+ src/core/lib/iomgr/polling_entity.c \
+ src/core/lib/iomgr/pollset_set_windows.c \
+ src/core/lib/iomgr/pollset_windows.c \
+ src/core/lib/iomgr/resolve_address_posix.c \
+ src/core/lib/iomgr/resolve_address_windows.c \
+ src/core/lib/iomgr/sockaddr_utils.c \
+ src/core/lib/iomgr/socket_utils_common_posix.c \
+ src/core/lib/iomgr/socket_utils_linux.c \
+ src/core/lib/iomgr/socket_utils_posix.c \
+ src/core/lib/iomgr/socket_windows.c \
+ src/core/lib/iomgr/tcp_client_posix.c \
+ src/core/lib/iomgr/tcp_client_windows.c \
+ src/core/lib/iomgr/tcp_posix.c \
+ src/core/lib/iomgr/tcp_server_posix.c \
+ src/core/lib/iomgr/tcp_server_windows.c \
+ src/core/lib/iomgr/tcp_windows.c \
+ src/core/lib/iomgr/time_averaged_stats.c \
+ src/core/lib/iomgr/timer.c \
+ src/core/lib/iomgr/timer_heap.c \
+ src/core/lib/iomgr/udp_server.c \
+ src/core/lib/iomgr/unix_sockets_posix.c \
+ src/core/lib/iomgr/unix_sockets_posix_noop.c \
+ src/core/lib/iomgr/wakeup_fd_eventfd.c \
+ src/core/lib/iomgr/wakeup_fd_nospecial.c \
+ src/core/lib/iomgr/wakeup_fd_pipe.c \
+ src/core/lib/iomgr/wakeup_fd_posix.c \
+ src/core/lib/iomgr/workqueue_posix.c \
+ src/core/lib/iomgr/workqueue_windows.c \
+ src/core/lib/json/json.c \
+ src/core/lib/json/json_reader.c \
+ src/core/lib/json/json_string.c \
+ src/core/lib/json/json_writer.c \
+ src/core/lib/surface/alarm.c \
+ src/core/lib/surface/api_trace.c \
+ src/core/lib/surface/byte_buffer.c \
+ src/core/lib/surface/byte_buffer_reader.c \
+ src/core/lib/surface/call.c \
+ src/core/lib/surface/call_details.c \
+ src/core/lib/surface/call_log_batch.c \
+ src/core/lib/surface/channel.c \
+ src/core/lib/surface/channel_init.c \
+ src/core/lib/surface/channel_ping.c \
+ src/core/lib/surface/channel_stack_type.c \
+ src/core/lib/surface/completion_queue.c \
+ src/core/lib/surface/event_string.c \
+ src/core/lib/surface/lame_client.c \
+ src/core/lib/surface/metadata_array.c \
+ src/core/lib/surface/server.c \
+ src/core/lib/surface/validate_metadata.c \
+ src/core/lib/surface/version.c \
+ src/core/lib/transport/byte_stream.c \
+ src/core/lib/transport/connectivity_state.c \
+ src/core/lib/transport/metadata.c \
+ src/core/lib/transport/metadata_batch.c \
+ src/core/lib/transport/static_metadata.c \
+ src/core/lib/transport/transport.c \
+ src/core/lib/transport/transport_op_string.c \
PUBLIC_HEADERS_C += \
+ include/grpc/byte_buffer.h \
+ include/grpc/byte_buffer_reader.h \
+ include/grpc/compression.h \
+ include/grpc/grpc.h \
+ include/grpc/grpc_posix.h \
+ include/grpc/status.h \
+ include/grpc/impl/codegen/byte_buffer.h \
+ include/grpc/impl/codegen/byte_buffer_reader.h \
+ include/grpc/impl/codegen/compression_types.h \
+ include/grpc/impl/codegen/connectivity_state.h \
+ include/grpc/impl/codegen/grpc_types.h \
+ include/grpc/impl/codegen/propagation_bits.h \
+ include/grpc/impl/codegen/status.h \
+ include/grpc/impl/codegen/alloc.h \
+ include/grpc/impl/codegen/atm.h \
+ include/grpc/impl/codegen/atm_gcc_atomic.h \
+ include/grpc/impl/codegen/atm_gcc_sync.h \
+ include/grpc/impl/codegen/atm_windows.h \
+ include/grpc/impl/codegen/log.h \
+ include/grpc/impl/codegen/port_platform.h \
+ include/grpc/impl/codegen/slice.h \
+ include/grpc/impl/codegen/slice_buffer.h \
+ include/grpc/impl/codegen/sync.h \
+ include/grpc/impl/codegen/sync_generic.h \
+ include/grpc/impl/codegen/sync_posix.h \
+ include/grpc/impl/codegen/sync_windows.h \
+ include/grpc/impl/codegen/time.h \
LIBGRPC_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_SRC))))
@@ -3270,6 +3391,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
src/core/ext/load_reporting/load_reporting.c \
src/core/ext/load_reporting/load_reporting_filter.c \
+ src/core/ext/lb_policy/grpclb/grpclb.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
@@ -11320,6 +11442,53 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_api_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
+GRPCLB_TEST_SRC = \
+ $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
+ test/cpp/grpclb/grpclb_test.cc \
+
+GRPCLB_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPCLB_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpclb_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/grpclb_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpclb_test: $(PROTOBUF_DEP) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpclb_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/lb/v1/load_balancer.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+
+deps_grpclb_test: $(GRPCLB_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPCLB_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
+
+
HYBRID_END2END_TEST_SRC = \
test/cpp/end2end/hybrid_end2end_test.cc \
diff --git a/binding.gyp b/binding.gyp
index 1dd7ee9555..9787be5dff 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -727,6 +727,7 @@
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+ 'src/core/ext/lb_policy/grpclb/grpclb.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
diff --git a/build.yaml b/build.yaml
index 37c95ccdc0..a4edb56876 100644
--- a/build.yaml
+++ b/build.yaml
@@ -376,11 +376,14 @@ filegroups:
- gpr_codegen
- name: grpc_lb_policy_grpclb
headers:
+ - src/core/ext/lb_policy/grpclb/grpclb.h
- src/core/ext/lb_policy/grpclb/load_balancer_api.h
- src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
src:
+ - src/core/ext/lb_policy/grpclb/grpclb.c
- src/core/ext/lb_policy/grpclb/load_balancer_api.c
- src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+ plugin: grpc_lb_policy_grpclb
uses:
- grpc_base
- grpc_client_config
@@ -816,6 +819,7 @@ libs:
- grpc_lb_policy_grpclb
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
+ - grpc_lb_policy_grpclb
- grpc_resolver_dns_native
- grpc_resolver_sockaddr
- grpc_load_reporting
@@ -882,6 +886,7 @@ libs:
- grpc
filegroups:
- grpc_test_util_base
+ - grpc_base
vs_project_guid: '{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}'
- name: grpc_test_util_unsecure
build: private
@@ -913,6 +918,7 @@ libs:
- grpc_lb_policy_grpclb
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
+ - grpc_lb_policy_grpclb
- census
generate_plugin_registry: true
secure: false
@@ -2750,6 +2756,20 @@ targets:
- grpc_test_util
- grpc++
- grpc
+- name: grpclb_test
+ gtest: false
+ build: test
+ language: c++
+ src:
+ - src/proto/grpc/lb/v1/load_balancer.proto
+ - test/cpp/grpclb/grpclb_test.cc
+ deps:
+ - gpr
+ - gpr_test_util
+ - grpc
+ - grpc++
+ - grpc++_test_util
+ - grpc_test_util
- name: hybrid_end2end_test
gtest: true
build: test
diff --git a/config.m4 b/config.m4
index e4e410884d..1d5e0ab2fc 100644
--- a/config.m4
+++ b/config.m4
@@ -246,6 +246,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
+ src/core/ext/lb_policy/grpclb/grpclb.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 10e9d00d70..0f8090054b 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -393,6 +393,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/subchannel_call_holder.h',
'src/core/ext/client_config/subchannel_index.h',
'src/core/ext/client_config/uri_parser.h',
+ 'src/core/ext/lb_policy/grpclb/grpclb.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
'third_party/nanopb/pb.h',
@@ -573,6 +574,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+ 'src/core/ext/lb_policy/grpclb/grpclb.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
@@ -748,6 +750,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/subchannel_call_holder.h',
'src/core/ext/client_config/subchannel_index.h',
'src/core/ext/client_config/uri_parser.h',
+ 'src/core/ext/lb_policy/grpclb/grpclb.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
'third_party/nanopb/pb.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 6b8beba907..619075171c 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -312,6 +312,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/subchannel_call_holder.h )
s.files += %w( src/core/ext/client_config/subchannel_index.h )
s.files += %w( src/core/ext/client_config/uri_parser.h )
+ s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.h )
s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.h )
s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
s.files += %w( third_party/nanopb/pb.h )
@@ -492,6 +493,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c )
s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )
s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c )
+ s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.c )
s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.c )
s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
s.files += %w( third_party/nanopb/pb_common.c )
diff --git a/package.xml b/package.xml
index f395334745..290e99e77f 100644
--- a/package.xml
+++ b/package.xml
@@ -320,6 +320,7 @@
<file baseinstalldir="/" name="src/core/ext/client_config/subchannel_call_holder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
@@ -500,6 +501,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
diff --git a/src/core/ext/client_config/lb_policy.h b/src/core/ext/client_config/lb_policy.h
index 3cfd041d3a..a2f5446fc6 100644
--- a/src/core/ext/client_config/lb_policy.h
+++ b/src/core/ext/client_config/lb_policy.h
@@ -73,7 +73,7 @@ struct grpc_lb_policy_vtable {
void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_closure *closure);
- /** try to enter a READY connectivity state */
+ /** Try to enter a READY connectivity state */
void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
/** check the current connectivity of the lb_policy */
@@ -82,7 +82,9 @@ struct grpc_lb_policy_vtable {
grpc_error **connectivity_error);
/** call notify when the connectivity state of a channel changes from *state.
- Updates *state with the new state of the policy */
+ Updates *state with the new state of the policy. Calling with a NULL \a
+ state cancels the subscription.
+ */
void (*notify_on_state_change)(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy,
grpc_connectivity_state *state,
@@ -125,7 +127,7 @@ void grpc_lb_policy_init(grpc_lb_policy *policy,
/** Given initial metadata in \a initial_metadata, find an appropriate
target for this rpc, and 'return' it by calling \a on_complete after setting
\a target.
- Picking can be asynchronous. Any IO should be done under \a pollset. */
+ Picking can be asynchronous. Any IO should be done under \a pollent. */
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_polling_entity *pollent,
grpc_metadata_batch *initial_metadata,
@@ -147,8 +149,11 @@ void grpc_lb_policy_cancel_picks(grpc_exec_ctx *exec_ctx,
uint32_t initial_metadata_flags_mask,
uint32_t initial_metadata_flags_eq);
+/** Try to enter a READY connectivity state */
void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+/* Call notify when the connectivity state of a channel changes from \a *state.
+ * Updates \a *state with the new state of the policy */
void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy,
grpc_connectivity_state *state,
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
new file mode 100644
index 0000000000..dec25efe61
--- /dev/null
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -0,0 +1,1039 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ *
+ */
+
+/** Implementation of the gRPC LB policy.
+ *
+ * This policy takes as input a set of resolved addresses {a1..an} for which the
+ * LB set was set (it's the resolver's responsibility to ensure this). That is
+ * to say, {a1..an} represent a collection of LB servers.
+ *
+ * An internal channel (\a glb_lb_policy.lb_channel) is created over {a1..an}.
+ * This channel behaves just like a regular channel. In particular, the
+ * constructed URI over the addresses a1..an will use the default pick first
+ * policy to select from this list of LB server backends.
+ *
+ * The first time the policy gets a request for a pick, a ping, or to exit the
+ * idle state, \a query_for_backends() is called. It creates an instance of \a
+ * lb_client_data, an internal struct meant to contain the data associated with
+ * the internal communication with the LB server. This instance is created via
+ * \a lb_client_data_create(). There, the call over lb_channel to pick-first
+ * from {a1..an} is created, the \a LoadBalancingRequest message is assembled
+ * and all necessary callbacks for the progress of the internal call configured.
+ *
+ * Back in \a query_for_backends(), the internal *streaming* call to the LB
+ * server (whichever address from {a1..an} pick-first chose) is kicked off.
+ * It'll progress over the callbacks configured in \a lb_client_data_create()
+ * (see the field docstrings of \a lb_client_data for more details).
+ *
+ * If the call fails with UNIMPLEMENTED, the original call will also fail.
+ * There's a misconfiguration somewhere: at least one of {a1..an} isn't a LB
+ * server, which contradicts the LB bit being set. If the internal call times
+ * out, the usual behavior of pick-first applies, continuing to pick from the
+ * list {a1..an}.
+ *
+ * Upon sucesss, a \a LoadBalancingResponse is expected in \a res_recv_cb. An
+ * invalid one results in the termination of the streaming call. A new streaming
+ * call should be created if possible, failing the original call otherwise.
+ * For a valid \a LoadBalancingResponse, the server list of actual backends is
+ * extracted. A Round Robin policy will be created from this list. There are two
+ * possible scenarios:
+ *
+ * 1. This is the first server list received. There was no previous instance of
+ * the Round Robin policy. \a rr_handover() will instantiate the RR policy
+ * and perform all the pending operations over it.
+ * 2. There's already a RR policy instance active. We need to introduce the new
+ * one build from the new serverlist, but taking care not to disrupt the
+ * operations in progress over the old RR instance. This is done by
+ * decreasing the reference count on the old policy. The moment no more
+ * references are held on the old RR policy, it'll be destroyed and \a
+ * rr_connectivity_changed notified with a \a GRPC_CHANNEL_SHUTDOWN state.
+ * At this point we can transition to a new RR instance safely, which is done
+ * once again via \a rr_handover().
+ *
+ *
+ * Once a RR policy instance is in place (and getting updated as described),
+ * calls to for a pick, a ping or a cancellation will be serviced right away by
+ * forwarding them to the RR instance. Any time there's no RR policy available
+ * (ie, right after the creation of the gRPCLB policy, if an empty serverlist
+ * is received, etc), pick/ping requests are added to a list of pending
+ * picks/pings to be flushed and serviced as part of \a rr_handover() the moment
+ * the RR policy instance becomes available.
+ *
+ * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the
+ * high level design and details. */
+
+/* TODO(dgq):
+ * - Implement LB service forwarding (point 2c. in the doc's diagram).
+ */
+
+#include <string.h>
+
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/client_config/client_channel_factory.h"
+#include "src/core/ext/client_config/lb_policy_registry.h"
+#include "src/core/ext/client_config/parse_address.h"
+#include "src/core/ext/lb_policy/grpclb/grpclb.h"
+#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
+
+int grpc_lb_glb_trace = 0;
+
+typedef struct wrapped_rr_closure_arg {
+ /* the original closure. Usually a on_complete/notify cb for pick() and ping()
+ * calls against the internal RR instance, respectively. */
+ grpc_closure *wrapped_closure;
+
+ /* The RR instance related to the closure */
+ grpc_lb_policy *rr_policy;
+
+ /* when not NULL, represents a pending_{pick,ping} node to be freed upon
+ * closure execution */
+ void *owning_pending_node; /* to be freed if not NULL */
+} wrapped_rr_closure_arg;
+
+/* The \a on_complete closure passed as part of the pick requires keeping a
+ * reference to its associated round robin instance. We wrap this closure in
+ * order to unref the round robin instance upon its invocation */
+static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ wrapped_rr_closure_arg *wc_arg = arg;
+ if (wc_arg->rr_policy != NULL) {
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")",
+ (intptr_t)wc_arg->rr_policy);
+ }
+ GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure");
+ }
+ GPR_ASSERT(wc_arg->wrapped_closure != NULL);
+ grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, error, NULL);
+ gpr_free(wc_arg->owning_pending_node);
+}
+
+/* Linked list of pending pick requests. It stores all information needed to
+ * eventually call (Round Robin's) pick() on them. They mainly stay pending
+ * waiting for the RR policy to be created/updated.
+ *
+ * One particularity is the wrapping of the user-provided \a on_complete closure
+ * (in \a wrapped_on_complete and \a wrapped_on_complete_arg). This is needed in
+ * order to correctly unref the RR policy instance upon completion of the pick.
+ * See \a wrapped_rr_closure for details. */
+typedef struct pending_pick {
+ struct pending_pick *next;
+
+ /* polling entity for the pick()'s async notification */
+ grpc_polling_entity *pollent;
+
+ /* the initial metadata for the pick. See grpc_lb_policy_pick() */
+ grpc_metadata_batch *initial_metadata;
+
+ /* bitmask passed to pick() and used for selective cancelling. See
+ * grpc_lb_policy_cancel_picks() */
+ uint32_t initial_metadata_flags;
+
+ /* output argument where to store the pick()ed connected subchannel, or NULL
+ * upon error. */
+ grpc_connected_subchannel **target;
+
+ /* a closure wrapping the original on_complete one to be invoked once the
+ * pick() has completed (regardless of success) */
+ grpc_closure wrapped_on_complete;
+
+ /* args for wrapped_on_complete */
+ wrapped_rr_closure_arg wrapped_on_complete_arg;
+} pending_pick;
+
+static void add_pending_pick(pending_pick **root, grpc_polling_entity *pollent,
+ grpc_metadata_batch *initial_metadata,
+ uint32_t initial_metadata_flags,
+ grpc_connected_subchannel **target,
+ grpc_closure *on_complete) {
+ pending_pick *pp = gpr_malloc(sizeof(*pp));
+ memset(pp, 0, sizeof(pending_pick));
+ memset(&pp->wrapped_on_complete_arg, 0, sizeof(wrapped_rr_closure_arg));
+ pp->next = *root;
+ pp->pollent = pollent;
+ pp->target = target;
+ pp->initial_metadata = initial_metadata;
+ pp->initial_metadata_flags = initial_metadata_flags;
+ pp->wrapped_on_complete_arg.wrapped_closure = on_complete;
+ grpc_closure_init(&pp->wrapped_on_complete, wrapped_rr_closure,
+ &pp->wrapped_on_complete_arg);
+ *root = pp;
+}
+
+/* Same as the \a pending_pick struct but for ping operations */
+typedef struct pending_ping {
+ struct pending_ping *next;
+
+ /* a closure wrapping the original on_complete one to be invoked once the
+ * ping() has completed (regardless of success) */
+ grpc_closure wrapped_notify;
+
+ /* args for wrapped_notify */
+ wrapped_rr_closure_arg wrapped_notify_arg;
+} pending_ping;
+
+static void add_pending_ping(pending_ping **root, grpc_closure *notify) {
+ pending_ping *pping = gpr_malloc(sizeof(*pping));
+ memset(pping, 0, sizeof(pending_ping));
+ memset(&pping->wrapped_notify_arg, 0, sizeof(wrapped_rr_closure_arg));
+ pping->next = *root;
+ grpc_closure_init(&pping->wrapped_notify, wrapped_rr_closure,
+ &pping->wrapped_notify_arg);
+ pping->wrapped_notify_arg.wrapped_closure = notify;
+ *root = pping;
+}
+
+/*
+ * glb_lb_policy
+ */
+typedef struct rr_connectivity_data rr_connectivity_data;
+struct lb_client_data;
+static const grpc_lb_policy_vtable glb_lb_policy_vtable;
+typedef struct glb_lb_policy {
+ /** base policy: must be first */
+ grpc_lb_policy base;
+
+ /** mutex protecting remaining members */
+ gpr_mu mu;
+
+ grpc_client_channel_factory *cc_factory;
+
+ /** for communicating with the LB server */
+ grpc_channel *lb_channel;
+
+ /** the RR policy to use of the backend servers returned by the LB server */
+ grpc_lb_policy *rr_policy;
+
+ bool started_picking;
+
+ /** our connectivity state tracker */
+ grpc_connectivity_state_tracker state_tracker;
+
+ /** stores the deserialized response from the LB. May be NULL until one such
+ * response has arrived. */
+ grpc_grpclb_serverlist *serverlist;
+
+ /** list of picks that are waiting on RR's policy connectivity */
+ pending_pick *pending_picks;
+
+ /** list of pings that are waiting on RR's policy connectivity */
+ pending_ping *pending_pings;
+
+ /** client data associated with the LB server communication */
+ struct lb_client_data *lb_client;
+
+ /** for tracking of the RR connectivity */
+ rr_connectivity_data *rr_connectivity;
+
+ /* a wrapped (see \a wrapped_rr_closure) on-complete closure for readily
+ * available RR picks */
+ grpc_closure wrapped_on_complete;
+
+ /* arguments for the wrapped_on_complete closure */
+ wrapped_rr_closure_arg wc_arg;
+} glb_lb_policy;
+
+/* Keeps track and reacts to changes in connectivity of the RR instance */
+struct rr_connectivity_data {
+ grpc_closure on_change;
+ grpc_connectivity_state state;
+ glb_lb_policy *glb_policy;
+};
+
+static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx,
+ const grpc_grpclb_serverlist *serverlist,
+ glb_lb_policy *glb_policy) {
+ /* TODO(dgq): support mixed ip version */
+ GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0);
+ char **host_ports = gpr_malloc(sizeof(char *) * serverlist->num_servers);
+ for (size_t i = 0; i < serverlist->num_servers; ++i) {
+ gpr_join_host_port(&host_ports[i], serverlist->servers[i]->ip_address,
+ serverlist->servers[i]->port);
+ }
+
+ size_t uri_path_len;
+ char *concat_ipports = gpr_strjoin_sep(
+ (const char **)host_ports, serverlist->num_servers, ",", &uri_path_len);
+
+ grpc_lb_policy_args args;
+ args.client_channel_factory = glb_policy->cc_factory;
+ args.addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
+ args.addresses->naddrs = serverlist->num_servers;
+ args.addresses->addrs =
+ gpr_malloc(sizeof(grpc_resolved_address) * args.addresses->naddrs);
+ size_t out_addrs_idx = 0;
+ for (size_t i = 0; i < serverlist->num_servers; ++i) {
+ grpc_uri uri;
+ struct sockaddr_storage sa;
+ size_t sa_len;
+ uri.path = host_ports[i];
+ if (parse_ipv4(&uri, &sa, &sa_len)) { /* TODO(dgq): add support for ipv6 */
+ memcpy(args.addresses->addrs[out_addrs_idx].addr, &sa, sa_len);
+ args.addresses->addrs[out_addrs_idx].len = sa_len;
+ ++out_addrs_idx;
+ } else {
+ gpr_log(GPR_ERROR, "Invalid LB service address '%s', ignoring.",
+ host_ports[i]);
+ }
+ }
+
+ grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args);
+
+ gpr_free(concat_ipports);
+ for (size_t i = 0; i < serverlist->num_servers; i++) {
+ gpr_free(host_ports[i]);
+ }
+ gpr_free(host_ports);
+ gpr_free(args.addresses->addrs);
+ gpr_free(args.addresses);
+ return rr;
+}
+
+static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
+ grpc_error *error) {
+ GRPC_ERROR_REF(error);
+ glb_policy->rr_policy =
+ create_rr(exec_ctx, glb_policy->serverlist, glb_policy);
+
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "Created RR policy (0x%" PRIxPTR ")",
+ (intptr_t)glb_policy->rr_policy);
+ }
+ GPR_ASSERT(glb_policy->rr_policy != NULL);
+ glb_policy->rr_connectivity->state = grpc_lb_policy_check_connectivity(
+ exec_ctx, glb_policy->rr_policy, &error);
+ grpc_lb_policy_notify_on_state_change(
+ exec_ctx, glb_policy->rr_policy, &glb_policy->rr_connectivity->state,
+ &glb_policy->rr_connectivity->on_change);
+ grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
+ glb_policy->rr_connectivity->state, error,
+ "rr_handover");
+ grpc_lb_policy_exit_idle(exec_ctx, glb_policy->rr_policy);
+
+ /* flush pending ops */
+ pending_pick *pp;
+ while ((pp = glb_policy->pending_picks)) {
+ glb_policy->pending_picks = pp->next;
+ GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_pick");
+ pp->wrapped_on_complete_arg.rr_policy = glb_policy->rr_policy;
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "",
+ (intptr_t)glb_policy->rr_policy);
+ }
+ grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, pp->pollent,
+ pp->initial_metadata, pp->initial_metadata_flags,
+ pp->target, &pp->wrapped_on_complete);
+ pp->wrapped_on_complete_arg.owning_pending_node = pp;
+ }
+
+ pending_ping *pping;
+ while ((pping = glb_policy->pending_pings)) {
+ glb_policy->pending_pings = pping->next;
+ GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_ping");
+ pping->wrapped_notify_arg.rr_policy = glb_policy->rr_policy;
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "Pending ping about to PING from 0x%" PRIxPTR "",
+ (intptr_t)glb_policy->rr_policy);
+ }
+ grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy,
+ &pping->wrapped_notify);
+ pping->wrapped_notify_arg.owning_pending_node = pping;
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ rr_connectivity_data *rr_conn_data = arg;
+ glb_lb_policy *glb_policy = rr_conn_data->glb_policy;
+ if (rr_conn_data->state == GRPC_CHANNEL_SHUTDOWN) {
+ if (glb_policy->serverlist != NULL) {
+ /* a RR policy is shutting down but there's a serverlist available ->
+ * perform a handover */
+ rr_handover(exec_ctx, glb_policy, error);
+ } else {
+ /* shutting down and no new serverlist available. Bail out. */
+ gpr_free(rr_conn_data);
+ }
+ } else {
+ if (error == GRPC_ERROR_NONE) {
+ /* RR not shutting down. Mimic the RR's policy state */
+ grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
+ rr_conn_data->state, error,
+ "rr_connectivity_changed");
+ /* resubscribe */
+ grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy,
+ &rr_conn_data->state,
+ &rr_conn_data->on_change);
+ } else { /* error */
+ gpr_free(rr_conn_data);
+ }
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
+ grpc_lb_policy_factory *factory,
+ grpc_lb_policy_args *args) {
+ glb_lb_policy *glb_policy = gpr_malloc(sizeof(*glb_policy));
+ memset(glb_policy, 0, sizeof(*glb_policy));
+
+ /* All input addresses in args->addresses come from a resolver that claims
+ * they are LB services. It's the resolver's responsibility to make sure this
+ * policy is only instantiated and used in that case.
+ *
+ * Create a client channel over them to communicate with a LB service */
+ glb_policy->cc_factory = args->client_channel_factory;
+ GPR_ASSERT(glb_policy->cc_factory != NULL);
+ if (args->addresses->naddrs == 0) {
+ return NULL;
+ }
+
+ /* construct a target from the args->addresses, in the form
+ * ipvX://ip1:port1,ip2:port2,...
+ * TODO(dgq): support mixed ip version */
+ char **addr_strs = gpr_malloc(sizeof(char *) * args->addresses->naddrs);
+ addr_strs[0] =
+ grpc_sockaddr_to_uri((const struct sockaddr *)&args->addresses->addrs[0]);
+ for (size_t i = 1; i < args->addresses->naddrs; i++) {
+ GPR_ASSERT(grpc_sockaddr_to_string(
+ &addr_strs[i],
+ (const struct sockaddr *)&args->addresses->addrs[i],
+ true) == 0);
+ }
+ size_t uri_path_len;
+ char *target_uri_str = gpr_strjoin_sep(
+ (const char **)addr_strs, args->addresses->naddrs, ",", &uri_path_len);
+
+ /* will pick using pick_first */
+ glb_policy->lb_channel = grpc_client_channel_factory_create_channel(
+ exec_ctx, glb_policy->cc_factory, target_uri_str,
+ GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, NULL);
+
+ gpr_free(target_uri_str);
+ for (size_t i = 0; i < args->addresses->naddrs; i++) {
+ gpr_free(addr_strs[i]);
+ }
+ gpr_free(addr_strs);
+
+ if (glb_policy->lb_channel == NULL) {
+ gpr_free(glb_policy);
+ return NULL;
+ }
+
+ rr_connectivity_data *rr_connectivity =
+ gpr_malloc(sizeof(rr_connectivity_data));
+ memset(rr_connectivity, 0, sizeof(rr_connectivity_data));
+ grpc_closure_init(&rr_connectivity->on_change, rr_connectivity_changed,
+ rr_connectivity);
+ rr_connectivity->glb_policy = glb_policy;
+ glb_policy->rr_connectivity = rr_connectivity;
+
+ grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable);
+ gpr_mu_init(&glb_policy->mu);
+ grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE,
+ "grpclb");
+ return &glb_policy->base;
+}
+
+static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ GPR_ASSERT(glb_policy->pending_picks == NULL);
+ GPR_ASSERT(glb_policy->pending_pings == NULL);
+ grpc_channel_destroy(glb_policy->lb_channel);
+ glb_policy->lb_channel = NULL;
+ grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker);
+ if (glb_policy->serverlist != NULL) {
+ grpc_grpclb_destroy_serverlist(glb_policy->serverlist);
+ }
+ gpr_mu_destroy(&glb_policy->mu);
+ gpr_free(glb_policy);
+}
+
+static void lb_client_data_destroy(struct lb_client_data *lb_client);
+static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+
+ pending_pick *pp = glb_policy->pending_picks;
+ glb_policy->pending_picks = NULL;
+ pending_ping *pping = glb_policy->pending_pings;
+ glb_policy->pending_pings = NULL;
+ gpr_mu_unlock(&glb_policy->mu);
+
+ while (pp != NULL) {
+ pending_pick *next = pp->next;
+ *pp->target = NULL;
+ grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete, GRPC_ERROR_NONE,
+ NULL);
+ gpr_free(pp);
+ pp = next;
+ }
+
+ while (pping != NULL) {
+ pending_ping *next = pping->next;
+ grpc_exec_ctx_sched(exec_ctx, &pping->wrapped_notify, GRPC_ERROR_NONE,
+ NULL);
+ pping = next;
+ }
+
+ if (glb_policy->rr_policy) {
+ /* unsubscribe */
+ grpc_lb_policy_notify_on_state_change(
+ exec_ctx, glb_policy->rr_policy, NULL,
+ &glb_policy->rr_connectivity->on_change);
+ GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
+ }
+
+ lb_client_data_destroy(glb_policy->lb_client);
+ glb_policy->lb_client = NULL;
+
+ grpc_connectivity_state_set(
+ exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown");
+}
+
+static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ grpc_connected_subchannel **target) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+ pending_pick *pp = glb_policy->pending_picks;
+ glb_policy->pending_picks = NULL;
+ while (pp != NULL) {
+ pending_pick *next = pp->next;
+ if (pp->target == target) {
+ grpc_polling_entity_del_from_pollset_set(
+ exec_ctx, pp->pollent, glb_policy->base.interested_parties);
+ *target = NULL;
+ grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete,
+ GRPC_ERROR_CANCELLED, NULL);
+ gpr_free(pp);
+ } else {
+ pp->next = glb_policy->pending_picks;
+ glb_policy->pending_picks = pp;
+ }
+ pp = next;
+ }
+ gpr_mu_unlock(&glb_policy->mu);
+}
+
+static grpc_call *lb_client_data_get_call(struct lb_client_data *lb_client);
+static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ uint32_t initial_metadata_flags_mask,
+ uint32_t initial_metadata_flags_eq) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+ if (glb_policy->lb_client != NULL) {
+ /* cancel the call to the load balancer service, if any */
+ grpc_call_cancel(lb_client_data_get_call(glb_policy->lb_client), NULL);
+ }
+ pending_pick *pp = glb_policy->pending_picks;
+ glb_policy->pending_picks = NULL;
+ while (pp != NULL) {
+ pending_pick *next = pp->next;
+ if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
+ initial_metadata_flags_eq) {
+ grpc_polling_entity_del_from_pollset_set(
+ exec_ctx, pp->pollent, glb_policy->base.interested_parties);
+ grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete,
+ GRPC_ERROR_CANCELLED, NULL);
+ gpr_free(pp);
+ } else {
+ pp->next = glb_policy->pending_picks;
+ glb_policy->pending_picks = pp;
+ }
+ pp = next;
+ }
+ gpr_mu_unlock(&glb_policy->mu);
+}
+
+static void query_for_backends(grpc_exec_ctx *exec_ctx,
+ glb_lb_policy *glb_policy);
+static void start_picking(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy) {
+ glb_policy->started_picking = true;
+ query_for_backends(exec_ctx, glb_policy);
+}
+
+static void glb_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+ if (!glb_policy->started_picking) {
+ start_picking(exec_ctx, glb_policy);
+ }
+ gpr_mu_unlock(&glb_policy->mu);
+}
+
+static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ grpc_polling_entity *pollent,
+ grpc_metadata_batch *initial_metadata,
+ uint32_t initial_metadata_flags,
+ grpc_connected_subchannel **target,
+ grpc_closure *on_complete) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+ int r;
+
+ if (glb_policy->rr_policy != NULL) {
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "about to PICK from 0x%" PRIxPTR "",
+ (intptr_t)glb_policy->rr_policy);
+ }
+ GRPC_LB_POLICY_REF(glb_policy->rr_policy, "glb_pick");
+ memset(&glb_policy->wc_arg, 0, sizeof(wrapped_rr_closure_arg));
+ glb_policy->wc_arg.rr_policy = glb_policy->rr_policy;
+ glb_policy->wc_arg.wrapped_closure = on_complete;
+ grpc_closure_init(&glb_policy->wrapped_on_complete, wrapped_rr_closure,
+ &glb_policy->wc_arg);
+ r = grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, pollent,
+ initial_metadata, initial_metadata_flags, target,
+ &glb_policy->wrapped_on_complete);
+ if (r != 0) {
+ /* the call to grpc_lb_policy_pick has been sychronous. Unreffing the RR
+ * policy and notify the original callback */
+ glb_policy->wc_arg.wrapped_closure = NULL;
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")",
+ (intptr_t)glb_policy->wc_arg.rr_policy);
+ }
+ GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->wc_arg.rr_policy, "glb_pick");
+ grpc_exec_ctx_sched(exec_ctx, glb_policy->wc_arg.wrapped_closure,
+ GRPC_ERROR_NONE, NULL);
+ }
+ } else {
+ grpc_polling_entity_add_to_pollset_set(exec_ctx, pollent,
+ glb_policy->base.interested_parties);
+ add_pending_pick(&glb_policy->pending_picks, pollent, initial_metadata,
+ initial_metadata_flags, target, on_complete);
+
+ if (!glb_policy->started_picking) {
+ start_picking(exec_ctx, glb_policy);
+ }
+ r = 0;
+ }
+ gpr_mu_unlock(&glb_policy->mu);
+ return r;
+}
+
+static grpc_connectivity_state glb_check_connectivity(
+ grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ grpc_error **connectivity_error) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ grpc_connectivity_state st;
+ gpr_mu_lock(&glb_policy->mu);
+ st = grpc_connectivity_state_check(&glb_policy->state_tracker,
+ connectivity_error);
+ gpr_mu_unlock(&glb_policy->mu);
+ return st;
+}
+
+static void glb_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ grpc_closure *closure) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+ if (glb_policy->rr_policy) {
+ grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy, closure);
+ } else {
+ add_pending_ping(&glb_policy->pending_pings, closure);
+ if (!glb_policy->started_picking) {
+ start_picking(exec_ctx, glb_policy);
+ }
+ }
+ gpr_mu_unlock(&glb_policy->mu);
+}
+
+static void glb_notify_on_state_change(grpc_exec_ctx *exec_ctx,
+ grpc_lb_policy *pol,
+ grpc_connectivity_state *current,
+ grpc_closure *notify) {
+ glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+ gpr_mu_lock(&glb_policy->mu);
+ grpc_connectivity_state_notify_on_state_change(
+ exec_ctx, &glb_policy->state_tracker, current, notify);
+
+ gpr_mu_unlock(&glb_policy->mu);
+}
+
+/*
+ * lb_client_data
+ *
+ * Used internally for the client call to the LB */
+typedef struct lb_client_data {
+ gpr_mu mu;
+
+ /* called once initial metadata's been sent */
+ grpc_closure md_sent;
+
+ /* called once initial metadata's been received */
+ grpc_closure md_rcvd;
+
+ /* called once the LoadBalanceRequest has been sent to the LB server. See
+ * src/proto/grpc/.../load_balancer.proto */
+ grpc_closure req_sent;
+
+ /* A response from the LB server has been received (or error). Process it */
+ grpc_closure res_rcvd;
+
+ /* After the client has sent a close to the LB server */
+ grpc_closure close_sent;
+
+ /* ... and the status from the LB server has been received */
+ grpc_closure srv_status_rcvd;
+
+ grpc_call *lb_call; /* streaming call to the LB server, */
+ gpr_timespec deadline; /* for the streaming call to the LB server */
+
+ grpc_metadata_array initial_metadata_recv; /* initial MD from LB server */
+ grpc_metadata_array trailing_metadata_recv; /* trailing MD from LB server */
+
+ /* what's being sent to the LB server. Note that its value may vary if the LB
+ * server indicates a redirect. */
+ grpc_byte_buffer *request_payload;
+
+ /* response from the LB server, if any. Processed in res_recv_cb() */
+ grpc_byte_buffer *response_payload;
+
+ /* the call's status and status detailset in srv_status_rcvd_cb() */
+ grpc_status_code status;
+ char *status_details;
+ size_t status_details_capacity;
+
+ /* pointer back to the enclosing policy */
+ glb_lb_policy *glb_policy;
+} lb_client_data;
+
+static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error);
+static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error);
+
+static lb_client_data *lb_client_data_create(glb_lb_policy *glb_policy) {
+ lb_client_data *lb_client = gpr_malloc(sizeof(lb_client_data));
+ memset(lb_client, 0, sizeof(lb_client_data));
+
+ gpr_mu_init(&lb_client->mu);
+ grpc_closure_init(&lb_client->md_sent, md_sent_cb, lb_client);
+
+ grpc_closure_init(&lb_client->md_rcvd, md_recv_cb, lb_client);
+ grpc_closure_init(&lb_client->req_sent, req_sent_cb, lb_client);
+ grpc_closure_init(&lb_client->res_rcvd, res_recv_cb, lb_client);
+ grpc_closure_init(&lb_client->close_sent, close_sent_cb, lb_client);
+ grpc_closure_init(&lb_client->srv_status_rcvd, srv_status_rcvd_cb, lb_client);
+
+ /* TODO(dgq): get the deadline from the client config instead of fabricating
+ * one here. */
+ lb_client->deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_seconds(3, GPR_TIMESPAN));
+
+ lb_client->lb_call = grpc_channel_create_pollset_set_call(
+ glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+ glb_policy->base.interested_parties, "/BalanceLoad",
+ NULL, /* FIXME(dgq): which "host" value to use? */
+ lb_client->deadline, NULL);
+
+ grpc_metadata_array_init(&lb_client->initial_metadata_recv);
+ grpc_metadata_array_init(&lb_client->trailing_metadata_recv);
+
+ grpc_grpclb_request *request = grpc_grpclb_request_create(
+ "load.balanced.service.name"); /* FIXME(dgq): get the name of the load
+ balanced service from the resolver */
+ gpr_slice request_payload_slice = grpc_grpclb_request_encode(request);
+ lb_client->request_payload =
+ grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+ gpr_slice_unref(request_payload_slice);
+ grpc_grpclb_request_destroy(request);
+
+ lb_client->status_details = NULL;
+ lb_client->status_details_capacity = 0;
+ lb_client->glb_policy = glb_policy;
+ return lb_client;
+}
+
+static void lb_client_data_destroy(lb_client_data *lb_client) {
+ grpc_call_destroy(lb_client->lb_call);
+ grpc_metadata_array_destroy(&lb_client->initial_metadata_recv);
+ grpc_metadata_array_destroy(&lb_client->trailing_metadata_recv);
+
+ grpc_byte_buffer_destroy(lb_client->request_payload);
+
+ gpr_free(lb_client->status_details);
+ gpr_mu_destroy(&lb_client->mu);
+ gpr_free(lb_client);
+}
+static grpc_call *lb_client_data_get_call(lb_client_data *lb_client) {
+ return lb_client->lb_call;
+}
+
+/*
+ * Auxiliary functions and LB client callbacks.
+ */
+static void query_for_backends(grpc_exec_ctx *exec_ctx,
+ glb_lb_policy *glb_policy) {
+ GPR_ASSERT(glb_policy->lb_channel != NULL);
+
+ glb_policy->lb_client = lb_client_data_create(glb_policy);
+ grpc_call_error call_error;
+ grpc_op ops[1];
+ memset(ops, 0, sizeof(ops));
+ grpc_op *op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, glb_policy->lb_client->lb_call, ops, (size_t)(op - ops),
+ &glb_policy->lb_client->md_sent);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+
+ op = ops;
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata =
+ &glb_policy->lb_client->trailing_metadata_recv;
+ op->data.recv_status_on_client.status = &glb_policy->lb_client->status;
+ op->data.recv_status_on_client.status_details =
+ &glb_policy->lb_client->status_details;
+ op->data.recv_status_on_client.status_details_capacity =
+ &glb_policy->lb_client->status_details_capacity;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, glb_policy->lb_client->lb_call, ops, (size_t)(op - ops),
+ &glb_policy->lb_client->srv_status_rcvd);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ lb_client_data *lb_client = arg;
+ GPR_ASSERT(lb_client->lb_call);
+ grpc_op ops[1];
+ memset(ops, 0, sizeof(ops));
+ grpc_op *op = ops;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata = &lb_client->initial_metadata_recv;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+ &lb_client->md_rcvd);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ lb_client_data *lb_client = arg;
+ GPR_ASSERT(lb_client->lb_call);
+ grpc_op ops[1];
+ memset(ops, 0, sizeof(ops));
+ grpc_op *op = ops;
+
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message = lb_client->request_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+ &lb_client->req_sent);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ lb_client_data *lb_client = arg;
+
+ grpc_op ops[1];
+ memset(ops, 0, sizeof(ops));
+ grpc_op *op = ops;
+
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message = &lb_client->response_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+ &lb_client->res_rcvd);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ lb_client_data *lb_client = arg;
+ grpc_op ops[2];
+ memset(ops, 0, sizeof(ops));
+ grpc_op *op = ops;
+ if (lb_client->response_payload != NULL) {
+ /* Received data from the LB server. Look inside
+ * lb_client->response_payload, for
+ * a serverlist. */
+ grpc_byte_buffer_reader bbr;
+ grpc_byte_buffer_reader_init(&bbr, lb_client->response_payload);
+ gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
+ grpc_byte_buffer_destroy(lb_client->response_payload);
+ grpc_grpclb_serverlist *serverlist =
+ grpc_grpclb_response_parse_serverlist(response_slice);
+ if (serverlist != NULL) {
+ gpr_slice_unref(response_slice);
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO, "Serverlist with %zu servers received",
+ serverlist->num_servers);
+ }
+
+ /* update serverlist */
+ if (serverlist->num_servers > 0) {
+ if (grpc_grpclb_serverlist_equals(lb_client->glb_policy->serverlist,
+ serverlist)) {
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO,
+ "Incoming server list identical to current, ignoring.");
+ }
+ } else { /* new serverlist */
+ if (lb_client->glb_policy->serverlist != NULL) {
+ /* dispose of the old serverlist */
+ grpc_grpclb_destroy_serverlist(lb_client->glb_policy->serverlist);
+ }
+ /* and update the copy in the glb_lb_policy instance */
+ lb_client->glb_policy->serverlist = serverlist;
+ }
+ if (lb_client->glb_policy->rr_policy == NULL) {
+ /* initial "handover", in this case from a null RR policy, meaning
+ * it'll just create the first RR policy instance */
+ rr_handover(exec_ctx, lb_client->glb_policy, error);
+ } else {
+ /* unref the RR policy, eventually leading to its substitution with a
+ * new one constructed from the received serverlist (see
+ * rr_connectivity_changed) */
+ GRPC_LB_POLICY_UNREF(exec_ctx, lb_client->glb_policy->rr_policy,
+ "serverlist_received");
+ }
+ } else {
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO,
+ "Received empty server list. Picks will stay pending until a "
+ "response with > 0 servers is received");
+ }
+ }
+
+ /* keep listening for serverlist updates */
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message = &lb_client->response_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ const grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+ &lb_client->res_rcvd); /* loop */
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+ return;
+ }
+
+ GPR_ASSERT(serverlist == NULL);
+ gpr_log(GPR_ERROR, "Invalid LB response received: '%s'",
+ gpr_dump_slice(response_slice, GPR_DUMP_ASCII));
+ gpr_slice_unref(response_slice);
+
+ /* Disconnect from server returning invalid response. */
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+ &lb_client->close_sent);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+ }
+ /* empty payload: call cancelled by server. Cleanups happening in
+ * srv_status_rcvd_cb */
+}
+
+static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO,
+ "Close from LB client sent. Waiting from server status now");
+ }
+}
+
+static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ lb_client_data *lb_client = arg;
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO,
+ "status from lb server received. Status = %d, Details = '%s', "
+ "Capaticy "
+ "= %zu",
+ lb_client->status, lb_client->status_details,
+ lb_client->status_details_capacity);
+ }
+ /* TODO(dgq): deal with stream termination properly (fire up another one? fail
+ * the original call?) */
+}
+
+/* Code wiring the policy with the rest of the core */
+static const grpc_lb_policy_vtable glb_lb_policy_vtable = {
+ glb_destroy, glb_shutdown, glb_pick,
+ glb_cancel_pick, glb_cancel_picks, glb_ping_one,
+ glb_exit_idle, glb_check_connectivity, glb_notify_on_state_change};
+
+static void glb_factory_ref(grpc_lb_policy_factory *factory) {}
+
+static void glb_factory_unref(grpc_lb_policy_factory *factory) {}
+
+static const grpc_lb_policy_factory_vtable glb_factory_vtable = {
+ glb_factory_ref, glb_factory_unref, glb_create, "grpclb"};
+
+static grpc_lb_policy_factory glb_lb_policy_factory = {&glb_factory_vtable};
+
+grpc_lb_policy_factory *grpc_glb_lb_factory_create() {
+ return &glb_lb_policy_factory;
+}
+
+/* Plugin registration */
+void grpc_lb_policy_grpclb_init() {
+ grpc_register_lb_policy(grpc_glb_lb_factory_create());
+ grpc_register_tracer("glb", &grpc_lb_glb_trace);
+}
+
+void grpc_lb_policy_grpclb_shutdown() {}
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.h b/src/core/ext/lb_policy/grpclb/grpclb.h
new file mode 100644
index 0000000000..83552b4fa0
--- /dev/null
+++ b/src/core/ext/lb_policy/grpclb/grpclb.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H
+#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H
+
+#include "src/core/ext/client_config/lb_policy_factory.h"
+
+/** Returns a load balancing factory for the glb policy, which tries to connect
+ * to a load balancing server to decide the next successfully connected
+ * subchannel to pick. */
+grpc_lb_policy_factory *grpc_glb_lb_factory_create();
+
+#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H */
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
index 59b89997dd..f4720a1345 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.c
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
@@ -38,9 +38,15 @@
#include <grpc/support/alloc.h>
typedef struct decode_serverlist_arg {
- int first_pass;
- int i;
+ /* The first pass counts the number of servers in the server list. The second
+ * one allocates and decodes. */
+ bool first_pass;
+ /* The decoding callback is invoked once per server in serverlist. Remember
+ * which index of the serverlist are we currently decoding */
+ size_t decoding_idx;
+ /* Populated after the first pass. Number of server in the input serverlist */
size_t num_servers;
+ /* The decoded serverlist */
grpc_grpclb_server **servers;
} decode_serverlist_arg;
@@ -48,23 +54,24 @@ typedef struct decode_serverlist_arg {
static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
void **arg) {
decode_serverlist_arg *dec_arg = *arg;
- if (dec_arg->first_pass != 0) { /* first pass */
+ if (dec_arg->first_pass) { /* count how many server do we have */
grpc_grpclb_server server;
if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) {
return false;
}
dec_arg->num_servers++;
- } else { /* second pass */
+ } else { /* second pass. Actually decode. */
grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server));
+ memset(server, 0, sizeof(grpc_grpclb_server));
GPR_ASSERT(dec_arg->num_servers > 0);
- if (dec_arg->i == 0) { /* first iteration of second pass */
+ if (dec_arg->decoding_idx == 0) { /* first iteration of second pass */
dec_arg->servers =
gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers);
}
if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) {
return false;
}
- dec_arg->servers[dec_arg->i++] = server;
+ dec_arg->servers[dec_arg->decoding_idx++] = server;
}
return true;
@@ -102,57 +109,59 @@ void grpc_grpclb_request_destroy(grpc_grpclb_request *request) {
gpr_free(request);
}
-grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) {
- bool status;
+typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response;
+grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
+ gpr_slice encoded_grpc_grpclb_response) {
pb_istream_t stream =
- pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
- GPR_SLICE_LENGTH(encoded_response));
- grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
- memset(res, 0, sizeof(*res));
- status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, res);
- if (!status) {
- grpc_grpclb_response_destroy(res);
+ pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_grpc_grpclb_response),
+ GPR_SLICE_LENGTH(encoded_grpc_grpclb_response));
+ grpc_grpclb_response res;
+ memset(&res, 0, sizeof(grpc_grpclb_response));
+ if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) {
return NULL;
}
- return res;
+ grpc_grpclb_initial_response *initial_res =
+ gpr_malloc(sizeof(grpc_grpclb_initial_response));
+ memcpy(initial_res, &res.initial_response,
+ sizeof(grpc_grpclb_initial_response));
+
+ return initial_res;
}
grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
- gpr_slice encoded_response) {
+ gpr_slice encoded_grpc_grpclb_response) {
bool status;
decode_serverlist_arg arg;
pb_istream_t stream =
- pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
- GPR_SLICE_LENGTH(encoded_response));
+ pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_grpc_grpclb_response),
+ GPR_SLICE_LENGTH(encoded_grpc_grpclb_response));
pb_istream_t stream_at_start = stream;
- grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
- memset(res, 0, sizeof(*res));
+ grpc_grpclb_response res;
+ memset(&res, 0, sizeof(grpc_grpclb_response));
memset(&arg, 0, sizeof(decode_serverlist_arg));
- res->server_list.servers.funcs.decode = decode_serverlist;
- res->server_list.servers.arg = &arg;
- arg.first_pass = 1;
- status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, res);
+ res.server_list.servers.funcs.decode = decode_serverlist;
+ res.server_list.servers.arg = &arg;
+ arg.first_pass = true;
+ status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res);
if (!status) {
- grpc_grpclb_response_destroy(res);
return NULL;
}
- arg.first_pass = 0;
+ arg.first_pass = false;
status =
- pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, res);
+ pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, &res);
if (!status) {
- grpc_grpclb_response_destroy(res);
return NULL;
}
grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist));
+ memset(sl, 0, sizeof(*sl));
sl->num_servers = arg.num_servers;
sl->servers = arg.servers;
- if (res->server_list.has_expiration_interval) {
- sl->expiration_interval = res->server_list.expiration_interval;
+ if (res.server_list.has_expiration_interval) {
+ sl->expiration_interval = res.server_list.expiration_interval;
}
- grpc_grpclb_response_destroy(res);
return sl;
}
@@ -167,6 +176,72 @@ void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) {
gpr_free(serverlist);
}
-void grpc_grpclb_response_destroy(grpc_grpclb_response *response) {
+grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy(
+ const grpc_grpclb_serverlist *sl) {
+ grpc_grpclb_serverlist *copy = gpr_malloc(sizeof(grpc_grpclb_serverlist));
+ memset(copy, 0, sizeof(grpc_grpclb_serverlist));
+ copy->num_servers = sl->num_servers;
+ memcpy(&copy->expiration_interval, &sl->expiration_interval,
+ sizeof(grpc_grpclb_duration));
+ copy->servers = gpr_malloc(sizeof(grpc_grpclb_server *) * sl->num_servers);
+ for (size_t i = 0; i < sl->num_servers; i++) {
+ copy->servers[i] = gpr_malloc(sizeof(grpc_grpclb_server));
+ memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server));
+ }
+ return copy;
+}
+
+bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs,
+ const grpc_grpclb_serverlist *rhs) {
+ if ((lhs == NULL) || (rhs == NULL)) {
+ return false;
+ }
+ if (lhs->num_servers != rhs->num_servers) {
+ return false;
+ }
+ if (grpc_grpclb_duration_compare(&lhs->expiration_interval,
+ &rhs->expiration_interval) != 0) {
+ return false;
+ }
+ for (size_t i = 0; i < lhs->num_servers; i++) {
+ if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs,
+ const grpc_grpclb_server *rhs) {
+ return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0;
+}
+
+int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs,
+ const grpc_grpclb_duration *rhs) {
+ GPR_ASSERT(lhs && rhs);
+ if (lhs->has_seconds && rhs->has_seconds) {
+ if (lhs->seconds < rhs->seconds) return -1;
+ if (lhs->seconds > rhs->seconds) return 1;
+ } else if (lhs->has_seconds) {
+ return 1;
+ } else if (rhs->has_seconds) {
+ return -1;
+ }
+
+ GPR_ASSERT(lhs->seconds == rhs->seconds);
+ if (lhs->has_nanos && rhs->has_nanos) {
+ if (lhs->nanos < rhs->nanos) return -1;
+ if (lhs->nanos > rhs->nanos) return 1;
+ } else if (lhs->has_nanos) {
+ return 1;
+ } else if (rhs->has_nanos) {
+ return -1;
+ }
+
+ return 0;
+}
+
+void grpc_grpclb_initial_response_destroy(
+ grpc_grpclb_initial_response *response) {
gpr_free(response);
}
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
index 71b5616d0c..9726c87a37 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
@@ -46,7 +46,7 @@ extern "C" {
#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128
typedef grpc_lb_v1_LoadBalanceRequest grpc_grpclb_request;
-typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response;
+typedef grpc_lb_v1_InitialLoadBalanceResponse grpc_grpclb_initial_response;
typedef grpc_lb_v1_Server grpc_grpclb_server;
typedef grpc_lb_v1_Duration grpc_grpclb_duration;
typedef struct grpc_grpclb_serverlist {
@@ -64,19 +64,37 @@ gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request);
/** Destroy \a request */
void grpc_grpclb_request_destroy(grpc_grpclb_request *request);
-/** Parse (ie, decode) the bytes in \a encoded_response as a \a
- * grpc_grpclb_response */
-grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response);
+/** Parse (ie, decode) the bytes in \a encoded_grpc_grpclb_response as a \a
+ * grpc_grpclb_initial_response */
+grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
+ gpr_slice encoded_grpc_grpclb_response);
+
+/** Parse the list of servers from an encoded \a grpc_grpclb_response */
+grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
+ gpr_slice encoded_grpc_grpclb_response);
+
+/** Return a copy of \a sl. The caller is responsible for calling \a
+ * grpc_grpclb_destroy_serverlist on the returned copy. */
+grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy(
+ const grpc_grpclb_serverlist *sl);
+
+bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs,
+ const grpc_grpclb_serverlist *rhs);
+
+bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs,
+ const grpc_grpclb_server *rhs);
/** Destroy \a serverlist */
void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist);
-/** Parse the list of servers from an encoded \a grpc_grpclb_response */
-grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
- gpr_slice encoded_response);
+/** Compare \a lhs against \a rhs and return 0 if \a lhs and \a rhs are equal,
+ * < 0 if \a lhs represents a duration shorter than \a rhs and > 0 otherwise */
+int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs,
+ const grpc_grpclb_duration *rhs);
-/** Destroy \a response */
-void grpc_grpclb_response_destroy(grpc_grpclb_response *response);
+/** Destroy \a initial_response */
+void grpc_grpclb_initial_response_destroy(
+ grpc_grpclb_initial_response *response);
#ifdef __cplusplus
}
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index ec21e03944..974d5ae479 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -284,7 +284,7 @@ static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
}
/* returns true if done, false if pending; if returning true, *error is set */
-#define MAX_WRITE_IOVEC 1024
+#define MAX_WRITE_IOVEC 1000
static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC];
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 70c94791f8..59295f47f0 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -1367,6 +1367,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
int num_completion_callbacks_needed = 1;
grpc_call_error error = GRPC_CALL_OK;
+ // sent_initial_metadata guards against variable reuse.
+ grpc_metadata compression_md;
+
GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
@@ -1412,8 +1415,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
goto done_with_error;
}
/* process compression level */
- grpc_metadata compression_md;
- memset(&compression_md, 0, sizeof(grpc_metadata));
+ memset(&compression_md, 0, sizeof(compression_md));
size_t additional_metadata_count = 0;
grpc_compression_level effective_compression_level;
bool level_set = false;
diff --git a/src/core/plugin_registry/grpc_plugin_registry.c b/src/core/plugin_registry/grpc_plugin_registry.c
index 905cd59e23..7a7a9ce477 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_plugin_registry.c
@@ -37,6 +37,8 @@ extern void grpc_chttp2_plugin_init(void);
extern void grpc_chttp2_plugin_shutdown(void);
extern void grpc_client_config_init(void);
extern void grpc_client_config_shutdown(void);
+extern void grpc_lb_policy_grpclb_init(void);
+extern void grpc_lb_policy_grpclb_shutdown(void);
extern void grpc_lb_policy_pick_first_init(void);
extern void grpc_lb_policy_pick_first_shutdown(void);
extern void grpc_lb_policy_round_robin_init(void);
@@ -55,6 +57,8 @@ void grpc_register_built_in_plugins(void) {
grpc_chttp2_plugin_shutdown);
grpc_register_plugin(grpc_client_config_init,
grpc_client_config_shutdown);
+ grpc_register_plugin(grpc_lb_policy_grpclb_init,
+ grpc_lb_policy_grpclb_shutdown);
grpc_register_plugin(grpc_lb_policy_pick_first_init,
grpc_lb_policy_pick_first_shutdown);
grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
index 7995078725..ad4ddf0ff4 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
@@ -43,6 +43,8 @@ extern void grpc_resolver_sockaddr_init(void);
extern void grpc_resolver_sockaddr_shutdown(void);
extern void grpc_load_reporting_plugin_init(void);
extern void grpc_load_reporting_plugin_shutdown(void);
+extern void grpc_lb_policy_grpclb_init(void);
+extern void grpc_lb_policy_grpclb_shutdown(void);
extern void grpc_lb_policy_pick_first_init(void);
extern void grpc_lb_policy_pick_first_shutdown(void);
extern void grpc_lb_policy_round_robin_init(void);
@@ -61,6 +63,8 @@ void grpc_register_built_in_plugins(void) {
grpc_resolver_sockaddr_shutdown);
grpc_register_plugin(grpc_load_reporting_plugin_init,
grpc_load_reporting_plugin_shutdown);
+ grpc_register_plugin(grpc_lb_policy_grpclb_init,
+ grpc_lb_policy_grpclb_shutdown);
grpc_register_plugin(grpc_lb_policy_pick_first_init,
grpc_lb_policy_pick_first_shutdown);
grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index fc0908b2f1..e3f1820753 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -240,6 +240,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+ 'src/core/ext/lb_policy/grpclb/grpclb.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index 890309c44a..b77568058c 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -259,9 +259,10 @@ void cq_verify(cq_verifier *v) {
gpr_strvec_destroy(&have_tags);
}
-void cq_verify_empty(cq_verifier *v) {
- gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_seconds(1, GPR_TIMESPAN));
+void cq_verify_empty_timeout(cq_verifier *v, int timeout_sec) {
+ gpr_timespec deadline =
+ gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_seconds(timeout_sec, GPR_TIMESPAN));
grpc_event ev;
GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
@@ -275,6 +276,8 @@ void cq_verify_empty(cq_verifier *v) {
}
}
+void cq_verify_empty(cq_verifier *v) { cq_verify_empty_timeout(v, 1); }
+
static expectation *add(cq_verifier *v, grpc_completion_type type, void *tag) {
expectation *e = gpr_malloc(sizeof(expectation));
e->type = type;
diff --git a/test/core/end2end/cq_verifier.h b/test/core/end2end/cq_verifier.h
index 8c9a85c218..bf82468c9a 100644
--- a/test/core/end2end/cq_verifier.h
+++ b/test/core/end2end/cq_verifier.h
@@ -55,6 +55,9 @@ void cq_verify(cq_verifier *v);
/* ensure that the completion queue is empty */
void cq_verify_empty(cq_verifier *v);
+/* ensure that the completion queue is empty, waiting up to \a timeout secs. */
+void cq_verify_empty_timeout(cq_verifier *v, int timeout_sec);
+
/* Various expectation matchers
Any functions taking ... expect a NULL terminated list of key/value pairs
(each pair using two parameter slots) of metadata that MUST be present in
diff --git a/test/core/nanopb/fuzzer_response.c b/test/core/nanopb/fuzzer_response.c
index 21a5d7b968..75a99faf3f 100644
--- a/test/core/nanopb/fuzzer_response.c
+++ b/test/core/nanopb/fuzzer_response.c
@@ -43,9 +43,9 @@ bool leak_check = true;
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size);
- grpc_grpclb_response *response;
- if ((response = grpc_grpclb_response_parse(slice))) {
- grpc_grpclb_response_destroy(response);
+ grpc_grpclb_initial_response *response;
+ if ((response = grpc_grpclb_initial_response_parse(slice))) {
+ grpc_grpclb_initial_response_destroy(response);
}
gpr_slice_unref(slice);
return 0;
diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc
index bf77878e0a..33de1ee93c 100644
--- a/test/cpp/grpclb/grpclb_api_test.cc
+++ b/test/cpp/grpclb/grpclb_api_test.cc
@@ -58,26 +58,24 @@ TEST_F(GrpclbTest, CreateRequest) {
grpc_grpclb_request_destroy(c_req);
}
-TEST_F(GrpclbTest, ParseResponse) {
+TEST_F(GrpclbTest, ParseInitialResponse) {
LoadBalanceResponse response;
auto* initial_response = response.mutable_initial_response();
auto* client_stats_report_interval =
initial_response->mutable_client_stats_report_interval();
client_stats_report_interval->set_seconds(123);
client_stats_report_interval->set_nanos(456);
-
const std::string encoded_response = response.SerializeAsString();
gpr_slice encoded_slice =
gpr_slice_from_copied_string(encoded_response.c_str());
- grpc_grpclb_response* c_response = grpc_grpclb_response_parse(encoded_slice);
- EXPECT_TRUE(c_response->has_initial_response);
- EXPECT_FALSE(c_response->initial_response.has_load_balancer_delegate);
- EXPECT_EQ(c_response->initial_response.client_stats_report_interval.seconds,
- 123);
- EXPECT_EQ(c_response->initial_response.client_stats_report_interval.nanos,
- 456);
+
+ grpc_grpclb_initial_response* c_initial_response =
+ grpc_grpclb_initial_response_parse(encoded_slice);
+ EXPECT_FALSE(c_initial_response->has_load_balancer_delegate);
+ EXPECT_EQ(c_initial_response->client_stats_report_interval.seconds, 123);
+ EXPECT_EQ(c_initial_response->client_stats_report_interval.nanos, 456);
gpr_slice_unref(encoded_slice);
- grpc_grpclb_response_destroy(c_response);
+ grpc_grpclb_initial_response_destroy(c_initial_response);
}
TEST_F(GrpclbTest, ParseResponseServerList) {
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
new file mode 100644
index 0000000000..1430f9de58
--- /dev/null
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -0,0 +1,688 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ *
+ */
+
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+extern "C" {
+#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/thd.h>
+#include <grpc/support/time.h>
+
+#include "src/core/ext/client_config/client_channel.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+}
+
+#include "src/proto/grpc/lb/v1/load_balancer.pb.h"
+
+#define NUM_BACKENDS 4
+
+// TODO(dgq): Other scenarios in need of testing:
+// - Send an empty serverlist update and verify that the client request blocks
+// until a new serverlist with actual contents is available.
+// - Send identical serverlist update
+// - Test reception of invalid serverlist
+// - Test pinging
+// - Test against a non-LB server. That server should return UNIMPLEMENTED and
+// the call should fail.
+// - Random LB server closing the stream unexpectedly.
+
+namespace grpc {
+namespace {
+
+typedef struct client_fixture {
+ grpc_channel *client;
+ char *server_uri;
+ grpc_completion_queue *cq;
+} client_fixture;
+
+typedef struct server_fixture {
+ grpc_server *server;
+ grpc_call *server_call;
+ grpc_completion_queue *cq;
+ char *servers_hostport;
+ int port;
+ gpr_thd_id tid;
+ int num_calls_serviced;
+} server_fixture;
+
+typedef struct test_fixture {
+ server_fixture lb_server;
+ server_fixture lb_backends[NUM_BACKENDS];
+ client_fixture client;
+ int lb_server_update_delay_ms;
+} test_fixture;
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static gpr_slice build_response_payload_slice(
+ const char *host, int *ports, size_t nports,
+ int64_t expiration_interval_secs, int32_t expiration_interval_nanos) {
+ // server_list {
+ // servers {
+ // ip_address: "127.0.0.1"
+ // port: ...
+ // load_balance_token: "token..."
+ // }
+ // ...
+ // }
+ grpc::lb::v1::LoadBalanceResponse response;
+ auto *serverlist = response.mutable_server_list();
+
+ if (expiration_interval_secs > 0 || expiration_interval_nanos > 0) {
+ auto *expiration_interval = serverlist->mutable_expiration_interval();
+ if (expiration_interval_secs > 0) {
+ expiration_interval->set_seconds(expiration_interval_secs);
+ }
+ if (expiration_interval_nanos > 0) {
+ expiration_interval->set_nanos(expiration_interval_nanos);
+ }
+ }
+ for (size_t i = 0; i < nports; i++) {
+ auto *server = serverlist->add_servers();
+ server->set_ip_address(host);
+ server->set_port(ports[i]);
+ // The following long long int cast is meant to work around the
+ // disfunctional implementation of std::to_string in gcc 4.4, which doesn't
+ // have a version for int but does have one for long long int.
+ server->set_load_balance_token("token" +
+ std::to_string((long long int)ports[i]));
+ }
+
+ gpr_log(GPR_INFO, "generating response: %s",
+ response.ShortDebugString().c_str());
+
+ const gpr_slice response_slice =
+ gpr_slice_from_copied_string(response.SerializeAsString().c_str());
+ return response_slice;
+}
+
+static void drain_cq(grpc_completion_queue *cq) {
+ grpc_event ev;
+ do {
+ ev = grpc_completion_queue_next(cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+ NULL);
+ } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void sleep_ms(int delay_ms) {
+ gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_millis(delay_ms, GPR_TIMESPAN)));
+}
+
+static void start_lb_server(server_fixture *sf, int *ports, size_t nports,
+ int update_delay_ms) {
+ grpc_call *s;
+ cq_verifier *cqv = cq_verifier_create(sf->cq);
+ grpc_op ops[6];
+ grpc_op *op;
+ grpc_metadata_array request_metadata_recv;
+ grpc_call_details call_details;
+ grpc_call_error error;
+ int was_cancelled = 2;
+ grpc_byte_buffer *request_payload_recv;
+ grpc_byte_buffer *response_payload;
+
+ memset(ops, 0, sizeof(ops));
+ grpc_metadata_array_init(&request_metadata_recv);
+ grpc_call_details_init(&call_details);
+
+ error = grpc_server_request_call(sf->server, &s, &call_details,
+ &request_metadata_recv, sf->cq, sf->cq,
+ tag(200));
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ gpr_log(GPR_INFO, "LB Server[%s] up", sf->servers_hostport);
+ cq_expect_completion(cqv, tag(200), 1);
+ cq_verify(cqv);
+ gpr_log(GPR_INFO, "LB Server[%s] after tag 200", sf->servers_hostport);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ op->data.recv_close_on_server.cancelled = &was_cancelled;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(201), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ gpr_log(GPR_INFO, "LB Server[%s] after tag 201", sf->servers_hostport);
+
+ // receive request for backends
+ op = ops;
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message = &request_payload_recv;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ cq_expect_completion(cqv, tag(202), 1);
+ cq_verify(cqv);
+ gpr_log(GPR_INFO, "LB Server[%s] after RECV_MSG", sf->servers_hostport);
+ // TODO(dgq): validate request.
+ grpc_byte_buffer_destroy(request_payload_recv);
+ gpr_slice response_payload_slice;
+ for (int i = 0; i < 2; i++) {
+ if (i == 0) {
+ // First half of the ports.
+ response_payload_slice =
+ build_response_payload_slice("127.0.0.1", ports, nports / 2, -1, -1);
+ } else {
+ // Second half of the ports.
+ sleep_ms(update_delay_ms);
+ response_payload_slice =
+ build_response_payload_slice("127.0.0.1", ports + (nports / 2),
+ (nports + 1) / 2 /* ceil */, -1, -1);
+ }
+
+ response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+ op = ops;
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message = response_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(203), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ cq_expect_completion(cqv, tag(203), 1);
+ cq_verify(cqv);
+ gpr_log(GPR_INFO, "LB Server[%s] after SEND_MESSAGE, iter %d",
+ sf->servers_hostport, i);
+
+ grpc_byte_buffer_destroy(response_payload);
+ gpr_slice_unref(response_payload_slice);
+ }
+ gpr_log(GPR_INFO, "LB Server[%s] shutting down", sf->servers_hostport);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count = 0;
+ op->data.send_status_from_server.status = GRPC_STATUS_OK;
+ op->data.send_status_from_server.status_details = "xyz";
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(204), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ cq_expect_completion(cqv, tag(201), 1);
+ cq_expect_completion(cqv, tag(204), 1);
+ cq_verify(cqv);
+ gpr_log(GPR_INFO, "LB Server[%s] after tag 204. All done. LB server out",
+ sf->servers_hostport);
+
+ grpc_call_destroy(s);
+
+ cq_verifier_destroy(cqv);
+
+ grpc_metadata_array_destroy(&request_metadata_recv);
+ grpc_call_details_destroy(&call_details);
+}
+
+static void start_backend_server(server_fixture *sf) {
+ grpc_call *s;
+ cq_verifier *cqv;
+ grpc_op ops[6];
+ grpc_op *op;
+ grpc_metadata_array request_metadata_recv;
+ grpc_call_details call_details;
+ grpc_call_error error;
+ int was_cancelled;
+ grpc_byte_buffer *request_payload_recv;
+ grpc_byte_buffer *response_payload;
+ grpc_event ev;
+
+ while (true) {
+ memset(ops, 0, sizeof(ops));
+ cqv = cq_verifier_create(sf->cq);
+ was_cancelled = 2;
+ grpc_metadata_array_init(&request_metadata_recv);
+ grpc_call_details_init(&call_details);
+
+ error = grpc_server_request_call(sf->server, &s, &call_details,
+ &request_metadata_recv, sf->cq, sf->cq,
+ tag(100));
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ gpr_log(GPR_INFO, "Server[%s] up", sf->servers_hostport);
+ ev = grpc_completion_queue_next(sf->cq,
+ GRPC_TIMEOUT_SECONDS_TO_DEADLINE(60), NULL);
+ if (!ev.success) {
+ gpr_log(GPR_INFO, "Server[%s] being torn down", sf->servers_hostport);
+ cq_verifier_destroy(cqv);
+ grpc_metadata_array_destroy(&request_metadata_recv);
+ grpc_call_details_destroy(&call_details);
+ return;
+ }
+ GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+ gpr_log(GPR_INFO, "Server[%s] after tag 100", sf->servers_hostport);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ op->data.recv_close_on_server.cancelled = &was_cancelled;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ gpr_log(GPR_INFO, "Server[%s] after tag 101", sf->servers_hostport);
+
+ bool exit = false;
+ gpr_slice response_payload_slice =
+ gpr_slice_from_copied_string("hello you");
+ while (!exit) {
+ op = ops;
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message = &request_payload_recv;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ ev = grpc_completion_queue_next(
+ sf->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), NULL);
+ if (ev.type == GRPC_OP_COMPLETE && ev.success) {
+ GPR_ASSERT(ev.tag = tag(102));
+ if (request_payload_recv == NULL) {
+ exit = true;
+ gpr_log(GPR_INFO,
+ "Server[%s] recv \"close\" from client, exiting. Call #%d",
+ sf->servers_hostport, sf->num_calls_serviced);
+ }
+ } else {
+ gpr_log(GPR_INFO, "Server[%s] forced to shutdown. Call #%d",
+ sf->servers_hostport, sf->num_calls_serviced);
+ exit = true;
+ }
+ gpr_log(GPR_INFO, "Server[%s] after tag 102. Call #%d",
+ sf->servers_hostport, sf->num_calls_serviced);
+
+ if (!exit) {
+ response_payload =
+ grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+ op = ops;
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message = response_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error =
+ grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ ev = grpc_completion_queue_next(
+ sf->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), NULL);
+ if (ev.type == GRPC_OP_COMPLETE && ev.success) {
+ GPR_ASSERT(ev.tag = tag(103));
+ } else {
+ gpr_log(GPR_INFO, "Server[%s] forced to shutdown. Call #%d",
+ sf->servers_hostport, sf->num_calls_serviced);
+ exit = true;
+ }
+ gpr_log(GPR_INFO, "Server[%s] after tag 103. Call #%d",
+ sf->servers_hostport, sf->num_calls_serviced);
+ grpc_byte_buffer_destroy(response_payload);
+ }
+
+ grpc_byte_buffer_destroy(request_payload_recv);
+ }
+ ++sf->num_calls_serviced;
+
+ gpr_log(GPR_INFO, "Server[%s] OUT OF THE LOOP", sf->servers_hostport);
+ gpr_slice_unref(response_payload_slice);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count = 0;
+ op->data.send_status_from_server.status = GRPC_STATUS_OK;
+ op->data.send_status_from_server.status_details = "Backend server out a-ok";
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ cq_expect_completion(cqv, tag(101), 1);
+ cq_expect_completion(cqv, tag(104), 1);
+ cq_verify(cqv);
+ gpr_log(GPR_INFO, "Server[%s] DONE. After servicing %d calls",
+ sf->servers_hostport, sf->num_calls_serviced);
+
+ grpc_call_destroy(s);
+ cq_verifier_destroy(cqv);
+ grpc_metadata_array_destroy(&request_metadata_recv);
+ grpc_call_details_destroy(&call_details);
+ }
+}
+
+static void perform_request(client_fixture *cf) {
+ grpc_call *c;
+ cq_verifier *cqv = cq_verifier_create(cf->cq);
+ grpc_op ops[6];
+ grpc_op *op;
+ grpc_metadata_array initial_metadata_recv;
+ grpc_metadata_array trailing_metadata_recv;
+ grpc_status_code status;
+ grpc_call_error error;
+ char *details = NULL;
+ size_t details_capacity = 0;
+ grpc_byte_buffer *request_payload;
+ grpc_byte_buffer *response_payload_recv;
+ int i;
+
+ memset(ops, 0, sizeof(ops));
+ gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+
+ c = grpc_channel_create_call(cf->client, NULL, GRPC_PROPAGATE_DEFAULTS,
+ cf->cq, "/foo", "foo.test.google.fr:1234",
+ GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1000), NULL);
+ gpr_log(GPR_INFO, "Call 0x%" PRIxPTR " created", (intptr_t)c);
+ GPR_ASSERT(c);
+ char *peer;
+
+ grpc_metadata_array_init(&initial_metadata_recv);
+ grpc_metadata_array_init(&trailing_metadata_recv);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata = &initial_metadata_recv;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+ op->data.recv_status_on_client.status = &status;
+ op->data.recv_status_on_client.status_details = &details;
+ op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ for (i = 0; i < 4; i++) {
+ request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message = request_payload;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message = &response_payload_recv;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ peer = grpc_call_get_peer(c);
+ cq_expect_completion(cqv, tag(2), 1);
+ cq_verify(cqv);
+ gpr_free(peer);
+
+ grpc_byte_buffer_destroy(request_payload);
+ grpc_byte_buffer_destroy(response_payload_recv);
+ }
+
+ gpr_slice_unref(request_payload_slice);
+
+ op = ops;
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+ error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ cq_expect_completion(cqv, tag(1), 1);
+ cq_expect_completion(cqv, tag(3), 1);
+ cq_verify(cqv);
+ peer = grpc_call_get_peer(c);
+ gpr_log(GPR_INFO, "Client DONE WITH SERVER %s ", peer);
+ gpr_free(peer);
+
+ grpc_call_destroy(c);
+
+ cq_verify_empty_timeout(cqv, 1);
+ cq_verifier_destroy(cqv);
+
+ grpc_metadata_array_destroy(&initial_metadata_recv);
+ grpc_metadata_array_destroy(&trailing_metadata_recv);
+ gpr_free(details);
+}
+
+static void setup_client(const char *server_hostport, client_fixture *cf) {
+ cf->cq = grpc_completion_queue_create(NULL);
+ cf->server_uri = gpr_strdup(server_hostport);
+ cf->client = grpc_insecure_channel_create(cf->server_uri, NULL, NULL);
+}
+
+static void teardown_client(client_fixture *cf) {
+ grpc_completion_queue_shutdown(cf->cq);
+ drain_cq(cf->cq);
+ grpc_completion_queue_destroy(cf->cq);
+ cf->cq = NULL;
+ grpc_channel_destroy(cf->client);
+ cf->client = NULL;
+ gpr_free(cf->server_uri);
+}
+
+static void setup_server(const char *host, server_fixture *sf) {
+ int assigned_port;
+
+ sf->cq = grpc_completion_queue_create(NULL);
+ const char *colon_idx = strchr(host, ':');
+ if (colon_idx) {
+ const char *port_str = colon_idx + 1;
+ sf->port = atoi(port_str);
+ sf->servers_hostport = gpr_strdup(host);
+ } else {
+ sf->port = grpc_pick_unused_port_or_die();
+ gpr_join_host_port(&sf->servers_hostport, host, sf->port);
+ }
+
+ sf->server = grpc_server_create(NULL, NULL);
+ grpc_server_register_completion_queue(sf->server, sf->cq, NULL);
+ GPR_ASSERT((assigned_port = grpc_server_add_insecure_http2_port(
+ sf->server, sf->servers_hostport)) > 0);
+ GPR_ASSERT(sf->port == assigned_port);
+ grpc_server_start(sf->server);
+}
+
+static void teardown_server(server_fixture *sf) {
+ if (!sf->server) return;
+
+ gpr_log(GPR_INFO, "Server[%s] shutting down", sf->servers_hostport);
+ grpc_server_shutdown_and_notify(sf->server, sf->cq, tag(1000));
+ GPR_ASSERT(grpc_completion_queue_pluck(
+ sf->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+ .type == GRPC_OP_COMPLETE);
+ grpc_server_destroy(sf->server);
+ gpr_thd_join(sf->tid);
+
+ sf->server = NULL;
+ grpc_completion_queue_shutdown(sf->cq);
+ drain_cq(sf->cq);
+ grpc_completion_queue_destroy(sf->cq);
+
+ gpr_log(GPR_INFO, "Server[%s] bye bye", sf->servers_hostport);
+ gpr_free(sf->servers_hostport);
+}
+
+static void fork_backend_server(void *arg) {
+ server_fixture *sf = static_cast<server_fixture *>(arg);
+ start_backend_server(sf);
+}
+
+static void fork_lb_server(void *arg) {
+ test_fixture *tf = static_cast<test_fixture *>(arg);
+ int ports[NUM_BACKENDS];
+ for (int i = 0; i < NUM_BACKENDS; i++) {
+ ports[i] = tf->lb_backends[i].port;
+ }
+ start_lb_server(&tf->lb_server, ports, NUM_BACKENDS,
+ tf->lb_server_update_delay_ms);
+}
+
+static void setup_test_fixture(test_fixture *tf,
+ int lb_server_update_delay_ms) {
+ tf->lb_server_update_delay_ms = lb_server_update_delay_ms;
+
+ gpr_thd_options options = gpr_thd_options_default();
+ gpr_thd_options_set_joinable(&options);
+
+ for (int i = 0; i < NUM_BACKENDS; ++i) {
+ setup_server("127.0.0.1", &tf->lb_backends[i]);
+ gpr_thd_new(&tf->lb_backends[i].tid, fork_backend_server,
+ &tf->lb_backends[i], &options);
+ }
+
+ setup_server("127.0.0.1", &tf->lb_server);
+ gpr_thd_new(&tf->lb_server.tid, fork_lb_server, &tf->lb_server, &options);
+
+ char *server_uri;
+ gpr_asprintf(&server_uri, "ipv4:%s?lb_policy=grpclb&lb_enabled=1",
+ tf->lb_server.servers_hostport);
+ setup_client(server_uri, &tf->client);
+ gpr_free(server_uri);
+}
+
+static void teardown_test_fixture(test_fixture *tf) {
+ teardown_client(&tf->client);
+ for (int i = 0; i < NUM_BACKENDS; ++i) {
+ teardown_server(&tf->lb_backends[i]);
+ }
+ teardown_server(&tf->lb_server);
+}
+
+// The LB server will send two updates: batch 1 and batch 2. Each batch
+// contains
+// two addresses, both of a valid and running backend server. Batch 1 is
+// readily
+// available and provided as soon as the client establishes the streaming
+// call.
+// Batch 2 is sent after a delay of \a lb_server_update_delay_ms
+// milliseconds.
+static test_fixture test_update(int lb_server_update_delay_ms) {
+ gpr_log(GPR_INFO, "start %s(%d)", __func__, lb_server_update_delay_ms);
+ test_fixture tf;
+ memset(&tf, 0, sizeof(tf));
+ setup_test_fixture(&tf, lb_server_update_delay_ms);
+ perform_request(
+ &tf.client); // "consumes" 1st backend server of 1st serverlist
+ perform_request(
+ &tf.client); // "consumes" 2nd backend server of 1st serverlist
+
+ perform_request(
+ &tf.client); // "consumes" 1st backend server of 2nd serverlist
+ perform_request(
+ &tf.client); // "consumes" 2nd backend server of 2nd serverlist
+
+ teardown_test_fixture(&tf);
+ gpr_log(GPR_INFO, "end %s(%d)", __func__, lb_server_update_delay_ms);
+ return tf;
+}
+
+} // namespace
+} // namespace grpc
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+
+ grpc::test_fixture tf_result;
+ // Clients take a bit over one second to complete a call (the last part of the
+ // call sleeps for 1 second while verifying the client's completion queue is
+ // empty). Therefore:
+ //
+ // If the LB server waits 800ms before sending an update, it will arrive
+ // before the first client request is done, skipping the second server from
+ // batch 1 altogether: the 2nd client request will go to the 1st server of
+ // batch 2 (ie, the third one out of the four total servers).
+ tf_result = grpc::test_update(800);
+ GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced == 1);
+ GPR_ASSERT(tf_result.lb_backends[1].num_calls_serviced == 0);
+ GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced == 2);
+ GPR_ASSERT(tf_result.lb_backends[3].num_calls_serviced == 1);
+
+ // If the LB server waits 1500ms, the update arrives after having picked the
+ // 2nd server from batch 1 but before the next pick for the first server of
+ // batch 2. All server are used.
+ tf_result = grpc::test_update(1500);
+ GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced == 1);
+ GPR_ASSERT(tf_result.lb_backends[1].num_calls_serviced == 1);
+ GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced == 1);
+ GPR_ASSERT(tf_result.lb_backends[3].num_calls_serviced == 1);
+
+ // If the LB server waits > 2000ms, the update arrives after the first two
+ // request are done and the third pick is performed, which returns, in RR
+ // fashion, the 1st server of the 1st update. Therefore, the second server of
+ // batch 1 is hit twice, whereas the first server of batch 2 is never hit.
+ tf_result = grpc::test_update(2100);
+ GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced == 2);
+ GPR_ASSERT(tf_result.lb_backends[1].num_calls_serviced == 1);
+ GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced == 1);
+ GPR_ASSERT(tf_result.lb_backends[3].num_calls_serviced == 0);
+
+ grpc_shutdown();
+ return 0;
+}
diff --git a/test/cpp/qps/limit_cores.cc b/test/cpp/qps/limit_cores.cc
index 59ed369067..b5c222542b 100644
--- a/test/cpp/qps/limit_cores.cc
+++ b/test/cpp/qps/limit_cores.cc
@@ -68,9 +68,9 @@ int LimitCores(const int* cores, int cores_size) {
cores_set++;
}
}
- GPR_ASSERT(sched_setaffinity(0, size, cpup) == 0);
+ bool affinity_set = (sched_setaffinity(0, size, cpup) == 0);
CPU_FREE(cpup);
- return cores_set;
+ return affinity_set ? cores_set : num_cores;
}
} // namespace testing
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 62cf5cc8c7..745069480c 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -931,6 +931,7 @@ src/core/ext/client_config/subchannel.h \
src/core/ext/client_config/subchannel_call_holder.h \
src/core/ext/client_config/subchannel_index.h \
src/core/ext/client_config/uri_parser.h \
+src/core/ext/lb_policy/grpclb/grpclb.h \
src/core/ext/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \
third_party/nanopb/pb.h \
@@ -1111,6 +1112,7 @@ src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
+src/core/ext/lb_policy/grpclb/grpclb.c \
src/core/ext/lb_policy/grpclb/load_balancer_api.c \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index c4b5d98a53..727b11e273 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -155,7 +155,9 @@ pip_install_dir() {
cd $PWD
}
-$VENV_PYTHON -m pip install --upgrade pip setuptools
+$VENV_PYTHON -m pip install --upgrade pip
+# TODO(https://github.com/pypa/setuptools/issues/709) get the latest setuptools
+$VENV_PYTHON -m pip install setuptools==25.1.1
$VENV_PYTHON -m pip install cython
pip_install_dir $ROOT
$VENV_PYTHON $ROOT/tools/distrib/python/make_grpcio_tools.py
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index a6485dca6e..439f425c88 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -2254,6 +2254,27 @@
"grpc++_test_util",
"grpc_test_util"
],
+ "headers": [
+ "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
+ "src/proto/grpc/lb/v1/load_balancer.pb.h"
+ ],
+ "language": "c++",
+ "name": "grpclb_test",
+ "src": [
+ "test/cpp/grpclb/grpclb_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
"headers": [],
"language": "c++",
"name": "hybrid_end2end_test",
@@ -4177,6 +4198,7 @@
"gpr",
"grpc_base",
"grpc_lb_policy_grpclb",
+ "grpc_lb_policy_grpclb",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
@@ -4230,6 +4252,7 @@
"gpr",
"gpr_test_util",
"grpc",
+ "grpc_base",
"grpc_test_util_base"
],
"headers": [
@@ -4271,6 +4294,7 @@
"gpr",
"grpc_base",
"grpc_lb_policy_grpclb",
+ "grpc_lb_policy_grpclb",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
@@ -6063,12 +6087,15 @@
"nanopb"
],
"headers": [
+ "src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
],
"language": "c",
"name": "grpc_lb_policy_grpclb",
"src": [
+ "src/core/ext/lb_policy/grpclb/grpclb.c",
+ "src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.c",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index d5e6f50703..283f2af129 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -2301,6 +2301,27 @@
"cpu_cost": 1.0,
"exclude_configs": [],
"flaky": false,
+ "gtest": false,
+ "language": "c++",
+ "name": "grpclb_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ]
+ },
+ {
+ "args": [],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "flaky": false,
"gtest": true,
"language": "c++",
"name": "hybrid_end2end_test",
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 33485d3dc9..4bfaa6e8d2 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -440,6 +440,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
<ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
@@ -787,6 +788,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index a21d873b88..14af1c3d2e 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -496,6 +496,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
<Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+ <Filter>src\core\ext\lb_policy\grpclb</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
<Filter>src\core\ext\lb_policy\grpclb</Filter>
</ClCompile>
@@ -1079,6 +1082,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h">
<Filter>src\core\ext\client_config</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h">
+ <Filter>src\core\ext\lb_policy\grpclb</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
<Filter>src\core\ext\lb_policy\grpclb</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index f0a8f7b6b9..cfa29d0c02 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -147,6 +147,35 @@
</ItemDefinitionGroup>
<ItemGroup>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+ </ItemGroup>
+ <ItemGroup>
<ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h" />
<ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h" />
<ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h" />
@@ -160,6 +189,85 @@
<ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
<ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h" />
<ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\client_certs.c">
@@ -196,6 +304,182 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index a1d31eb54e..913774d71e 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -52,6 +52,353 @@
<ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
<Filter>test\core\util</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+ <Filter>src\core\lib\channel</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+ <Filter>src\core\lib\compression</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+ <Filter>src\core\lib\compression</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+ <Filter>src\core\lib\debug</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+ <Filter>src\core\lib\http</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+ <Filter>src\core\lib\http</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+ <Filter>src\core\lib\http</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+ <Filter>src\core\lib\json</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+ <Filter>src\core\lib\json</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+ <Filter>src\core\lib\json</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+ <Filter>src\core\lib\json</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+ <Filter>src\core\lib\surface</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
+ <Filter>include\grpc</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+ <Filter>include\grpc\impl\codegen</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h">
@@ -93,9 +440,291 @@
<ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h">
<Filter>test\core\util</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+ <Filter>src\core\lib\channel</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
+ <Filter>src\core\lib\compression</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
+ <Filter>src\core\lib\compression</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
+ <Filter>src\core\lib\debug</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
+ <Filter>src\core\lib\http</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
+ <Filter>src\core\lib\http</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
+ <Filter>src\core\lib\http</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h">
+ <Filter>src\core\lib\iomgr</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
+ <Filter>src\core\lib\json</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
+ <Filter>src\core\lib\json</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
+ <Filter>src\core\lib\json</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
+ <Filter>src\core\lib\json</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
+ <Filter>src\core\lib\surface</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
+ <Filter Include="include">
+ <UniqueIdentifier>{50129440-aff7-7df7-682c-b9671be19a6f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\grpc">
+ <UniqueIdentifier>{d448b078-95a6-6fca-fe4a-8b44dd71f359}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\grpc\impl">
+ <UniqueIdentifier>{314a6801-6fe3-9211-33d8-ecf3332c1151}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\grpc\impl\codegen">
+ <UniqueIdentifier>{8e97f1e1-f4d1-a56e-0837-7901778fb3b9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src">
+ <UniqueIdentifier>{7d107d7c-1da3-9525-3ba1-3a411b552ea8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core">
+ <UniqueIdentifier>{f7bfac91-5eb2-dea7-4601-6c63edbbf997}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib">
+ <UniqueIdentifier>{f4e8c61e-1ca6-0fdd-7b5e-b7f9a30c9a21}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\channel">
+ <UniqueIdentifier>{1cd1503c-bec0-5ade-c75f-aa25c80975ec}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\compression">
+ <UniqueIdentifier>{09632582-2cc3-5618-d673-65d3884f8ce5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\debug">
+ <UniqueIdentifier>{2c1a72e9-886e-8082-9d2f-0fc9cb3ab996}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\http">
+ <UniqueIdentifier>{4862ecce-fa07-eb5e-5c05-bfa753c8bfe5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\iomgr">
+ <UniqueIdentifier>{fc7f488e-08b4-8366-3720-1f7ffaa0b0b3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\json">
+ <UniqueIdentifier>{89bc8f83-e29a-ddab-8f6b-22df11cdc867}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\surface">
+ <UniqueIdentifier>{7f2b7dca-395f-94dd-c9ad-9a286bd9751e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\core\lib\transport">
+ <UniqueIdentifier>{5249e884-ea07-6782-531d-ec622c54b9af}</UniqueIdentifier>
+ </Filter>
<Filter Include="test">
<UniqueIdentifier>{a2783de3-4fcf-718d-a859-c2108350ff33}</UniqueIdentifier>
</Filter>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 3a3610d524..cffdffcb63 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -407,6 +407,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
<ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
@@ -702,6 +703,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index bec089e860..1fee3653ec 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -421,6 +421,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
<Filter>src\core\ext\load_reporting</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+ <Filter>src\core\ext\lb_policy\grpclb</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
<Filter>src\core\ext\lb_policy\grpclb</Filter>
</ClCompile>
@@ -920,6 +923,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h">
<Filter>src\core\ext\load_reporting</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h">
+ <Filter>src\core\ext\lb_policy\grpclb</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
<Filter>src\core\ext\lb_policy\grpclb</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
new file mode 100644
index 0000000000..91b9a6eacc
--- /dev/null
+++ b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{9D6FFE17-ABF0-A851-268E-9E3E8C573CBB}</ProjectGuid>
+ <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+ <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+ <TargetName>grpclb_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'">
+ <TargetName>grpclb_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.pb.cc">
+ </ClCompile>
+ <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.pb.h">
+ </ClInclude>
+ <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.grpc.pb.cc">
+ </ClCompile>
+ <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.grpc.pb.h">
+ </ClInclude>
+ <ClCompile Include="$(SolutionDir)\..\test\cpp\grpclb\grpclb_test.cc">
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+ <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+ <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+ <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+ <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
+ <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+ <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ </ImportGroup>
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+ </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters
new file mode 100644
index 0000000000..5493df2e7b
--- /dev/null
+++ b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.proto">
+ <Filter>src\proto\grpc\lb\v1</Filter>
+ </ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\test\cpp\grpclb\grpclb_test.cc">
+ <Filter>test\cpp\grpclb</Filter>
+ </ClCompile>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Filter Include="src">
+ <UniqueIdentifier>{082bbcbc-bbd8-db7d-afe9-fa0fec76863d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\proto">
+ <UniqueIdentifier>{7c61995a-80c2-ef3d-0a4b-baf2221c12f8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\proto\grpc">
+ <UniqueIdentifier>{fc2920d4-902c-fdf0-d4b8-6b22e1361105}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\proto\grpc\lb">
+ <UniqueIdentifier>{4778352a-559f-b008-e3d2-4ae9181260df}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\proto\grpc\lb\v1">
+ <UniqueIdentifier>{36a4326b-4f2a-4720-b730-e40fe078fd40}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test">
+ <UniqueIdentifier>{e0ba55a2-37d9-5029-6f4e-64f097307340}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\cpp">
+ <UniqueIdentifier>{ad67d6ba-d08b-7879-2929-20f0f01c9918}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\cpp\grpclb">
+ <UniqueIdentifier>{4498fa30-2dab-584c-5711-a1055cec30f6}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project>
+