Merge pull request #2907 from yang-g/error_code_conforming

return StatusCode::INTERNAL for proto parsing error
diff --git a/BUILD b/BUILD
index 9eaabbb..7eb5979 100644
--- a/BUILD
+++ b/BUILD
@@ -52,7 +52,6 @@
     "src/core/support/string_win32.h",
     "src/core/support/thd_internal.h",
     "src/core/support/alloc.c",
-    "src/core/support/cancellable.c",
     "src/core/support/cmdline.c",
     "src/core/support/cpu_iphone.c",
     "src/core/support/cpu_linux.c",
@@ -96,7 +95,6 @@
     "include/grpc/support/atm_gcc_atomic.h",
     "include/grpc/support/atm_gcc_sync.h",
     "include/grpc/support/atm_win32.h",
-    "include/grpc/support/cancellable_platform.h",
     "include/grpc/support/cmdline.h",
     "include/grpc/support/cpu.h",
     "include/grpc/support/histogram.h",
@@ -202,6 +200,7 @@
     "src/core/iomgr/tcp_server.h",
     "src/core/iomgr/tcp_windows.h",
     "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
     "src/core/json/json.h",
@@ -326,6 +325,7 @@
     "src/core/iomgr/tcp_server_windows.c",
     "src/core/iomgr/tcp_windows.c",
     "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/udp_server.c",
     "src/core/iomgr/wakeup_fd_eventfd.c",
     "src/core/iomgr/wakeup_fd_nospecial.c",
     "src/core/iomgr/wakeup_fd_pipe.c",
@@ -400,6 +400,7 @@
   ],
   deps = [
     "//external:libssl",
+    "//external:zlib",
     ":gpr",
   ],
 )
@@ -465,6 +466,7 @@
     "src/core/iomgr/tcp_server.h",
     "src/core/iomgr/tcp_windows.h",
     "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
     "src/core/json/json.h",
@@ -569,6 +571,7 @@
     "src/core/iomgr/tcp_server_windows.c",
     "src/core/iomgr/tcp_windows.c",
     "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/udp_server.c",
     "src/core/iomgr/wakeup_fd_eventfd.c",
     "src/core/iomgr/wakeup_fd_nospecial.c",
     "src/core/iomgr/wakeup_fd_pipe.c",
@@ -647,6 +650,26 @@
 
 
 cc_library(
+  name = "grpc_zookeeper",
+  srcs = [
+    "src/core/client_config/resolvers/zookeeper_resolver.h",
+    "src/core/client_config/resolvers/zookeeper_resolver.c",
+  ],
+  hdrs = [
+    "include/grpc/grpc_zookeeper.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":gpr",
+    ":grpc",
+  ],
+)
+
+
+cc_library(
   name = "grpc++",
   srcs = [
     "src/cpp/client/secure_credentials.h",
@@ -887,7 +910,6 @@
   name = "gpr_objc",
   srcs = [
     "src/core/support/alloc.c",
-    "src/core/support/cancellable.c",
     "src/core/support/cmdline.c",
     "src/core/support/cpu_iphone.c",
     "src/core/support/cpu_linux.c",
@@ -931,7 +953,6 @@
     "include/grpc/support/atm_gcc_atomic.h",
     "include/grpc/support/atm_gcc_sync.h",
     "include/grpc/support/atm_win32.h",
-    "include/grpc/support/cancellable_platform.h",
     "include/grpc/support/cmdline.h",
     "include/grpc/support/cpu.h",
     "include/grpc/support/histogram.h",
@@ -1054,6 +1075,7 @@
     "src/core/iomgr/tcp_server_windows.c",
     "src/core/iomgr/tcp_windows.c",
     "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/udp_server.c",
     "src/core/iomgr/wakeup_fd_eventfd.c",
     "src/core/iomgr/wakeup_fd_nospecial.c",
     "src/core/iomgr/wakeup_fd_pipe.c",
@@ -1191,6 +1213,7 @@
     "src/core/iomgr/tcp_server.h",
     "src/core/iomgr/tcp_windows.h",
     "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
     "src/core/json/json.h",
diff --git a/Makefile b/Makefile
index 46e23db..d254fd6 100644
--- a/Makefile
+++ b/Makefile
@@ -411,6 +411,7 @@
 PROTOC_CHECK_VERSION_CMD = protoc --version | grep -q libprotoc.3
 DTRACE_CHECK_CMD = which dtrace > /dev/null
 SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
+ZOOKEEPER_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zookeeper.c $(LDFLAGS) -lzookeeper_mt
 
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
 HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
@@ -478,6 +479,8 @@
 CACHE_MK += HAS_SYSTEMTAP = true,
 endif
 
+HAS_ZOOKEEPER = $(shell $(ZOOKEEPER_CHECK_CMD) 2> /dev/null && echo true || echo false)
+
 # Note that for testing purposes, one can do:
 #   make HAS_EMBEDDED_OPENSSL_ALPN=false
 # to emulate the fact we do not have OpenSSL in the third_party folder.
@@ -596,6 +599,14 @@
 PC_LIB = -lgrpc
 GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
 
+# gprc_zookeeper .pc file
+PC_NAME = gRPC zookeeper
+PC_DESCRIPTION = gRPC's zookeeper plugin
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE =
+PC_LIBS_PRIVATE = -lzookeeper_mt
+GRPC_ZOOKEEPER_PC_FILE := $(PC_TEMPLATE)
+
 PROTOBUF_PKG_CONFIG = false
 
 PC_REQUIRES_GRPCXX =
@@ -781,7 +792,6 @@
 fling_stream_test: $(BINDIR)/$(CONFIG)/fling_stream_test
 fling_test: $(BINDIR)/$(CONFIG)/fling_test
 gen_hpack_tables: $(BINDIR)/$(CONFIG)/gen_hpack_tables
-gpr_cancellable_test: $(BINDIR)/$(CONFIG)/gpr_cancellable_test
 gpr_cmdline_test: $(BINDIR)/$(CONFIG)/gpr_cmdline_test
 gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
 gpr_file_test: $(BINDIR)/$(CONFIG)/gpr_file_test
@@ -837,6 +847,7 @@
 timers_test: $(BINDIR)/$(CONFIG)/timers_test
 transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test
 transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
+udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
 uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
 async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
 async_streaming_ping_pong_test: $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test
@@ -881,6 +892,7 @@
 sync_streaming_ping_pong_test: $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test
 sync_unary_ping_pong_test: $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test
 thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
+zookeeper_test: $(BINDIR)/$(CONFIG)/zookeeper_test
 chttp2_fake_security_bad_hostname_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test
 chttp2_fake_security_cancel_after_accept_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test
 chttp2_fake_security_cancel_after_accept_and_writes_closed_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test
@@ -1601,6 +1613,7 @@
 	$(PERFTOOLS_CHECK_CMD) || true
 	$(PROTOBUF_CHECK_CMD) || true
 	$(PROTOC_CHECK_VERSION_CMD) || true
+	$(ZOOKEEPER_CHECK_CMD) || true
 
 $(LIBDIR)/$(CONFIG)/zlib/libz.a:
 	$(E) "[MAKE]    Building zlib"
@@ -1659,17 +1672,29 @@
 
 static: static_c static_cxx
 
-static_c: pc_c pc_c_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
+static_c: pc_c pc_c_unsecure cache.mk pc_gpr pc_c_zookeeper $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a static_zookeeper_libs
+
 
 static_cxx: pc_cxx pc_cxx_unsecure pc_gpr cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 
 shared: shared_c shared_cxx
 
-shared_c: pc_c pc_c_unsecure pc_gpr  cache.mk $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+shared_c: pc_c pc_c_unsecure pc_gpr cache.mk pc_c_zookeeper $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) shared_zookeeper_libs
 
 shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT)
 
 shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
+ifeq ($(HAS_ZOOKEEPER),true)
+static_zookeeper_libs: $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
+shared_zookeeper_libs: $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT)
+else
+
+static_zookeeper_libs:
+
+shared_zookeeper_libs:
+
+endif
+
 grpc_csharp_ext: shared_csharp
 
 plugins: $(PROTOC_PLUGINS)
@@ -1683,21 +1708,41 @@
 
 pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
 
+ifeq ($(HAS_ZOOKEEPER),true)
+pc_c_zookeeper: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_zookeeper.pc
+else
+pc_c_zookeeper:
+endif
+
 pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
 
 pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a
 
-buildtests: buildtests_c buildtests_cxx
+ifeq ($(HAS_ZOOKEEPER),true)
+privatelibs_zookeeper: 
+else
+privatelibs_zookeeper:
+endif
 
-buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
 
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/reconnect_interop_client $(BINDIR)/$(CONFIG)/reconnect_interop_server $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test
+buildtests: buildtests_c buildtests_cxx buildtests_zookeeper
 
-test: test_c test_cxx
+buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/udp_server_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_default_host_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_channel_connectivity_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_default_host_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_channel_connectivity_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_default_host_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
 
-flaky_test: flaky_test_c flaky_test_cxx
+buildtests_cxx: buildtests_zookeeper privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/reconnect_interop_client $(BINDIR)/$(CONFIG)/reconnect_interop_server $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test
+
+ifeq ($(HAS_ZOOKEEPER),true)
+buildtests_zookeeper: privatelibs_zookeeper $(BINDIR)/$(CONFIG)/zookeeper_test
+else
+buildtests_zookeeper:
+endif
+
+
+test: test_c test_cxx test_zookeeper
+
+flaky_test: flaky_test_c flaky_test_cxx flaky_test_zookeeper
 
 test_c: buildtests_c
 	$(E) "[RUN]     Testing alarm_heap_test"
@@ -1726,8 +1771,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/fling_stream_test || ( echo test fling_stream_test failed ; exit 1 )
 	$(E) "[RUN]     Testing fling_test"
 	$(Q) $(BINDIR)/$(CONFIG)/fling_test || ( echo test fling_test failed ; exit 1 )
-	$(E) "[RUN]     Testing gpr_cancellable_test"
-	$(Q) $(BINDIR)/$(CONFIG)/gpr_cancellable_test || ( echo test gpr_cancellable_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_cmdline_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_cmdline_test || ( echo test gpr_cmdline_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_env_test"
@@ -1826,6 +1869,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 )
 	$(E) "[RUN]     Testing transport_security_test"
 	$(Q) $(BINDIR)/$(CONFIG)/transport_security_test || ( echo test transport_security_test failed ; exit 1 )
+	$(E) "[RUN]     Testing udp_server_test"
+	$(Q) $(BINDIR)/$(CONFIG)/udp_server_test || ( echo test udp_server_test failed ; exit 1 )
 	$(E) "[RUN]     Testing uri_parser_test"
 	$(Q) $(BINDIR)/$(CONFIG)/uri_parser_test || ( echo test uri_parser_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_bad_hostname_test"
@@ -3257,7 +3302,7 @@
 flaky_test_c: buildtests_c
 
 
-test_cxx: buildtests_cxx
+test_cxx: test_zookeeper buildtests_cxx
 	$(E) "[RUN]     Testing async_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing async_streaming_ping_pong_test"
@@ -3313,6 +3358,20 @@
 flaky_test_cxx: buildtests_cxx
 
 
+ifeq ($(HAS_ZOOKEEPER),true)
+test_zookeeper: buildtests_zookeeper
+	$(E) "[RUN]     Testing zookeeper_test"
+	$(Q) $(BINDIR)/$(CONFIG)/zookeeper_test || ( echo test zookeeper_test failed ; exit 1 )
+
+
+flaky_test_zookeeper: buildtests_zookeeper
+
+else
+test_zookeeper:
+flaky_test_zookeeper:
+endif
+
+
 test_python: static_c
 	$(E) "[RUN]     Testing python code"
 	$(Q) tools/run_tests/run_tests.py -lpython -c$(CONFIG)
@@ -3348,6 +3407,10 @@
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc.a
 	$(E) "[STRIP]   Stripping libgrpc_unsecure.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
+ifeq ($(HAS_ZOOKEEPER),true)
+	$(E) "[STRIP]   Stripping libgrpc_zookeeper.a"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
+endif
 endif
 
 strip-static_cxx: static_cxx
@@ -3366,6 +3429,10 @@
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT)
 	$(E) "[STRIP]   Stripping libgrpc_unsecure.so"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+ifeq ($(HAS_ZOOKEEPER),true)
+	$(E) "[STRIP]   Stripping libgrpc_zookeeper.so"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT)
+endif
 endif
 
 strip-shared_cxx: shared_cxx
@@ -3401,6 +3468,11 @@
 	$(Q) mkdir -p $(@D)
 	$(Q) echo "$(GRPC_UNSECURE_PC_FILE)" | tr , '\n' >$@
 
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc_zookeeper.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo -e "$(GRPC_ZOOKEEPER_PC_FILE)" >$@
+
 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc:
 	$(E) "[MAKE]    Generating $@"
 	$(Q) mkdir -p $(@D)
@@ -3643,6 +3715,11 @@
 	$(E) "[INSTALL] Installing libgrpc_unsecure.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(prefix)/lib/libgrpc_unsecure.a
+ifeq ($(HAS_ZOOKEEPER),true)
+	$(E) "[INSTALL] Installing libgrpc_zookeeper.a"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(prefix)/lib/libgrpc_zookeeper.a
+endif
 
 install-static_cxx: static_cxx strip-static_cxx install-pkg-config_cxx
 	$(E) "[INSTALL] Installing libgrpc++.a"
@@ -3697,6 +3774,22 @@
 	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
 endif
 endif
+ifeq ($(HAS_ZOOKEEPER),true)
+ifeq ($(SYSTEM),MINGW32)
+	$(E) "[INSTALL] Installing grpc_zookeeper.$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/grpc_zookeeper.$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper-imp.a $(prefix)/lib/libgrpc_zookeeper-imp.a
+else
+	$(E) "[INSTALL] Installing libgrpc_zookeeper.$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.so.0
+	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.so
+endif
+endif
+endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
 	$(Q) ldconfig || true
@@ -3733,6 +3826,8 @@
 	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so
 endif
 endif
+ifeq ($(HAS_ZOOKEEPER),true)
+endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
 	$(Q) ldconfig || true
@@ -3755,6 +3850,8 @@
 	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
 endif
 endif
+ifeq ($(HAS_ZOOKEEPER),true)
+endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
 	$(Q) ldconfig || true
@@ -3779,12 +3876,15 @@
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
 endif
 
-install-pkg-config_c: pc_gpr pc_c pc_c_unsecure
+install-pkg-config_c: pc_gpr pc_c pc_c_unsecure pc_c_zookeeper
 	$(E) "[INSTALL] Installing C pkg-config files"
 	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc $(prefix)/lib/pkgconfig/gpr.pc
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(prefix)/lib/pkgconfig/grpc.pc
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(prefix)/lib/pkgconfig/grpc_unsecure.pc
+ifeq ($(HAS_ZOOKEEPER),true)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_zookeeper.pc $(prefix)/lib/pkgconfig/grpc_zookeeper.pc
+endif
 
 install-pkg-config_cxx: pc_cxx pc_cxx_unsecure
 	$(E) "[INSTALL] Installing C++ pkg-config files"
@@ -3827,7 +3927,6 @@
 
 LIBGPR_SRC = \
     src/core/support/alloc.c \
-    src/core/support/cancellable.c \
     src/core/support/cmdline.c \
     src/core/support/cpu_iphone.c \
     src/core/support/cpu_linux.c \
@@ -3871,7 +3970,6 @@
     include/grpc/support/atm_gcc_atomic.h \
     include/grpc/support/atm_gcc_sync.h \
     include/grpc/support/atm_win32.h \
-    include/grpc/support/cancellable_platform.h \
     include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
     include/grpc/support/histogram.h \
@@ -4035,6 +4133,7 @@
     src/core/iomgr/tcp_server_windows.c \
     src/core/iomgr/tcp_windows.c \
     src/core/iomgr/time_averaged_stats.c \
+    src/core/iomgr/udp_server.c \
     src/core/iomgr/wakeup_fd_eventfd.c \
     src/core/iomgr/wakeup_fd_nospecial.c \
     src/core/iomgr/wakeup_fd_pipe.c \
@@ -4307,6 +4406,7 @@
     src/core/iomgr/tcp_server_windows.c \
     src/core/iomgr/tcp_windows.c \
     src/core/iomgr/time_averaged_stats.c \
+    src/core/iomgr/udp_server.c \
     src/core/iomgr/wakeup_fd_eventfd.c \
     src/core/iomgr/wakeup_fd_nospecial.c \
     src/core/iomgr/wakeup_fd_pipe.c \
@@ -4410,6 +4510,48 @@
 endif
 
 
+LIBGRPC_ZOOKEEPER_SRC = \
+    src/core/client_config/resolvers/zookeeper_resolver.c \
+
+PUBLIC_HEADERS_C += \
+    include/grpc/grpc_zookeeper.h \
+
+LIBGRPC_ZOOKEEPER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_ZOOKEEPER_SRC))))
+
+$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a: $(ZLIB_DEP) $(LIBGRPC_ZOOKEEPER_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(LIBGRPC_ZOOKEEPER_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
+endif
+
+
+
+ifeq ($(SYSTEM),MINGW32)
+$(LIBDIR)/$(CONFIG)/grpc_zookeeper.$(SHARED_EXT): $(LIBGRPC_ZOOKEEPER_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_zookeeper.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper-imp.a -o $(LIBDIR)/$(CONFIG)/grpc_zookeeper.$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) -lgpr-imp -lgrpc-imp
+else
+$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT): $(LIBGRPC_ZOOKEEPER_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+ifeq ($(SYSTEM),Darwin)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_zookeeper.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) -lgpr -lgrpc -lzookeeper_mt
+else
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_zookeeper.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) -lgpr -lgrpc -lzookeeper_mt
+	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.so.0
+	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.so
+endif
+endif
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC_ZOOKEEPER_OBJS:.o=.dep)
+endif
+
+
 LIBRECONNECT_SERVER_SRC = \
     test/core/util/reconnect_server.c \
 
@@ -6943,35 +7085,6 @@
 endif
 
 
-GPR_CANCELLABLE_TEST_SRC = \
-    test/core/support/cancellable_test.c \
-
-GPR_CANCELLABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_CANCELLABLE_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/gpr_cancellable_test: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/gpr_cancellable_test: $(GPR_CANCELLABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GPR_CANCELLABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_cancellable_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/support/cancellable_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_gpr_cancellable_test: $(GPR_CANCELLABLE_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GPR_CANCELLABLE_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 GPR_CMDLINE_TEST_SRC = \
     test/core/support/cmdline_test.c \
 
@@ -8567,6 +8680,35 @@
 endif
 
 
+UDP_SERVER_TEST_SRC = \
+    test/core/iomgr/udp_server_test.c \
+
+UDP_SERVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(UDP_SERVER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/udp_server_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/udp_server_test: $(UDP_SERVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(UDP_SERVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/udp_server_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/udp_server_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_udp_server_test: $(UDP_SERVER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(UDP_SERVER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 URI_PARSER_TEST_SRC = \
     test/core/client_config/uri_parser_test.c \
 
@@ -10246,6 +10388,46 @@
 endif
 
 
+ZOOKEEPER_TEST_SRC = \
+    test/cpp/end2end/zookeeper_test.cc \
+
+ZOOKEEPER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ZOOKEEPER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/zookeeper_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)/zookeeper_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/zookeeper_test: $(PROTOBUF_DEP) $(ZOOKEEPER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ZOOKEEPER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -lzookeeper_mt $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/zookeeper_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/zookeeper_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_zookeeper_test: $(ZOOKEEPER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ZOOKEEPER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ifeq ($(NO_SECURE),true)
 
 # You can't build secure targets if you don't have OpenSSL.
diff --git a/build.json b/build.json
index 896cbee..f7be17e 100644
--- a/build.json
+++ b/build.json
@@ -171,6 +171,7 @@
         "src/core/iomgr/tcp_server.h",
         "src/core/iomgr/tcp_windows.h",
         "src/core/iomgr/time_averaged_stats.h",
+        "src/core/iomgr/udp_server.h",
         "src/core/iomgr/wakeup_fd_pipe.h",
         "src/core/iomgr/wakeup_fd_posix.h",
         "src/core/json/json.h",
@@ -274,6 +275,7 @@
         "src/core/iomgr/tcp_server_windows.c",
         "src/core/iomgr/tcp_windows.c",
         "src/core/iomgr/time_averaged_stats.c",
+        "src/core/iomgr/udp_server.c",
         "src/core/iomgr/wakeup_fd_eventfd.c",
         "src/core/iomgr/wakeup_fd_nospecial.c",
         "src/core/iomgr/wakeup_fd_pipe.c",
@@ -367,7 +369,6 @@
         "include/grpc/support/atm_gcc_atomic.h",
         "include/grpc/support/atm_gcc_sync.h",
         "include/grpc/support/atm_win32.h",
-        "include/grpc/support/cancellable_platform.h",
         "include/grpc/support/cmdline.h",
         "include/grpc/support/cpu.h",
         "include/grpc/support/histogram.h",
@@ -402,7 +403,6 @@
       ],
       "src": [
         "src/core/support/alloc.c",
-        "src/core/support/cancellable.c",
         "src/core/support/cmdline.c",
         "src/core/support/cpu_iphone.c",
         "src/core/support/cpu_linux.c",
@@ -573,6 +573,29 @@
       "vs_project_guid": "{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}"
     },
     {
+      "name": "grpc_zookeeper",
+      "build": "all",
+      "language": "c",
+      "public_headers": [
+        "include/grpc/grpc_zookeeper.h"
+      ],
+      "headers": [
+        "src/core/client_config/resolvers/zookeeper_resolver.h"
+      ],
+      "src": [
+        "src/core/client_config/resolvers/zookeeper_resolver.c"
+      ],
+      "deps": [
+        "gpr",
+        "grpc"
+      ],
+      "external_deps": [
+        "zookeeper"
+      ],
+      "secure": "no",
+      "vs_project_guid": "{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}"
+    },
+    {
       "name": "reconnect_server",
       "build": "private",
       "language": "c",
@@ -1107,18 +1130,6 @@
       ]
     },
     {
-      "name": "gpr_cancellable_test",
-      "build": "test",
-      "language": "c",
-      "src": [
-        "test/core/support/cancellable_test.c"
-      ],
-      "deps": [
-        "gpr_test_util",
-        "gpr"
-      ]
-    },
-    {
       "name": "gpr_cmdline_test",
       "build": "test",
       "language": "c",
@@ -1876,6 +1887,23 @@
       ]
     },
     {
+      "name": "udp_server_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/iomgr/udp_server_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ],
+      "platforms": [
+        "posix"
+      ]
+    },
+    {
       "name": "uri_parser_test",
       "build": "test",
       "language": "c",
@@ -2642,6 +2670,26 @@
         "gpr_test_util",
         "gpr"
       ]
+    },
+    {
+      "name": "zookeeper_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/end2end/zookeeper_test.cc"
+      ],
+      "deps": [
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc_zookeeper",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ],
+      "external_deps": [
+        "zookeeper"
+      ]
     }
   ]
 }
diff --git a/doc/connectivity-semantics-and-api.md b/doc/connectivity-semantics-and-api.md
index 930dff2..5427900 100644
--- a/doc/connectivity-semantics-and-api.md
+++ b/doc/connectivity-semantics-and-api.md
@@ -38,7 +38,7 @@
 large amounts of time in this state.
 
 IDLE: This is the state where the channel is not even trying to create a
-connection because of a lack of new or pending RPCs. New channels MAY be created
+connection because of a lack of new or pending RPCs. New RPCs  MAY be created
 in this state. Any attempt to start an RPC on the channel will push the channel
 out of this state to connecting. When there has been no RPC activity on a channel
 for a specified IDLE_TIMEOUT, i.e., no new or pending (active) RPCs for this
diff --git a/gRPC.podspec b/gRPC.podspec
index 12ce7c1..d945c29 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -73,7 +73,6 @@
                       'grpc/support/atm_gcc_atomic.h',
                       'grpc/support/atm_gcc_sync.h',
                       'grpc/support/atm_win32.h',
-                      'grpc/support/cancellable_platform.h',
                       'grpc/support/cmdline.h',
                       'grpc/support/cpu.h',
                       'grpc/support/histogram.h',
@@ -97,7 +96,6 @@
                       'grpc/support/tls_pthread.h',
                       'grpc/support/useful.h',
                       'src/core/support/alloc.c',
-                      'src/core/support/cancellable.c',
                       'src/core/support/cmdline.c',
                       'src/core/support/cpu_iphone.c',
                       'src/core/support/cpu_linux.c',
@@ -204,6 +202,7 @@
                       'src/core/iomgr/tcp_server.h',
                       'src/core/iomgr/tcp_windows.h',
                       'src/core/iomgr/time_averaged_stats.h',
+                      'src/core/iomgr/udp_server.h',
                       'src/core/iomgr/wakeup_fd_pipe.h',
                       'src/core/iomgr/wakeup_fd_posix.h',
                       'src/core/json/json.h',
@@ -335,6 +334,7 @@
                       'src/core/iomgr/tcp_server_windows.c',
                       'src/core/iomgr/tcp_windows.c',
                       'src/core/iomgr/time_averaged_stats.c',
+                      'src/core/iomgr/udp_server.c',
                       'src/core/iomgr/wakeup_fd_eventfd.c',
                       'src/core/iomgr/wakeup_fd_nospecial.c',
                       'src/core/iomgr/wakeup_fd_pipe.c',
@@ -471,6 +471,7 @@
                               'src/core/iomgr/tcp_server.h',
                               'src/core/iomgr/tcp_windows.h',
                               'src/core/iomgr/time_averaged_stats.h',
+                              'src/core/iomgr/udp_server.h',
                               'src/core/iomgr/wakeup_fd_pipe.h',
                               'src/core/iomgr/wakeup_fd_posix.h',
                               'src/core/json/json.h',
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index 34945f3..d7fafac 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -218,15 +218,11 @@
   void set_call(grpc_call* call,
                 const std::shared_ptr<ChannelInterface>& channel);
 
-  grpc_completion_queue* cq() { return cq_; }
-  void set_cq(grpc_completion_queue* cq) { cq_ = cq; }
-
   grpc::string authority() { return authority_; }
 
   bool initial_metadata_received_;
   std::shared_ptr<ChannelInterface> channel_;
   grpc_call* call_;
-  grpc_completion_queue* cq_;
   gpr_timespec deadline_;
   grpc::string authority_;
   std::shared_ptr<Credentials> creds_;
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index 0523ab6..2f30211 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -63,6 +63,7 @@
 class ServerStreamingHandler;
 template <class ServiceType, class RequestType, class ResponseType>
 class BidiStreamingHandler;
+class UnknownMethodHandler;
 
 class ChannelInterface;
 class ClientContext;
@@ -138,6 +139,7 @@
   friend class ServerStreamingHandler;
   template <class ServiceType, class RequestType, class ResponseType>
   friend class BidiStreamingHandler;
+  friend class UnknownMethodHandler;
   friend class ::grpc::Server;
   friend class ::grpc::ServerContext;
   template <class InputMessage, class OutputMessage>
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index 1fa4490..d49102f 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -173,6 +173,7 @@
     grpc_op* op = &ops[(*nops)++];
     op->op = GRPC_OP_SEND_INITIAL_METADATA;
     op->flags = 0;
+    op->reserved = NULL;
     op->data.send_initial_metadata.count = initial_metadata_count_;
     op->data.send_initial_metadata.metadata = initial_metadata_;
   }
@@ -206,6 +207,7 @@
     grpc_op* op = &ops[(*nops)++];
     op->op = GRPC_OP_SEND_MESSAGE;
     op->flags = write_options_.flags();
+    op->reserved = NULL;
     op->data.send_message = send_buf_;
     // Flags are per-message: clear them after use.
     write_options_.Clear();
@@ -248,6 +250,7 @@
     grpc_op* op = &ops[(*nops)++];
     op->op = GRPC_OP_RECV_MESSAGE;
     op->flags = 0;
+    op->reserved = NULL;
     op->data.recv_message = &recv_buf_;
   }
 
@@ -313,6 +316,7 @@
     grpc_op* op = &ops[(*nops)++];
     op->op = GRPC_OP_RECV_MESSAGE;
     op->flags = 0;
+    op->reserved = NULL;
     op->data.recv_message = &recv_buf_;
   }
 
@@ -350,6 +354,7 @@
     grpc_op* op = &ops[(*nops)++];
     op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
     op->flags = 0;
+    op->reserved = NULL;
   }
   void FinishOp(bool* status, int max_message_size) { send_ = false; }
 
@@ -383,6 +388,7 @@
     op->data.send_status_from_server.status_details =
         send_status_details_.empty() ? nullptr : send_status_details_.c_str();
     op->flags = 0;
+    op->reserved = NULL;
   }
 
   void FinishOp(bool* status, int max_message_size) {
@@ -416,6 +422,7 @@
     op->op = GRPC_OP_RECV_INITIAL_METADATA;
     op->data.recv_initial_metadata = &recv_initial_metadata_arr_;
     op->flags = 0;
+    op->reserved = NULL;
   }
   void FinishOp(bool* status, int max_message_size) {
     if (recv_initial_metadata_ == nullptr) return;
@@ -453,6 +460,7 @@
     op->data.recv_status_on_client.status_details_capacity =
         &status_details_capacity_;
     op->flags = 0;
+    op->reserved = NULL;
   }
 
   void FinishOp(bool* status, int max_message_size) {
diff --git a/include/grpc++/impl/rpc_service_method.h b/include/grpc++/impl/rpc_service_method.h
index 3cfbef7..925801e 100644
--- a/include/grpc++/impl/rpc_service_method.h
+++ b/include/grpc++/impl/rpc_service_method.h
@@ -208,6 +208,21 @@
   ServiceType* service_;
 };
 
+// Handle unknown method by returning UNIMPLEMENTED error.
+class UnknownMethodHandler : public MethodHandler {
+ public:
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    Status status(StatusCode::UNIMPLEMENTED, "");
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    if (!param.server_context->sent_initial_metadata_) {
+      ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+};
+
 // Server side rpc method class
 class RpcServiceMethod : public RpcMethod {
  public:
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index 94ee0b6..8755b4b 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -228,6 +228,8 @@
   grpc::condition_variable callback_cv_;
 
   std::list<SyncRequest>* sync_methods_;
+  std::unique_ptr<RpcServiceMethod> unknown_method_;
+  bool has_generic_service_;
 
   // Pointer to the c grpc server.
   grpc_server* const server_;
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index 4f7fc54..8262dee 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -73,6 +73,7 @@
 class ServerStreamingHandler;
 template <class ServiceType, class RequestType, class ResponseType>
 class BidiStreamingHandler;
+class UnknownMethodHandler;
 
 class Call;
 class CallOpBuffer;
@@ -159,6 +160,7 @@
   friend class ServerStreamingHandler;
   template <class ServiceType, class RequestType, class ResponseType>
   friend class BidiStreamingHandler;
+  friend class UnknownMethodHandler;
   friend class ::grpc::ClientContext;
 
   // Prevent copying.
diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h
index 913e2a7..1433ffd 100644
--- a/include/grpc/byte_buffer.h
+++ b/include/grpc/byte_buffer.h
@@ -47,9 +47,13 @@
 } grpc_byte_buffer_type;
 
 struct grpc_byte_buffer {
+  void *reserved;
   grpc_byte_buffer_type type;
   union {
     struct {
+      void *reserved[8];
+    } reserved;
+    struct {
       grpc_compression_algorithm compression;
       gpr_slice_buffer slice_buffer;
     } raw;
diff --git a/include/grpc/census.h b/include/grpc/census.h
index 7603dfd..a18b997 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -104,6 +104,61 @@
  * future census calls will result in undefined behavior. */
 void census_context_destroy(census_context *context);
 
+/* Max number of characters in tag key */
+#define CENSUS_MAX_TAG_KEY_LENGTH 20
+/* Max number of tag value characters */
+#define CENSUS_MAX_TAG_VALUE_LENGTH 50
+
+/* A Census tag set is a collection of key:value string pairs; these form the
+   basis against which Census metrics will be recorded. Keys are unique within
+   a tag set. All contexts have an associated tag set. */
+typedef struct census_tag_set census_tag_set;
+
+/* Returns a pointer to a newly created, empty tag set. If size_hint > 0,
+   indicates that the tag set is intended to hold approximately that number
+   of tags. */
+census_tag_set *census_tag_set_create(size_t size_hint);
+
+/* Add a new tag key/value to an existing tag set; if the tag key already exists
+   in the tag set, then its value is overwritten with the new one. Can also be
+   used to delete a tag, by specifying a NULL value. If key is NULL, returns
+   the number of tags in the tag set.
+   Return values:
+   -1: invalid length key or value
+   non-negative value: the number of tags in the tag set. */
+int census_tag_set_add(census_tag_set *tags, const char *key,
+                       const char *value);
+
+/* Destroys a tag set. This function must be called to prevent memory leaks.
+   Once called, the tag set cannot be used again. */
+void census_tag_set_destroy(census_tag_set *tags);
+
+/* Get a contexts tag set. */
+census_tag_set *census_context_tag_set(census_context *context);
+
+/* A read-only representation of a tag for use by census clients. */
+typedef struct {
+  size_t key_len;    /* Number of bytes in tag key. */
+  const char *key;   /* A pointer to the tag key. May not be null-terminated. */
+  size_t value_len;  /* Number of bytes in tag value. */
+  const char *value; /* Pointer to the tag value. May not be null-terminated. */
+} census_tag_const;
+
+/* Used to iterate through a tag sets contents. */
+typedef struct census_tag_set_iterator census_tag_set_iterator;
+
+/* Open a tag set for iteration. The tag set must not be modified while
+   iteration is ongoing. Returns an iterator for use in following functions. */
+census_tag_set_iterator *census_tag_set_open(census_tag_set *tags);
+
+/* Get the next tag in the tag set, by writing into the 'tag' argument. Returns
+   1 if there is a "next" tag, 0 if there are no more tags. */
+int census_tag_set_next(census_tag_set_iterator *it, census_tag_const *tag);
+
+/* Close an iterator opened by census_tag_set_open(). The iterator will be
+   invalidated, and should not be used once close is called. */
+void census_tag_set_close(census_tag_set_iterator *it);
+
 /* A census statistic to be recorded comprises two parts: an ID for the
  * particular statistic and the value to be recorded against it. */
 typedef struct {
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 5915dda..2d53325 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -202,13 +202,14 @@
   const char *key;
   const char *value;
   size_t value_length;
+  gpr_uint32 flags;
 
   /** The following fields are reserved for grpc internal use.
       There is no need to initialize them, and they will be set to garbage
      during
       calls to grpc. */
   struct {
-    void *obfuscated[3];
+    void *obfuscated[4];
   } internal_data;
 } grpc_metadata;
 
@@ -251,6 +252,7 @@
   char *host;
   size_t host_capacity;
   gpr_timespec deadline;
+  void *reserved;
 } grpc_call_details;
 
 void grpc_call_details_init(grpc_call_details *details);
@@ -306,7 +308,13 @@
   grpc_op_type op;
   /** Write flags bitset for grpc_begin_messages */
   gpr_uint32 flags;
+  /** Reserved for future usage */
+  void *reserved;
   union {
+    /** Reserved for future usage */
+    struct {
+      void *reserved[8];
+    } reserved;
     struct {
       size_t count;
       grpc_metadata *metadata;
@@ -368,6 +376,23 @@
   } data;
 } grpc_op;
 
+/** Registers a plugin to be initialized and destroyed with the library.
+
+    The \a init and \a destroy functions will be invoked as part of 
+    \a grpc_init() and \a grpc_shutdown(), respectively. 
+    Note that these functions can be invoked an arbitrary number of times
+    (and hence so will \a init and \a destroy).
+    It is safe to pass NULL to either argument. Plugins are destroyed in 
+    the reverse order they were initialized. */
+void grpc_register_plugin(void (*init)(void), void (*destroy)(void));
+
+/** Frees the memory used by all the plugin information.
+
+    While grpc_init and grpc_shutdown can be called multiple times, the plugins
+    won't be unregistered and their memory cleaned up unless you call that
+    function. Using atexit(grpc_unregister_all_plugins) is a valid method. */
+void grpc_unregister_all_plugins();
+
 /* Propagation bits: this can be bitwise or-ed to form propagation_mask for
  * grpc_call */
 /** Propagate deadline */
@@ -380,8 +405,8 @@
 
 /* Default propagation mask: clients of the core API are encouraged to encode
    deltas from this in their implementations... ie write:
-   GRPC_PROPAGATE_DEFAULTS & ~GRPC_PROPAGATE_DEADLINE to disable deadline 
-   propagation. Doing so gives flexibility in the future to define new 
+   GRPC_PROPAGATE_DEFAULTS & ~GRPC_PROPAGATE_DEADLINE to disable deadline
+   propagation. Doing so gives flexibility in the future to define new
    propagation types that are default inherited or not. */
 #define GRPC_PROPAGATE_DEFAULTS                                                \
   ((gpr_uint32)((                                                              \
@@ -408,7 +433,7 @@
 const char *grpc_version_string(void);
 
 /** Create a completion queue */
-grpc_completion_queue *grpc_completion_queue_create(void);
+grpc_completion_queue *grpc_completion_queue_create(void *reserved);
 
 /** Blocks until an event is available, the completion queue is being shut down,
     or deadline is reached.
@@ -419,7 +444,7 @@
     Callers must not call grpc_completion_queue_next and
     grpc_completion_queue_pluck simultaneously on the same completion queue. */
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
-                                      gpr_timespec deadline);
+                                      gpr_timespec deadline, void *reserved);
 
 /** Blocks until an event with tag 'tag' is available, the completion queue is
     being shutdown or deadline is reached.
@@ -428,12 +453,12 @@
     otherwise a grpc_event describing the event that occurred.
 
     Callers must not call grpc_completion_queue_next and
-    grpc_completion_queue_pluck simultaneously on the same completion queue. 
-    
+    grpc_completion_queue_pluck simultaneously on the same completion queue.
+
     Completion queues support a maximum of GRPC_MAX_COMPLETION_QUEUE_PLUCKERS
     concurrently executing plucks at any time. */
 grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
-                                       gpr_timespec deadline);
+                                       gpr_timespec deadline, void *reserved);
 
 /** Maximum number of outstanding grpc_completion_queue_pluck executions per
     completion queue */
@@ -469,24 +494,24 @@
     completions are sent to 'completion_queue'. 'method' and 'host' need only
     live through the invocation of this function.
     If parent_call is non-NULL, it must be a server-side call. It will be used
-    to propagate properties from the server call to this new client call. 
+    to propagate properties from the server call to this new client call.
     */
 grpc_call *grpc_channel_create_call(grpc_channel *channel,
                                     grpc_call *parent_call,
                                     gpr_uint32 propagation_mask,
                                     grpc_completion_queue *completion_queue,
                                     const char *method, const char *host,
-                                    gpr_timespec deadline);
+                                    gpr_timespec deadline, void *reserved);
 
 /** Pre-register a method/host pair on a channel. */
 void *grpc_channel_register_call(grpc_channel *channel, const char *method,
-                                 const char *host);
+                                 const char *host, void *reserved);
 
 /** Create a call given a handle returned from grpc_channel_register_call */
 grpc_call *grpc_channel_create_registered_call(
     grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask,
     grpc_completion_queue *completion_queue, void *registered_call_handle,
-    gpr_timespec deadline);
+    gpr_timespec deadline, void *reserved);
 
 /** Start a batch of operations defined in the array ops; when complete, post a
     completion of type 'tag' to the completion queue bound to the call.
@@ -500,7 +525,7 @@
     containing just send operations independently from batches containing just
     receive operations. */
 grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
-                                      size_t nops, void *tag);
+                                      size_t nops, void *tag, void *reserved);
 
 /** Returns a newly allocated string representing the endpoint to which this
     call is communicating with. The string is in the uri format accepted by
@@ -532,7 +557,8 @@
     more on this. The data in 'args' need only live through the invocation of
     this function. */
 grpc_channel *grpc_insecure_channel_create(const char *target,
-                                           const grpc_channel_args *args);
+                                           const grpc_channel_args *args,
+                                           void *reserved);
 
 /** Create a lame client: this client fails every operation attempted on it. */
 grpc_channel *grpc_lame_client_channel_create(const char *target);
@@ -551,7 +577,7 @@
     THREAD-SAFETY grpc_call_cancel and grpc_call_cancel_with_status
     are thread-safe, and can be called at any point before grpc_call_destroy
     is called.*/
-grpc_call_error grpc_call_cancel(grpc_call *call);
+grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved);
 
 /** Called by clients to cancel an RPC on the server.
     Can be called multiple times, from any thread.
@@ -561,7 +587,8 @@
     remote endpoint. */
 grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
                                              grpc_status_code status,
-                                             const char *description);
+                                             const char *description,
+                                             void *reserved);
 
 /** Destroy a call.
     THREAD SAFETY: grpc_call_destroy is thread-compatible */
@@ -600,14 +627,16 @@
     be specified with args. If no additional configuration is needed, args can
     be NULL. See grpc_channel_args for more. The data in 'args' need only live
     through the invocation of this function. */
-grpc_server *grpc_server_create(const grpc_channel_args *args);
+grpc_server *grpc_server_create(const grpc_channel_args *args,
+                                void *reserved);
 
 /** Register a completion queue with the server. Must be done for any
     notification completion queue that is passed to grpc_server_request_*_call
     and to grpc_server_shutdown_and_notify. Must be performed prior to
     grpc_server_start. */
 void grpc_server_register_completion_queue(grpc_server *server,
-                                           grpc_completion_queue *cq);
+                                           grpc_completion_queue *cq,
+                                           void *reserved);
 
 /** Add a HTTP2 over plaintext over tcp listener.
     Returns bound port number on success, 0 on failure.
diff --git a/include/grpc/support/cancellable_platform.h b/include/grpc/grpc_zookeeper.h
similarity index 69%
rename from include/grpc/support/cancellable_platform.h
rename to include/grpc/grpc_zookeeper.h
index e8e4b84..2b195c1 100644
--- a/include/grpc/support/cancellable_platform.h
+++ b/include/grpc/grpc_zookeeper.h
@@ -31,26 +31,29 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_CANCELLABLE_PLATFORM_H
-#define GRPC_SUPPORT_CANCELLABLE_PLATFORM_H
+/** Support zookeeper as alternative name system in addition to DNS
+ *  Zookeeper name in gRPC is represented as a URI:
+ *  zookeeper://host:port/path/service/instance
+ *
+ *  Where zookeeper is the name system scheme
+ *  host:port is the address of a zookeeper server
+ *  /path/service/instance is the zookeeper name to be resolved
+ *
+ *  Refer doc/naming.md for more details
+ */
 
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
+#ifndef GRPC_GRPC_ZOOKEEPER_H
+#define GRPC_GRPC_ZOOKEEPER_H
 
-struct gpr_cancellable_list_ {
-  /* a doubly-linked list on cancellable's waiters queue */
-  struct gpr_cancellable_list_ *next;
-  struct gpr_cancellable_list_ *prev;
-  /* The following two fields are arguments to gpr_cv_cancellable_wait() */
-  gpr_mu *mu;
-  gpr_cv *cv;
-};
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-/* Internal definition of gpr_cancellable. */
-typedef struct {
-  gpr_mu mu; /* protects waiters and modifications to cancelled */
-  gpr_atm cancelled;
-  struct gpr_cancellable_list_ waiters;
-} gpr_cancellable;
+/** Register zookeeper name resolver in grpc */
+void grpc_zookeeper_register();
 
-#endif  /* GRPC_SUPPORT_CANCELLABLE_PLATFORM_H */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_GRPC_ZOOKEEPER_H */
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index 57fed18..d5745f9 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -173,6 +173,8 @@
 #endif /* _LP64 */
 #elif defined(__APPLE__)
 #include <TargetConditionals.h>
+/* Provides IPV6_RECVPKTINFO */
+#define __APPLE_USE_RFC_3542
 #ifndef _BSD_SOURCE
 #define _BSD_SOURCE
 #endif
diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h
index 1cdde1d..1dd826a 100644
--- a/include/grpc/support/sync.h
+++ b/include/grpc/support/sync.h
@@ -65,7 +65,6 @@
 #endif
 
 #include <grpc/support/time.h> /* for gpr_timespec */
-#include <grpc/support/cancellable_platform.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -121,11 +120,6 @@
    holds an exclusive lock on *mu.  */
 int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
 
-/* Behave like gpr_cv_wait(cv, mu, abs_deadline), except behave as though
-   the deadline has expired if *c is cancelled. */
-int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline,
-                            gpr_cancellable *c);
-
 /* If any threads are waiting on *cv, wake at least one.
    Clients may treat this as an optimization of gpr_cv_broadcast()
    for use in the case where waking more than one waiter is not useful.
@@ -135,28 +129,6 @@
 /* Wake all threads waiting on *cv.  Requires:  *cv initialized.  */
 void gpr_cv_broadcast(gpr_cv *cv);
 
-/* --- Cancellation ---
-   A gpr_cancellable can be used with gpr_cv_cancellable_wait()
-   or gpr_event_cancellable_wait() cancel pending waits. */
-
-/* Initialize *c. */
-void gpr_cancellable_init(gpr_cancellable *c);
-
-/* Cause *c no longer to be initialized, freeing any memory in use.  Requires:
-   *c initialized; no other concurrent operation on *c.  */
-void gpr_cancellable_destroy(gpr_cancellable *c);
-
-/* Return non-zero iff *c has been cancelled.  Requires *c initialized.
-   This call is faster than acquiring a mutex on most platforms. */
-int gpr_cancellable_is_cancelled(gpr_cancellable *c);
-
-/* Cancel *c.  If *c was not previously cancelled, cause
-   gpr_cancellable_init() to return non-zero, and outstanding and future
-   calls to gpr_cv_cancellable_wait() and gpr_event_cancellable_wait() to
-   return immediately indicating a timeout has occurred; otherwise do nothing.
-   Requires *c initialized.*/
-void gpr_cancellable_cancel(gpr_cancellable *c);
-
 /* --- One-time initialization ---
 
    gpr_once must be declared with static storage class, and initialized with
@@ -199,11 +171,6 @@
    on most platforms.  */
 void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline);
 
-/* Behave like gpr_event_wait(ev, abs_deadline), except behave as though
-   the deadline has expired if *c is cancelled. */
-void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline,
-                                 gpr_cancellable *c);
-
 /* --- Reference counting ---
 
    These calls act on the type gpr_refcount.  It requires no destruction.  */
diff --git a/src/compiler/csharp_generator_helpers.h b/src/compiler/csharp_generator_helpers.h
index 1370627..5639ea0 100644
--- a/src/compiler/csharp_generator_helpers.h
+++ b/src/compiler/csharp_generator_helpers.h
@@ -41,7 +41,7 @@
 
 inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
                              grpc::string *file_name_or_error) {
-  *file_name_or_error = grpc_generator::FileNameInUpperCamel(file) + "Grpc.cs";
+  *file_name_or_error = grpc_generator::FileNameInUpperCamel(file, false) + "Grpc.cs";
   return true;
 }
 
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 68b807b..e1bb66a 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -125,16 +125,23 @@
   return result;
 }
 
-inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file,
+                                         bool include_package_path) {
   std::vector<grpc::string> tokens = tokenize(StripProto(file->name()), "/");
   grpc::string result = "";
-  for (unsigned int i = 0; i < tokens.size() - 1; i++) {
-    result += tokens[i] + "/";
+  if (include_package_path) {
+    for (unsigned int i = 0; i < tokens.size() - 1; i++) {
+      result += tokens[i] + "/";
+    }
   }
   result += LowerUnderscoreToUpperCamel(tokens.back());
   return result;
 }
 
+inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+  return FileNameInUpperCamel(file, true);
+}
+
 enum MethodType {
   METHODTYPE_NO_STREAMING,
   METHODTYPE_CLIENT_STREAMING,
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index 69b3805..a3157db 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -44,7 +44,6 @@
 using ::grpc::protobuf::io::Printer;
 using ::grpc::protobuf::MethodDescriptor;
 using ::grpc::protobuf::ServiceDescriptor;
-using ::grpc::string;
 using ::std::map;
 
 namespace grpc_objective_c_generator {
@@ -52,7 +51,7 @@
 
 void PrintProtoRpcDeclarationAsPragma(Printer *printer,
                                       const MethodDescriptor *method,
-                                      map<string, string> vars) {
+                                      map< ::grpc::string, ::grpc::string> vars) {
   vars["client_stream"] = method->client_streaming() ? "stream " : "";
   vars["server_stream"] = method->server_streaming() ? "stream " : "";
 
@@ -62,7 +61,7 @@
 }
 
 void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
-                          const map<string, string> &vars) {
+                          const map< ::grpc::string, ::grpc::string> &vars) {
   // TODO(jcanizales): Print method comments.
 
   printer->Print(vars, "- ($return_type$)$method_name$With");
@@ -85,7 +84,7 @@
 }
 
 void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
-                          map<string, string> vars) {
+                          map< ::grpc::string, ::grpc::string> vars) {
   vars["method_name"] =
       grpc_generator::LowercaseFirstLetter(vars["method_name"]);
   vars["return_type"] = "void";
@@ -93,14 +92,14 @@
 }
 
 void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
-                            map<string, string> vars) {
+                            map< ::grpc::string, ::grpc::string> vars) {
   vars["method_name"] = "RPCTo" + vars["method_name"];
   vars["return_type"] = "ProtoRPC *";
   PrintMethodSignature(printer, method, vars);
 }
 
-inline map<string, string> GetMethodVars(const MethodDescriptor *method) {
-  map<string, string> res;
+inline map< ::grpc::string, ::grpc::string> GetMethodVars(const MethodDescriptor *method) {
+  map< ::grpc::string, ::grpc::string> res;
   res["method_name"] = method->name();
   res["request_type"] = method->input_type()->name();
   res["response_type"] = method->output_type()->name();
@@ -110,7 +109,7 @@
 }
 
 void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
-  map<string, string> vars = GetMethodVars(method);
+  map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
 
   PrintProtoRpcDeclarationAsPragma(printer, method, vars);
 
@@ -121,7 +120,7 @@
 }
 
 void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
-                               map<string, string> vars) {
+                               map< ::grpc::string, ::grpc::string> vars) {
   printer->Print("{\n");
   printer->Print(vars, "  [[self RPCTo$method_name$With");
   if (method->client_streaming()) {
@@ -139,7 +138,7 @@
 
 void PrintAdvancedImplementation(Printer *printer,
                                  const MethodDescriptor *method,
-                                 map<string, string> vars) {
+                                 map< ::grpc::string, ::grpc::string> vars) {
   printer->Print("{\n");
   printer->Print(vars, "  return [self RPCToMethod:@\"$method_name$\"\n");
 
@@ -154,9 +153,9 @@
 
   printer->Print("        responsesWriteable:[GRXWriteable ");
   if (method->server_streaming()) {
-    printer->Print("writeableWithStreamHandler:eventHandler]];\n");
+    printer->Print("writeableWithEventHandler:eventHandler]];\n");
   } else {
-    printer->Print("writeableWithSingleValueHandler:handler]];\n");
+    printer->Print("writeableWithSingleHandler:handler]];\n");
   }
 
   printer->Print("}\n");
@@ -164,7 +163,7 @@
 
 void PrintMethodImplementations(Printer *printer,
                                 const MethodDescriptor *method) {
-  map<string, string> vars = GetMethodVars(method);
+  map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
 
   PrintProtoRpcDeclarationAsPragma(printer, method, vars);
 
@@ -179,14 +178,14 @@
 
 }  // namespace
 
-string GetHeader(const ServiceDescriptor *service) {
-  string output;
+::grpc::string GetHeader(const ServiceDescriptor *service) {
+  ::grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     Printer printer(&output_stream, '$');
 
-    map<string, string> vars = {{"service_class", ServiceClassName(service)}};
+    map< ::grpc::string, ::grpc::string> vars = {{"service_class", ServiceClassName(service)}};
 
     printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
 
@@ -209,14 +208,14 @@
   return output;
 }
 
-string GetSource(const ServiceDescriptor *service) {
-  string output;
+::grpc::string GetSource(const ServiceDescriptor *service) {
+ ::grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     Printer printer(&output_stream, '$');
 
-    map<string, string> vars = {{"service_name", service->name()},
+    map< ::grpc::string,::grpc::string> vars = {{"service_name", service->name()},
                                 {"service_class", ServiceClassName(service)},
                                 {"package", service->file()->package()}};
 
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index 10f06ad..1744035 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -39,44 +39,43 @@
 #include "src/compiler/objective_c_generator.h"
 #include "src/compiler/objective_c_generator_helpers.h"
 
-using ::grpc::string;
-
 class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  public:
   ObjectiveCGrpcGenerator() {}
   virtual ~ObjectiveCGrpcGenerator() {}
 
   virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
-                        const string &parameter,
+                        const ::grpc::string &parameter,
                         grpc::protobuf::compiler::GeneratorContext *context,
-                        string *error) const {
+                        ::grpc::string *error) const {
 
     if (file->service_count() == 0) {
       // No services.  Do nothing.
       return true;
     }
 
-    string file_name = grpc_generator::FileNameInUpperCamel(file);
-    string prefix = file->options().objc_class_prefix();
+    ::grpc::string file_name = grpc_generator::FileNameInUpperCamel(file);
+    ::grpc::string prefix = file->options().objc_class_prefix();
 
     {
       // Generate .pbrpc.h
 
-      string imports = string("#import \"") + file_name + ".pbobjc.h\"\n\n"
+      ::grpc::string imports = ::grpc::string("#import \"") + file_name +
+        ".pbobjc.h\"\n\n"
         "#import <ProtoRPC/ProtoService.h>\n"
         "#import <RxLibrary/GRXWriteable.h>\n"
         "#import <RxLibrary/GRXWriter.h>\n";
 
       // TODO(jcanizales): Instead forward-declare the input and output types
       // and import the files in the .pbrpc.m
-      string proto_imports;
+      ::grpc::string proto_imports;
       for (int i = 0; i < file->dependency_count(); i++) {
-        string header = grpc_objective_c_generator::MessageHeaderName(
+        ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(
             file->dependency(i));
-        proto_imports += string("#import \"") + header + "\"\n";
+        proto_imports += ::grpc::string("#import \"") + header + "\"\n";
       }
 
-      string declarations;
+      ::grpc::string declarations;
       for (int i = 0; i < file->service_count(); i++) {
         const grpc::protobuf::ServiceDescriptor *service = file->service(i);
         declarations += grpc_objective_c_generator::GetHeader(service);
@@ -89,11 +88,12 @@
     {
       // Generate .pbrpc.m
 
-      string imports = string("#import \"") + file_name + ".pbrpc.h\"\n\n"
+      ::grpc::string imports = ::grpc::string("#import \"") + file_name +
+        ".pbrpc.h\"\n\n"
         "#import <ProtoRPC/ProtoRPC.h>\n"
         "#import <RxLibrary/GRXWriter+Immediate.h>\n";
 
-      string definitions;
+      ::grpc::string definitions;
       for (int i = 0; i < file->service_count(); i++) {
         const grpc::protobuf::ServiceDescriptor *service = file->service(i);
         definitions += grpc_objective_c_generator::GetSource(service);
@@ -108,7 +108,7 @@
  private:
   // Write the given code into the given file.
   void Write(grpc::protobuf::compiler::GeneratorContext *context,
-              const string &filename, const string &code) const {
+              const ::grpc::string &filename, const ::grpc::string &code) const {
     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
         context->Open(filename));
     grpc::protobuf::io::CodedOutputStream coded_out(output.get());
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c
new file mode 100644
index 0000000..a8397a3
--- /dev/null
+++ b/src/core/client_config/resolvers/zookeeper_resolver.c
@@ -0,0 +1,501 @@
+/*
+ *
+ * Copyright 2015, 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 "src/core/client_config/resolvers/zookeeper_resolver.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include <grpc/grpc_zookeeper.h>
+#include <zookeeper/zookeeper.h>
+
+#include "src/core/client_config/lb_policies/pick_first.h"
+#include "src/core/client_config/resolver_registry.h"
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/support/string.h"
+#include "src/core/json/json.h"
+
+/** Zookeeper session expiration time in milliseconds */
+#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000
+
+typedef struct {
+  /** base class: must be first */
+  grpc_resolver base;
+  /** refcount */
+  gpr_refcount refs;
+  /** name to resolve */
+  char *name;
+  /** subchannel factory */
+  grpc_subchannel_factory *subchannel_factory;
+  /** load balancing policy factory */
+  grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+                                       size_t num_subchannels);
+
+  /** mutex guarding the rest of the state */
+  gpr_mu mu;
+  /** are we currently resolving? */
+  int resolving;
+  /** which version of resolved_config have we published? */
+  int published_version;
+  /** which version of resolved_config is current? */
+  int resolved_version;
+  /** pending next completion, or NULL */
+  grpc_iomgr_closure *next_completion;
+  /** target config address for next completion */
+  grpc_client_config **target_config;
+  /** current (fully resolved) config */
+  grpc_client_config *resolved_config;
+
+  /** zookeeper handle */
+  zhandle_t *zookeeper_handle;
+  /** zookeeper resolved addresses */
+  grpc_resolved_addresses *resolved_addrs;
+  /** total number of addresses to be resolved */
+  int resolved_total;
+  /** number of addresses resolved */
+  int resolved_num;
+} zookeeper_resolver;
+
+static void zookeeper_destroy(grpc_resolver *r);
+
+static void zookeeper_start_resolving_locked(zookeeper_resolver *r);
+static void zookeeper_maybe_finish_next_locked(zookeeper_resolver *r);
+
+static void zookeeper_shutdown(grpc_resolver *r);
+static void zookeeper_channel_saw_error(grpc_resolver *r,
+                                        struct sockaddr *failing_address,
+                                        int failing_address_len);
+static void zookeeper_next(grpc_resolver *r, grpc_client_config **target_config,
+                           grpc_iomgr_closure *on_complete);
+
+static const grpc_resolver_vtable zookeeper_resolver_vtable = {
+    zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error,
+    zookeeper_next};
+
+static void zookeeper_shutdown(grpc_resolver *resolver) {
+  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (r->next_completion != NULL) {
+    *r->target_config = NULL;
+    grpc_iomgr_add_callback(r->next_completion);
+    r->next_completion = NULL;
+  }
+  zookeeper_close(r->zookeeper_handle);
+  gpr_mu_unlock(&r->mu);
+}
+
+static void zookeeper_channel_saw_error(grpc_resolver *resolver,
+                                        struct sockaddr *sa, int len) {
+  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (r->resolving == 0) {
+    zookeeper_start_resolving_locked(r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void zookeeper_next(grpc_resolver *resolver,
+                           grpc_client_config **target_config,
+                           grpc_iomgr_closure *on_complete) {
+  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(r->next_completion == NULL);
+  r->next_completion = on_complete;
+  r->target_config = target_config;
+  if (r->resolved_version == 0 && r->resolving == 0) {
+    zookeeper_start_resolving_locked(r);
+  } else {
+    zookeeper_maybe_finish_next_locked(r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+/** Zookeeper global watcher for connection management 
+    TODO: better connection management besides logs */
+static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type,
+                                     int state, const char *path,
+                                     void *watcher_ctx) {
+  if (type == ZOO_SESSION_EVENT) {
+    if (state == ZOO_EXPIRED_SESSION_STATE) {
+      gpr_log(GPR_ERROR, "Zookeeper session expired");
+    } else if (state == ZOO_AUTH_FAILED_STATE) {
+      gpr_log(GPR_ERROR, "Zookeeper authentication failed");
+    }
+  }
+}
+
+/** Zookeeper watcher triggered by changes to watched nodes
+    Once triggered, it tries to resolve again to get updated addresses */
+static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state,
+                              const char *path, void *watcher_ctx) {
+  if (watcher_ctx != NULL) {
+    zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx;
+    if (state == ZOO_CONNECTED_STATE) {
+      gpr_mu_lock(&r->mu);
+      if (r->resolving == 0) {
+        zookeeper_start_resolving_locked(r);
+      }
+      gpr_mu_unlock(&r->mu);
+    }
+  }
+}
+
+/** Callback function after getting all resolved addresses  
+    Creates a subchannel for each address */
+static void zookeeper_on_resolved(void *arg,
+                                  grpc_resolved_addresses *addresses) {
+  zookeeper_resolver *r = arg;
+  grpc_client_config *config = NULL;
+  grpc_subchannel **subchannels;
+  grpc_subchannel_args args;
+  grpc_lb_policy *lb_policy;
+  size_t i;
+  if (addresses != NULL) {
+    config = grpc_client_config_create();
+    subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
+    for (i = 0; i < addresses->naddrs; i++) {
+      memset(&args, 0, sizeof(args));
+      args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
+      args.addr_len = addresses->addrs[i].len;
+      subchannels[i] = grpc_subchannel_factory_create_subchannel(
+          r->subchannel_factory, &args);
+    }
+    lb_policy = r->lb_policy_factory(subchannels, addresses->naddrs);
+    grpc_client_config_set_lb_policy(config, lb_policy);
+    GRPC_LB_POLICY_UNREF(lb_policy, "construction");
+    grpc_resolved_addresses_destroy(addresses);
+    gpr_free(subchannels);
+  }
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(r->resolving == 1);
+  r->resolving = 0;
+  if (r->resolved_config != NULL) {
+    grpc_client_config_unref(r->resolved_config);
+  }
+  r->resolved_config = config;
+  r->resolved_version++;
+  zookeeper_maybe_finish_next_locked(r);
+  gpr_mu_unlock(&r->mu);
+
+  GRPC_RESOLVER_UNREF(&r->base, "zookeeper-resolving");
+}
+
+/** Callback function for each DNS resolved address */
+static void zookeeper_dns_resolved(void *arg,
+                                   grpc_resolved_addresses *addresses) {
+  size_t i;
+  zookeeper_resolver *r = arg;
+  int resolve_done = 0;
+
+  gpr_mu_lock(&r->mu);
+  r->resolved_num++;
+  r->resolved_addrs->addrs =
+      gpr_realloc(r->resolved_addrs->addrs,
+                  sizeof(grpc_resolved_address) *
+                      (r->resolved_addrs->naddrs + addresses->naddrs));
+  for (i = 0; i < addresses->naddrs; i++) {
+    memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr,
+           addresses->addrs[i].addr, addresses->addrs[i].len);
+    r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len =
+        addresses->addrs[i].len;
+  }
+
+  r->resolved_addrs->naddrs += addresses->naddrs;
+  grpc_resolved_addresses_destroy(addresses);
+
+  /** Wait for all addresses to be resolved */
+  resolve_done = (r->resolved_num == r->resolved_total);
+  gpr_mu_unlock(&r->mu);
+  if (resolve_done) {
+    zookeeper_on_resolved(r, r->resolved_addrs);
+  }
+}
+
+/** Parses JSON format address of a zookeeper node */
+static char *zookeeper_parse_address(const char *value, int value_len) {
+  grpc_json *json;
+  grpc_json *cur;
+  const char *host;
+  const char *port;
+  char* buffer;
+  char *address = NULL;
+
+  buffer = gpr_malloc(value_len);
+  memcpy(buffer, value, value_len);
+  json = grpc_json_parse_string_with_len(buffer, value_len);
+  if (json != NULL) {
+    host = NULL;
+    port = NULL;
+    for (cur = json->child; cur != NULL; cur = cur->next) {
+      if (!strcmp(cur->key, "host")) {
+        host = cur->value;
+        if (port != NULL) {
+          break;
+        }
+      } else if (!strcmp(cur->key, "port")) {
+        port = cur->value;
+        if (host != NULL) {
+          break;
+        }
+      }
+    }
+    if (host != NULL && port != NULL) {
+      gpr_asprintf(&address, "%s:%s", host, port);
+    }
+    grpc_json_destroy(json);
+  }
+  gpr_free(buffer);
+
+  return address;
+}
+
+static void zookeeper_get_children_node_completion(int rc, const char *value,
+                                                   int value_len,
+                                                   const struct Stat *stat,
+                                                   const void *arg) {
+  char *address = NULL;
+  zookeeper_resolver *r = (zookeeper_resolver *)arg;
+  int resolve_done = 0;
+
+  if (rc != 0) {
+    gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name);
+    return;
+  }
+
+  address = zookeeper_parse_address(value, value_len);
+  if (address != NULL) {
+    /** Further resolves address by DNS */
+    grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
+    gpr_free(address);
+  } else {
+    gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name);
+    gpr_mu_lock(&r->mu);
+    r->resolved_total--;
+    resolve_done = (r->resolved_num == r->resolved_total);
+    gpr_mu_unlock(&r->mu);
+    if (resolve_done) {
+      zookeeper_on_resolved(r, r->resolved_addrs);
+    }
+  }
+}
+
+static void zookeeper_get_children_completion(
+    int rc, const struct String_vector *children, const void *arg) {
+  char *path;
+  int status;
+  int i;
+  zookeeper_resolver *r = (zookeeper_resolver *)arg;
+
+  if (rc != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
+    return;
+  }
+
+  if (children->count == 0) {
+    gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name);
+    return;
+  }
+
+  r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+  r->resolved_addrs->addrs = NULL;
+  r->resolved_addrs->naddrs = 0;
+  r->resolved_total = children->count;
+
+  /** TODO: Replace expensive heap allocation with stack
+      if we can get maximum length of zookeeper path */
+  for (i = 0; i < children->count; i++) {
+    gpr_asprintf(&path, "%s/%s", r->name, children->data[i]);
+    status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r,
+                       zookeeper_get_children_node_completion, r);
+    gpr_free(path);
+    if (status != 0) {
+      gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path);
+    }
+  }
+}
+
+static void zookeeper_get_node_completion(int rc, const char *value,
+                                          int value_len,
+                                          const struct Stat *stat,
+                                          const void *arg) {
+  int status;
+  char *address = NULL;
+  zookeeper_resolver *r = (zookeeper_resolver *)arg;
+  r->resolved_addrs = NULL;
+  r->resolved_total = 0;
+  r->resolved_num = 0;
+
+  if (rc != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
+    return;
+  }
+
+  /** If zookeeper node of path r->name does not have address
+      (i.e. service node), get its children */
+  address = zookeeper_parse_address(value, value_len);
+  if (address != NULL) {
+    r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+    r->resolved_addrs->addrs = NULL;
+    r->resolved_addrs->naddrs = 0;
+    r->resolved_total = 1;
+    /** Further resolves address by DNS */
+    grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
+    gpr_free(address);
+    return;
+  }
+
+  status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher,
+                              r, zookeeper_get_children_completion, r);
+  if (status != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
+  }
+}
+
+static void zookeeper_resolve_address(zookeeper_resolver *r) {
+  int status;
+  status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r,
+                     zookeeper_get_node_completion, r);
+  if (status != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
+  }
+}
+
+static void zookeeper_start_resolving_locked(zookeeper_resolver *r) {
+  GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving");
+  GPR_ASSERT(r->resolving == 0);
+  r->resolving = 1;
+  zookeeper_resolve_address(r);
+}
+
+static void zookeeper_maybe_finish_next_locked(zookeeper_resolver *r) {
+  if (r->next_completion != NULL &&
+      r->resolved_version != r->published_version) {
+    *r->target_config = r->resolved_config;
+    if (r->resolved_config != NULL) {
+      grpc_client_config_ref(r->resolved_config);
+    }
+    grpc_iomgr_add_callback(r->next_completion);
+    r->next_completion = NULL;
+    r->published_version = r->resolved_version;
+  }
+}
+
+static void zookeeper_destroy(grpc_resolver *gr) {
+  zookeeper_resolver *r = (zookeeper_resolver *)gr;
+  gpr_mu_destroy(&r->mu);
+  if (r->resolved_config != NULL) {
+    grpc_client_config_unref(r->resolved_config);
+  }
+  grpc_subchannel_factory_unref(r->subchannel_factory);
+  gpr_free(r->name);
+  gpr_free(r);
+}
+
+static grpc_resolver *zookeeper_create(
+    grpc_uri *uri,
+    grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+                                         size_t num_subchannels),
+    grpc_subchannel_factory *subchannel_factory) {
+  zookeeper_resolver *r;
+  size_t length;
+  char *path = uri->path;
+
+  if (0 == strcmp(uri->authority, "")) {
+    gpr_log(GPR_ERROR, "No authority specified in zookeeper uri");
+    return NULL;
+  }
+
+  /** Removes the trailing slash if exists */
+  length = strlen(path);
+  if (length > 1 && path[length - 1] == '/') {
+    path[length - 1] = 0;
+  }
+
+  r = gpr_malloc(sizeof(zookeeper_resolver));
+  memset(r, 0, sizeof(*r));
+  gpr_ref_init(&r->refs, 1);
+  gpr_mu_init(&r->mu);
+  grpc_resolver_init(&r->base, &zookeeper_resolver_vtable);
+  r->name = gpr_strdup(path);
+  
+  r->subchannel_factory = subchannel_factory;
+  r->lb_policy_factory = lb_policy_factory;
+  grpc_subchannel_factory_ref(subchannel_factory);
+
+  /** Initializes zookeeper client */
+  zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
+  r->zookeeper_handle = zookeeper_init(uri->authority, zookeeper_global_watcher,
+                                       GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0);
+  if (r->zookeeper_handle == NULL) {
+    gpr_log(GPR_ERROR, "Unable to connect to zookeeper server");
+    return NULL;
+  }
+
+  return &r->base;
+}
+
+static void zookeeper_plugin_init() {
+  grpc_register_resolver_type("zookeeper",
+                              grpc_zookeeper_resolver_factory_create());
+}
+
+void grpc_zookeeper_register() {
+  grpc_register_plugin(zookeeper_plugin_init, NULL);
+}
+
+/*
+ * FACTORY
+ */
+
+static void zookeeper_factory_ref(grpc_resolver_factory *factory) {}
+
+static void zookeeper_factory_unref(grpc_resolver_factory *factory) {}
+
+static grpc_resolver *zookeeper_factory_create_resolver(
+    grpc_resolver_factory *factory, grpc_uri *uri,
+    grpc_subchannel_factory *subchannel_factory) {
+  return zookeeper_create(uri, grpc_create_pick_first_lb_policy,
+                          subchannel_factory);
+}
+
+static const grpc_resolver_factory_vtable zookeeper_factory_vtable = {
+    zookeeper_factory_ref, zookeeper_factory_unref,
+    zookeeper_factory_create_resolver};
+static grpc_resolver_factory zookeeper_resolver_factory = {
+    &zookeeper_factory_vtable};
+
+grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() {
+  return &zookeeper_resolver_factory;
+}
diff --git a/include/grpc/support/cancellable_platform.h b/src/core/client_config/resolvers/zookeeper_resolver.h
similarity index 69%
copy from include/grpc/support/cancellable_platform.h
copy to src/core/client_config/resolvers/zookeeper_resolver.h
index e8e4b84..a6f002d 100644
--- a/include/grpc/support/cancellable_platform.h
+++ b/src/core/client_config/resolvers/zookeeper_resolver.h
@@ -31,26 +31,12 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_CANCELLABLE_PLATFORM_H
-#define GRPC_SUPPORT_CANCELLABLE_PLATFORM_H
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
 
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
+#include "src/core/client_config/resolver_factory.h"
 
-struct gpr_cancellable_list_ {
-  /* a doubly-linked list on cancellable's waiters queue */
-  struct gpr_cancellable_list_ *next;
-  struct gpr_cancellable_list_ *prev;
-  /* The following two fields are arguments to gpr_cv_cancellable_wait() */
-  gpr_mu *mu;
-  gpr_cv *cv;
-};
+/** Create a zookeeper resolver factory */
+grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void);
 
-/* Internal definition of gpr_cancellable. */
-typedef struct {
-  gpr_mu mu; /* protects waiters and modifications to cancelled */
-  gpr_atm cancelled;
-  struct gpr_cancellable_list_ waiters;
-} gpr_cancellable;
-
-#endif  /* GRPC_SUPPORT_CANCELLABLE_PLATFORM_H */
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index e426241..0fd0287 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -37,7 +37,7 @@
 
 int grpc_compression_algorithm_parse(const char* name,
                                      grpc_compression_algorithm *algorithm) {
-  if (strcmp(name, "none") == 0) {
+  if (strcmp(name, "identity") == 0) {
     *algorithm = GRPC_COMPRESS_NONE;
   } else if (strcmp(name, "gzip") == 0) {
     *algorithm = GRPC_COMPRESS_GZIP;
@@ -53,7 +53,7 @@
                                     char **name) {
   switch (algorithm) {
     case GRPC_COMPRESS_NONE:
-      *name = "none";
+      *name = "identity";
       break;
     case GRPC_COMPRESS_DEFLATE:
       *name = "deflate";
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
new file mode 100644
index 0000000..db0aef8
--- /dev/null
+++ b/src/core/iomgr/udp_server.c
@@ -0,0 +1,438 @@
+/*
+ *
+ * Copyright 2015, 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.
+ *
+ */
+
+/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/iomgr/udp_server.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "src/core/iomgr/fd_posix.h"
+#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/iomgr/socket_utils_posix.h"
+#include "src/core/support/string.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#define INIT_PORT_CAP 2
+
+/* one listening port */
+typedef struct {
+  int fd;
+  grpc_fd *emfd;
+  grpc_udp_server *server;
+  union {
+    gpr_uint8 untyped[GRPC_MAX_SOCKADDR_SIZE];
+    struct sockaddr sockaddr;
+    struct sockaddr_un un;
+  } addr;
+  int addr_len;
+  grpc_iomgr_closure read_closure;
+  grpc_iomgr_closure destroyed_closure;
+  grpc_udp_server_read_cb read_cb;
+} server_port;
+
+static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
+  struct stat st;
+
+  if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
+    unlink(un->sun_path);
+  }
+}
+
+/* the overall server */
+struct grpc_udp_server {
+  grpc_udp_server_cb cb;
+  void *cb_arg;
+
+  gpr_mu mu;
+  gpr_cv cv;
+
+  /* active port count: how many ports are actually still listening */
+  size_t active_ports;
+  /* destroyed port count: how many ports are completely destroyed */
+  size_t destroyed_ports;
+
+  /* is this server shutting down? (boolean) */
+  int shutdown;
+
+  /* all listening ports */
+  server_port *ports;
+  size_t nports;
+  size_t port_capacity;
+
+  /* shutdown callback */
+  void (*shutdown_complete)(void *);
+  void *shutdown_complete_arg;
+
+  /* all pollsets interested in new connections */
+  grpc_pollset **pollsets;
+  /* number of pollsets in the pollsets array */
+  size_t pollset_count;
+};
+
+grpc_udp_server *grpc_udp_server_create(void) {
+  grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server));
+  gpr_mu_init(&s->mu);
+  gpr_cv_init(&s->cv);
+  s->active_ports = 0;
+  s->destroyed_ports = 0;
+  s->shutdown = 0;
+  s->cb = NULL;
+  s->cb_arg = NULL;
+  s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
+  s->nports = 0;
+  s->port_capacity = INIT_PORT_CAP;
+
+  return s;
+}
+
+static void finish_shutdown(grpc_udp_server *s) {
+  s->shutdown_complete(s->shutdown_complete_arg);
+
+  gpr_mu_destroy(&s->mu);
+  gpr_cv_destroy(&s->cv);
+
+  gpr_free(s->ports);
+  gpr_free(s);
+}
+
+static void destroyed_port(void *server, int success) {
+  grpc_udp_server *s = server;
+  gpr_mu_lock(&s->mu);
+  s->destroyed_ports++;
+  if (s->destroyed_ports == s->nports) {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(s);
+  } else {
+    gpr_mu_unlock(&s->mu);
+  }
+}
+
+static void dont_care_about_shutdown_completion(void *ignored) {}
+
+/* called when all listening endpoints have been shutdown, so no further
+   events will be received on them - at this point it's safe to destroy
+   things */
+static void deactivated_all_ports(grpc_udp_server *s) {
+  size_t i;
+
+  /* delete ALL the things */
+  gpr_mu_lock(&s->mu);
+
+  if (!s->shutdown) {
+    gpr_mu_unlock(&s->mu);
+    return;
+  }
+
+  if (s->nports) {
+    for (i = 0; i < s->nports; i++) {
+      server_port *sp = &s->ports[i];
+      if (sp->addr.sockaddr.sa_family == AF_UNIX) {
+        unlink_if_unix_domain_socket(&sp->addr.un);
+      }
+      sp->destroyed_closure.cb = destroyed_port;
+      sp->destroyed_closure.cb_arg = s;
+      grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, "udp_listener_shutdown");
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(s);
+  }
+}
+
+void grpc_udp_server_destroy(
+    grpc_udp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg),
+    void *shutdown_complete_arg) {
+  size_t i;
+  gpr_mu_lock(&s->mu);
+
+  GPR_ASSERT(!s->shutdown);
+  s->shutdown = 1;
+
+  s->shutdown_complete = shutdown_complete
+                             ? shutdown_complete
+                             : dont_care_about_shutdown_completion;
+  s->shutdown_complete_arg = shutdown_complete_arg;
+
+  /* shutdown all fd's */
+  if (s->active_ports) {
+    for (i = 0; i < s->nports; i++) {
+      grpc_fd_shutdown(s->ports[i].emfd);
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    deactivated_all_ports(s);
+  }
+}
+
+/* Prepare a recently-created socket for listening. */
+static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) {
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+  int get_local_ip;
+  int rc;
+
+  if (fd < 0) {
+    goto error;
+  }
+
+  get_local_ip = 1;
+  rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
+                      &get_local_ip, sizeof(get_local_ip));
+  if (rc == 0 && addr->sa_family == AF_INET6) {
+    rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                    &get_local_ip, sizeof(get_local_ip));
+  }
+
+  if (bind(fd, addr, addr_len) < 0) {
+    char *addr_str;
+    grpc_sockaddr_to_string(&addr_str, addr, 0);
+    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
+    gpr_free(addr_str);
+    goto error;
+  }
+
+  sockname_len = sizeof(sockname_temp);
+  if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
+    goto error;
+  }
+
+  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+/* event manager callback when reads are ready */
+static void on_read(void *arg, int success) {
+  server_port *sp = arg;
+
+  if (success == 0) {
+    gpr_mu_lock(&sp->server->mu);
+    if (0 == --sp->server->active_ports) {
+      gpr_mu_unlock(&sp->server->mu);
+      deactivated_all_ports(sp->server);
+    } else {
+      gpr_mu_unlock(&sp->server->mu);
+    }
+    return;
+  }
+
+  /* Tell the registered callback that data is available to read. */
+  GPR_ASSERT(sp->read_cb);
+  sp->read_cb(sp->fd, sp->server->cb, sp->server->cb_arg);
+
+  /* Re-arm the notification event so we get another chance to read. */
+  grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+}
+
+static int add_socket_to_server(grpc_udp_server *s, int fd,
+                                const struct sockaddr *addr, int addr_len,
+                                grpc_udp_server_read_cb read_cb) {
+  server_port *sp;
+  int port;
+  char *addr_str;
+  char *name;
+
+  port = prepare_socket(fd, addr, addr_len);
+  if (port >= 0) {
+    grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
+    gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
+    gpr_mu_lock(&s->mu);
+    GPR_ASSERT(!s->cb && "must add ports before starting server");
+    /* append it to the list under a lock */
+    if (s->nports == s->port_capacity) {
+      s->port_capacity *= 2;
+      s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
+    }
+    sp = &s->ports[s->nports++];
+    sp->server = s;
+    sp->fd = fd;
+    sp->emfd = grpc_fd_create(fd, name);
+    memcpy(sp->addr.untyped, addr, addr_len);
+    sp->addr_len = addr_len;
+    sp->read_cb = read_cb;
+    GPR_ASSERT(sp->emfd);
+    gpr_mu_unlock(&s->mu);
+  }
+
+  return port;
+}
+
+int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
+                             int addr_len, grpc_udp_server_read_cb read_cb) {
+  int allocated_port1 = -1;
+  int allocated_port2 = -1;
+  unsigned i;
+  int fd;
+  grpc_dualstack_mode dsmode;
+  struct sockaddr_in6 addr6_v4mapped;
+  struct sockaddr_in wild4;
+  struct sockaddr_in6 wild6;
+  struct sockaddr_in addr4_copy;
+  struct sockaddr *allocated_addr = NULL;
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+  int port;
+
+  if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
+    unlink_if_unix_domain_socket(addr);
+  }
+
+  /* Check if this is a wildcard port, and if so, try to keep the port the same
+     as some previously created listener. */
+  if (grpc_sockaddr_get_port(addr) == 0) {
+    for (i = 0; i < s->nports; i++) {
+      sockname_len = sizeof(sockname_temp);
+      if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
+                           &sockname_len)) {
+        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+        if (port > 0) {
+          allocated_addr = malloc(addr_len);
+          memcpy(allocated_addr, addr, addr_len);
+          grpc_sockaddr_set_port(allocated_addr, port);
+          addr = allocated_addr;
+          break;
+        }
+      }
+    }
+  }
+
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = (const struct sockaddr *)&addr6_v4mapped;
+    addr_len = sizeof(addr6_v4mapped);
+  }
+
+  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+  if (grpc_sockaddr_is_wildcard(addr, &port)) {
+    grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
+
+    /* Try listening on IPv6 first. */
+    addr = (struct sockaddr *)&wild6;
+    addr_len = sizeof(wild6);
+    fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
+    allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
+    if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
+      goto done;
+    }
+
+    /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
+    if (port == 0 && allocated_port1 > 0) {
+      grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
+    }
+    addr = (struct sockaddr *)&wild4;
+    addr_len = sizeof(wild4);
+  }
+
+  fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+  }
+  if (dsmode == GRPC_DSMODE_IPV4 &&
+      grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
+    addr = (struct sockaddr *)&addr4_copy;
+    addr_len = sizeof(addr4_copy);
+  }
+  allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
+
+done:
+  gpr_free(allocated_addr);
+  return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
+}
+
+int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index) {
+  return (index < s->nports) ? s->ports[index].fd : -1;
+}
+
+void grpc_udp_server_start(grpc_udp_server *s, grpc_pollset **pollsets,
+                           size_t pollset_count,
+                           grpc_udp_server_cb new_transport_cb, void *cb_arg) {
+  size_t i, j;
+  GPR_ASSERT(new_transport_cb);
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(!s->cb);
+  GPR_ASSERT(s->active_ports == 0);
+  s->cb = new_transport_cb;
+  s->cb_arg = cb_arg;
+  s->pollsets = pollsets;
+  for (i = 0; i < s->nports; i++) {
+    for (j = 0; j < pollset_count; j++) {
+      grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd);
+    }
+    s->ports[i].read_closure.cb = on_read;
+    s->ports[i].read_closure.cb_arg = &s->ports[i];
+    grpc_fd_notify_on_read(s->ports[i].emfd, &s->ports[i].read_closure);
+    s->active_ports++;
+  }
+  gpr_mu_unlock(&s->mu);
+}
+
+/* TODO(rjshade): Add a test for this method. */
+void grpc_udp_server_write(server_port *sp, const char *buffer, size_t buf_len,
+                           const struct sockaddr *peer_address) {
+  int rc;
+  rc = sendto(sp->fd, buffer, buf_len, 0, peer_address, sizeof(peer_address));
+  if (rc < 0) {
+    gpr_log(GPR_ERROR, "Unable to send data: %s", strerror(errno));
+  }
+}
+
+#endif
diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h
new file mode 100644
index 0000000..fcc4ba6
--- /dev/null
+++ b/src/core/iomgr/udp_server.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2015, 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_INTERNAL_CORE_IOMGR_UDP_SERVER_H
+#define GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H
+
+#include "src/core/iomgr/endpoint.h"
+
+/* Forward decl of grpc_udp_server */
+typedef struct grpc_udp_server grpc_udp_server;
+
+/* New server callback: ep is the newly connected connection */
+typedef void (*grpc_udp_server_cb)(void *arg, grpc_endpoint *ep);
+
+/* Called when data is available to read from the socket. */
+typedef void (*grpc_udp_server_read_cb)(int fd,
+                                        grpc_udp_server_cb new_transport_cb,
+                                        void *cb_arg);
+
+/* Create a server, initially not bound to any ports */
+grpc_udp_server *grpc_udp_server_create(void);
+
+/* Start listening to bound ports */
+void grpc_udp_server_start(grpc_udp_server *server, grpc_pollset **pollsets,
+                           size_t pollset_count, grpc_udp_server_cb cb,
+                           void *cb_arg);
+
+int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index);
+
+/* Add a port to the server, returning port number on success, or negative
+   on failure.
+
+   The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
+   both IPv4 and IPv6 connections, but :: is the preferred style.  This usually
+   creates one socket, but possibly two on systems which support IPv6,
+   but not dualstack sockets. */
+
+/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle
+                  all of the multiple socket port matching logic in one place */
+int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, int addr_len,
+                             grpc_udp_server_read_cb read_cb);
+
+void grpc_udp_server_destroy(grpc_udp_server *server,
+                             void (*shutdown_done)(void *shutdown_done_arg),
+                             void *shutdown_done_arg);
+
+/* Write the contents of buffer to the underlying UDP socket. */
+/*
+void grpc_udp_server_write(grpc_udp_server *s,
+                           const char *buffer,
+                           int buf_len,
+                           const struct sockaddr* to);
+                           */
+
+#endif /* GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H */
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 0e69987..410852d 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -75,11 +75,11 @@
   grpc_mdstr *status_key;
 } channel_data;
 
-static void bubble_up_error(grpc_call_element *elem, const char *error_msg) {
+static void bubble_up_error(grpc_call_element *elem, grpc_status_code status,
+                            const char *error_msg) {
   call_data *calld = elem->call_data;
   gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg);
-  grpc_transport_stream_op_add_cancellation(&calld->op,
-                                            GRPC_STATUS_UNAUTHENTICATED);
+  grpc_transport_stream_op_add_cancellation(&calld->op, status);
   grpc_call_next_op(elem, &calld->op);
 }
 
@@ -94,7 +94,8 @@
   grpc_metadata_batch *mdb;
   size_t i;
   if (status != GRPC_CREDENTIALS_OK) {
-    bubble_up_error(elem, "Credentials failed to get metadata.");
+    bubble_up_error(elem, GRPC_STATUS_UNAUTHENTICATED,
+                    "Credentials failed to get metadata.");
     return;
   }
   GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT);
@@ -154,7 +155,7 @@
   if (channel_creds_has_md && call_creds_has_md) {
     calld->creds = grpc_composite_credentials_create(channel_creds, ctx->creds);
     if (calld->creds == NULL) {
-      bubble_up_error(elem,
+      bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT,
                       "Incompatible credentials set on channel and call.");
       return;
     }
@@ -182,7 +183,7 @@
     char *error_msg;
     gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
                  grpc_mdstr_as_c_string(calld->host));
-    bubble_up_error(elem, error_msg);
+    bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg);
     gpr_free(error_msg);
   }
 }
@@ -252,7 +253,7 @@
             gpr_asprintf(&error_msg,
                          "Invalid host %s set in :authority metadata.",
                          call_host);
-            bubble_up_error(elem, error_msg);
+            bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg);
             gpr_free(error_msg);
           }
           return; /* early exit */
diff --git a/src/core/support/cancellable.c b/src/core/support/cancellable.c
deleted file mode 100644
index 4756f1e..0000000
--- a/src/core/support/cancellable.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- *
- * Copyright 2015, 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 for gpr_cancellable */
-
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-void gpr_cancellable_init(gpr_cancellable *c) {
-  gpr_mu_init(&c->mu);
-  c->cancelled = 0;
-  c->waiters.next = &c->waiters;
-  c->waiters.prev = &c->waiters;
-  c->waiters.mu = NULL;
-  c->waiters.cv = NULL;
-}
-
-void gpr_cancellable_destroy(gpr_cancellable *c) { gpr_mu_destroy(&c->mu); }
-
-int gpr_cancellable_is_cancelled(gpr_cancellable *c) {
-  return gpr_atm_acq_load(&c->cancelled) != 0;
-}
-
-/* Threads in gpr_cv_cancellable_wait(cv, mu, ..., c) place themselves on a
-   linked list c->waiters of gpr_cancellable_list_ before waiting on their
-   condition variables.  They check for cancellation while holding *mu.  Thus,
-   to wake a thread from gpr_cv_cancellable_wait(), it suffices to:
-      - set c->cancelled
-      - acquire and release *mu
-      - gpr_cv_broadcast(cv)
-
-   However, gpr_cancellable_cancel() may not use gpr_mu_lock(mu), since the
-   caller may already hold *mu---a possible deadlock.  (If we knew the caller
-   did not hold *mu, care would still be needed, because c->mu follows *mu in
-   the locking order, so *mu could not be acquired while holding c->mu---which
-   is needed to iterate over c->waiters.)
-
-   Therefore, gpr_cancellable_cancel() uses gpr_mu_trylock() rather than
-   gpr_mu_lock(), and retries until either gpr_mu_trylock() succeeds or the
-   thread leaves gpr_cv_cancellable_wait() for other reasons.  In the first
-   case, gpr_cancellable_cancel() removes the entry from the waiters list; in
-   the second, the waiting thread removes itself from the list.
-
-   A one-entry cache of mutexes and condition variables processed is kept to
-   avoid doing the same work again and again if many threads are blocked in the
-   same place.  However, it's important to broadcast on a condition variable if
-   the corresponding mutex has been locked successfully, even if the condition
-   variable has been signalled before.  */
-
-void gpr_cancellable_cancel(gpr_cancellable *c) {
-  if (!gpr_cancellable_is_cancelled(c)) {
-    int failures;
-    int backoff = 1;
-    do {
-      struct gpr_cancellable_list_ *l;
-      struct gpr_cancellable_list_ *nl;
-      gpr_mu *omu = 0; /* one-element cache of a processed gpr_mu */
-      gpr_cv *ocv = 0; /* one-element cache of a processd gpr_cv */
-      gpr_mu_lock(&c->mu);
-      gpr_atm_rel_store(&c->cancelled, 1);
-      failures = 0;
-      for (l = c->waiters.next; l != &c->waiters; l = nl) {
-        nl = l->next;
-        if (omu != l->mu) {
-          omu = l->mu;
-          if (gpr_mu_trylock(l->mu)) {
-            gpr_mu_unlock(l->mu);
-            l->next->prev = l->prev; /* remove *l from list */
-            l->prev->next = l->next;
-            /* allow unconditional dequeue in gpr_cv_cancellable_wait() */
-            l->next = l;
-            l->prev = l;
-            ocv = 0; /* force broadcast */
-          } else {
-            failures++;
-          }
-        }
-        if (ocv != l->cv) {
-          ocv = l->cv;
-          gpr_cv_broadcast(l->cv);
-        }
-      }
-      gpr_mu_unlock(&c->mu);
-      if (failures != 0) {
-        if (backoff < 10) {
-          volatile int i;
-          for (i = 0; i != (1 << backoff); i++) {
-          }
-          backoff++;
-        } else {
-          gpr_event ev;
-          gpr_event_init(&ev);
-          gpr_event_wait(
-              &ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                                gpr_time_from_micros(1000, GPR_TIMESPAN)));
-        }
-      }
-    } while (failures != 0);
-  }
-}
-
-int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline,
-                            gpr_cancellable *c) {
-  gpr_int32 timeout;
-  gpr_mu_lock(&c->mu);
-  timeout = gpr_cancellable_is_cancelled(c);
-  if (!timeout) {
-    struct gpr_cancellable_list_ le;
-    le.mu = mu;
-    le.cv = cv;
-    le.next = c->waiters.next;
-    le.prev = &c->waiters;
-    le.next->prev = &le;
-    le.prev->next = &le;
-    gpr_mu_unlock(&c->mu);
-    timeout = gpr_cv_wait(cv, mu, abs_deadline);
-    gpr_mu_lock(&c->mu);
-    le.next->prev = le.prev;
-    le.prev->next = le.next;
-    if (!timeout) {
-      timeout = gpr_cancellable_is_cancelled(c);
-    }
-  }
-  gpr_mu_unlock(&c->mu);
-  return timeout;
-}
diff --git a/src/core/support/sync.c b/src/core/support/sync.c
index 856b5ad..d3cf77f 100644
--- a/src/core/support/sync.c
+++ b/src/core/support/sync.c
@@ -94,21 +94,6 @@
   return result;
 }
 
-void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline,
-                                 gpr_cancellable *c) {
-  void *result = (void *)gpr_atm_acq_load(&ev->state);
-  if (result == NULL) {
-    struct sync_array_s *s = hash(ev);
-    gpr_mu_lock(&s->mu);
-    do {
-      result = (void *)gpr_atm_acq_load(&ev->state);
-    } while (result == NULL &&
-             !gpr_cv_cancellable_wait(&s->cv, &s->mu, abs_deadline, c));
-    gpr_mu_unlock(&s->mu);
-  }
-  return result;
-}
-
 void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
 
 void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 5839d3a..6a1a6cb 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -964,7 +964,7 @@
           next_child_call = child_call->sibling_next;
           if (child_call->cancellation_is_inherited) {
             GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
-            grpc_call_cancel(child_call);
+            grpc_call_cancel(child_call, NULL);
             GRPC_CALL_INTERNAL_UNREF(child_call, "propagate_cancel", 0);
           }
           child_call = next_child_call;
@@ -1265,18 +1265,22 @@
   c->cancel_alarm |= c->have_alarm;
   cancel = c->read_state != READ_STATE_STREAM_CLOSED;
   unlock(c);
-  if (cancel) grpc_call_cancel(c);
+  if (cancel) grpc_call_cancel(c, NULL);
   GRPC_CALL_INTERNAL_UNREF(c, "destroy", 1);
 }
 
-grpc_call_error grpc_call_cancel(grpc_call *call) {
-  return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled");
+grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
+  GPR_ASSERT(!reserved);
+  return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
+                                      NULL);
 }
 
 grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
                                              grpc_status_code status,
-                                             const char *description) {
+                                             const char *description,
+                                             void *reserved) {
   grpc_call_error r;
+  (void) reserved;
   lock(c);
   r = cancel_with_status(c, status, description);
   unlock(c);
@@ -1513,13 +1517,14 @@
 }
 
 grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
-                                      size_t nops, void *tag) {
+                                      size_t nops, void *tag, void *reserved) {
   grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT];
   size_t in;
   size_t out;
   const grpc_op *op;
   grpc_ioreq *req;
   void (*finish_func)(grpc_call *, int, void *) = finish_batch;
+  GPR_ASSERT(!reserved);
 
   GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
 
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 8692aa3..308572c 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -168,7 +168,8 @@
                                     gpr_uint32 propagation_mask,
                                     grpc_completion_queue *cq,
                                     const char *method, const char *host,
-                                    gpr_timespec deadline) {
+                                    gpr_timespec deadline, void *reserved) {
+  GPR_ASSERT(!reserved);
   return grpc_channel_create_call_internal(
       channel, parent_call, propagation_mask, cq,
       grpc_mdelem_from_metadata_strings(
@@ -182,8 +183,9 @@
 }
 
 void *grpc_channel_register_call(grpc_channel *channel, const char *method,
-                                 const char *host) {
+                                 const char *host, void *reserved) {
   registered_call *rc = gpr_malloc(sizeof(registered_call));
+  GPR_ASSERT(!reserved);
   rc->path = grpc_mdelem_from_metadata_strings(
       channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
       grpc_mdstr_from_string(channel->metadata_context, method, 0));
@@ -200,8 +202,9 @@
 grpc_call *grpc_channel_create_registered_call(
     grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask,
     grpc_completion_queue *completion_queue, void *registered_call_handle,
-    gpr_timespec deadline) {
+    gpr_timespec deadline, void *reserved) {
   registered_call *rc = registered_call_handle;
+  GPR_ASSERT(!reserved);
   return grpc_channel_create_call_internal(
       channel, parent_call, propagation_mask, completion_queue, 
       GRPC_MDELEM_REF(rc->path), 
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 707d615..82ddfac 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -155,7 +155,8 @@
                    - connect to it (trying alternatives as presented)
                    - perform handshakes */
 grpc_channel *grpc_insecure_channel_create(const char *target,
-                                           const grpc_channel_args *args) {
+                                           const grpc_channel_args *args,
+                                           void *reserved) {
   grpc_channel *channel = NULL;
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
@@ -163,6 +164,7 @@
   subchannel_factory *f;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   int n = 0;
+  GPR_ASSERT(!reserved);
   /* TODO(census)
   if (grpc_channel_args_is_census_enabled(args)) {
     filters[n++] = &grpc_client_census_filter;
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 36d69cf..378b3f7 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -69,8 +69,9 @@
   plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
 };
 
-grpc_completion_queue *grpc_completion_queue_create(void) {
+grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
   grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
+  GPR_ASSERT(!reserved);
   memset(cc, 0, sizeof(*cc));
   /* Initial ref is dropped by grpc_completion_queue_shutdown */
   gpr_ref_init(&cc->pending_events, 1);
@@ -166,9 +167,11 @@
 }
 
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
-                                      gpr_timespec deadline) {
+                                      gpr_timespec deadline,
+                                      void *reserved) {
   grpc_event ret;
   grpc_pollset_worker worker;
+  GPR_ASSERT(!reserved);
 
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
 
@@ -232,11 +235,12 @@
 }
 
 grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
-                                       gpr_timespec deadline) {
+                                       gpr_timespec deadline, void *reserved) {
   grpc_event ret;
   grpc_cq_completion *c;
   grpc_cq_completion *prev;
   grpc_pollset_worker worker;
+  GPR_ASSERT(!reserved);
 
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
 
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index 442bc72..d904454 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -33,8 +33,11 @@
 
 #include <grpc/support/port_platform.h>
 
+#include <memory.h>
+
 #include <grpc/census.h>
 #include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
 #include <grpc/support/time.h>
 #include "src/core/channel/channel_stack.h"
 #include "src/core/client_config/resolver_registry.h"
@@ -49,6 +52,8 @@
 #include "src/core/transport/chttp2_transport.h"
 #include "src/core/transport/connectivity_state.h"
 
+#define MAX_PLUGINS 128
+
 static gpr_once g_basic_init = GPR_ONCE_INIT;
 static gpr_mu g_init_mu;
 static int g_initializations;
@@ -58,7 +63,23 @@
   g_initializations = 0;
 }
 
+typedef struct grpc_plugin {
+  void (*init)();
+  void (*destroy)();
+} grpc_plugin;
+
+static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS];
+static int g_number_of_plugins = 0;
+
+void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) {
+  GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS);
+  g_all_of_the_plugins[g_number_of_plugins].init = init;
+  g_all_of_the_plugins[g_number_of_plugins].destroy = destroy;
+  g_number_of_plugins++;
+}
+
 void grpc_init(void) {
+  int i;
   gpr_once_init(&g_basic_init, do_basic_init);
 
   gpr_mu_lock(&g_init_mu);
@@ -87,11 +108,17 @@
       }
     }
     grpc_timers_global_init();
+    for (i = 0; i < g_number_of_plugins; i++) {
+      if (g_all_of_the_plugins[i].init != NULL) {
+        g_all_of_the_plugins[i].init();
+      }
+    }
   }
   gpr_mu_unlock(&g_init_mu);
 }
 
 void grpc_shutdown(void) {
+  int i;
   gpr_mu_lock(&g_init_mu);
   if (--g_initializations == 0) {
     grpc_iomgr_shutdown();
@@ -99,6 +126,11 @@
     grpc_timers_global_destroy();
     grpc_tracer_shutdown();
     grpc_resolver_registry_shutdown();
+    for (i = 0; i < g_number_of_plugins; i++) {
+      if (g_all_of_the_plugins[i].destroy != NULL) {
+        g_all_of_the_plugins[i].destroy();
+      }
+    }
   }
   gpr_mu_unlock(&g_init_mu);
 }
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index cd1dc58..f883275 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -761,8 +761,10 @@
 };
 
 void grpc_server_register_completion_queue(grpc_server *server,
-                                           grpc_completion_queue *cq) {
+                                           grpc_completion_queue *cq,
+                                           void *reserved) {
   size_t i, n;
+  GPR_ASSERT(!reserved);
   for (i = 0; i < server->cq_count; i++) {
     if (server->cqs[i] == cq) return;
   }
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
index 1e26c67..9237eb5 100644
--- a/src/core/surface/server_create.c
+++ b/src/core/surface/server_create.c
@@ -36,8 +36,9 @@
 #include "src/core/surface/server.h"
 #include "src/core/channel/compress_filter.h"
 
-grpc_server *grpc_server_create(const grpc_channel_args *args) {
+grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
   const grpc_channel_filter *filters[] = {&grpc_compress_filter};
+  (void) reserved;
   return grpc_server_create_from_filters(filters, GPR_ARRAY_SIZE(filters),
                                          args);
 }
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
index a5dfec9..0a9669b 100644
--- a/src/core/transport/stream_op.c
+++ b/src/core/transport/stream_op.c
@@ -258,6 +258,7 @@
   GPR_ASSERT(storage->md);
   storage->prev = list->tail;
   storage->next = NULL;
+  storage->reserved = NULL;
   if (list->tail != NULL) {
     list->tail->next = storage;
   } else {
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
index 227320c..37f18b0 100644
--- a/src/core/transport/stream_op.h
+++ b/src/core/transport/stream_op.h
@@ -77,6 +77,7 @@
   grpc_mdelem *md;
   struct grpc_linked_mdelem *next;
   struct grpc_linked_mdelem *prev;
+  void *reserved;
 } grpc_linked_mdelem;
 
 typedef struct grpc_mdelem_list {
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index af7366e..0582b59 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -61,19 +61,25 @@
 
 Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
                          CompletionQueue* cq) {
-  const char* host_str = host_.empty() ? NULL : host_.c_str();
-  auto c_call = method.channel_tag() && context->authority().empty()
-                    ? grpc_channel_create_registered_call(
-                          c_channel_, context->propagate_from_call_,
-                          context->propagation_options_.c_bitmask(), cq->cq(),
-                          method.channel_tag(), context->raw_deadline())
-                    : grpc_channel_create_call(
-                          c_channel_, context->propagate_from_call_,
-                          context->propagation_options_.c_bitmask(), cq->cq(),
-                          method.name(), context->authority().empty()
-                                             ? host_str
-                                             : context->authority().c_str(),
-                          context->raw_deadline());
+  const bool kRegistered = method.channel_tag() && context->authority().empty();
+  grpc_call* c_call = NULL;
+  if (kRegistered) {
+    c_call = grpc_channel_create_registered_call(
+        c_channel_, context->propagate_from_call_,
+        context->propagation_options_.c_bitmask(), cq->cq(),
+        method.channel_tag(), context->raw_deadline(), nullptr);
+  } else {
+    const char* host_str = NULL;
+    if (!context->authority().empty()) {
+      host_str = context->authority().c_str();
+    } else if (!host_.empty()) {
+      host_str = host_.c_str();
+    }
+    c_call = grpc_channel_create_call(c_channel_, context->propagate_from_call_,
+                                      context->propagation_options_.c_bitmask(),
+                                      cq->cq(), method.name(), host_str,
+                                      context->raw_deadline(), nullptr);
+  }
   grpc_census_call_set_context(c_call, context->census_context());
   GRPC_TIMER_MARK(GRPC_PTAG_CPP_CALL_CREATED, c_call);
   context->set_call(c_call, shared_from_this());
@@ -87,13 +93,14 @@
   GRPC_TIMER_BEGIN(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
   ops->FillOps(cops, &nops);
   GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call->call(), cops, nops, ops));
+             grpc_call_start_batch(call->call(), cops, nops, ops, nullptr));
   GRPC_TIMER_END(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
 }
 
 void* Channel::RegisterMethod(const char* method) {
   return grpc_channel_register_call(c_channel_, method,
-                                    host_.empty() ? NULL : host_.c_str());
+                                    host_.empty() ? NULL : host_.c_str(),
+                                    nullptr);
 }
 
 grpc_connectivity_state Channel::GetState(bool try_to_connect) {
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 1ed2d38..b8caa1e 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -48,7 +48,6 @@
 ClientContext::ClientContext()
     : initial_metadata_received_(false),
       call_(nullptr),
-      cq_(nullptr),
       deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
       propagate_from_call_(nullptr) {}
 
@@ -56,14 +55,6 @@
   if (call_) {
     grpc_call_destroy(call_);
   }
-  if (cq_) {
-    // Drain cq_.
-    grpc_completion_queue_shutdown(cq_);
-    while (grpc_completion_queue_next(cq_, gpr_inf_future(GPR_CLOCK_REALTIME))
-               .type != GRPC_QUEUE_SHUTDOWN)
-      ;
-    grpc_completion_queue_destroy(cq_);
-  }
 }
 
 std::unique_ptr<ClientContext> ClientContext::FromServerContext(
@@ -86,19 +77,19 @@
   channel_ = channel;
   if (creds_ && !creds_->ApplyToCall(call_)) {
     grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED,
-                                 "Failed to set credentials to rpc.");
+                                 "Failed to set credentials to rpc.", nullptr);
   }
 }
 
 void ClientContext::set_compression_algorithm(
     grpc_compression_algorithm algorithm) {
-  char* algorithm_name = NULL;
+  char* algorithm_name = nullptr;
   if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) {
     gpr_log(GPR_ERROR, "Name for compression algorithm '%d' unknown.",
             algorithm);
     abort();
   }
-  GPR_ASSERT(algorithm_name != NULL);
+  GPR_ASSERT(algorithm_name != nullptr);
   AddMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
 }
 
@@ -111,7 +102,7 @@
 
 void ClientContext::TryCancel() {
   if (call_) {
-    grpc_call_cancel(call_);
+    grpc_call_cancel(call_, nullptr);
   }
 }
 
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index d8dcaa1..2f9357b 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -49,7 +49,7 @@
     grpc_channel_args channel_args;
     args.SetChannelArgs(&channel_args);
     return std::shared_ptr<ChannelInterface>(new Channel(
-        grpc_insecure_channel_create(target.c_str(), &channel_args)));
+        grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr)));
   }
 
   // InsecureCredentials should not be applied to a call.
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index 593963f..fca33f8 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -40,7 +40,9 @@
 
 namespace grpc {
 
-CompletionQueue::CompletionQueue() { cq_ = grpc_completion_queue_create(); }
+CompletionQueue::CompletionQueue() {
+  cq_ = grpc_completion_queue_create(nullptr);
+}
 
 CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {}
 
@@ -51,7 +53,7 @@
 CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
     void** tag, bool* ok, gpr_timespec deadline) {
   for (;;) {
-    auto ev = grpc_completion_queue_next(cq_, deadline);
+    auto ev = grpc_completion_queue_next(cq_, deadline, nullptr);
     switch (ev.type) {
       case GRPC_QUEUE_TIMEOUT:
         return TIMEOUT;
@@ -70,8 +72,8 @@
 }
 
 bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
-  auto ev =
-      grpc_completion_queue_pluck(cq_, tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+  auto deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr);
   bool ok = ev.success != 0;
   void* ignored = tag;
   GPR_ASSERT(tag->FinalizeResult(&ignored, &ok));
@@ -81,8 +83,8 @@
 }
 
 void CompletionQueue::TryPluck(CompletionQueueTag* tag) {
-  auto ev =
-      grpc_completion_queue_pluck(cq_, tag, gpr_time_0(GPR_CLOCK_REALTIME));
+  auto deadline = gpr_time_0(GPR_CLOCK_REALTIME);
+  auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr);
   if (ev.type == GRPC_QUEUE_TIMEOUT) return;
   bool ok = ev.success != 0;
   void* ignored = tag;
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index ab87b22..a70b555 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -67,11 +67,17 @@
         has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
                              method->method_type() ==
                                  RpcMethod::SERVER_STREAMING),
+        call_details_(nullptr),
         cq_(nullptr) {
     grpc_metadata_array_init(&request_metadata_);
   }
 
-  ~SyncRequest() { grpc_metadata_array_destroy(&request_metadata_); }
+  ~SyncRequest() {
+    if (call_details_) {
+      delete call_details_;
+    }
+    grpc_metadata_array_destroy(&request_metadata_);
+  }
 
   static SyncRequest* Wait(CompletionQueue* cq, bool* ok) {
     void* tag = nullptr;
@@ -84,7 +90,7 @@
     return mrd;
   }
 
-  void SetupRequest() { cq_ = grpc_completion_queue_create(); }
+  void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); }
 
   void TeardownRequest() {
     grpc_completion_queue_destroy(cq_);
@@ -94,17 +100,32 @@
   void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
     GPR_ASSERT(cq_ && !in_flight_);
     in_flight_ = true;
-    GPR_ASSERT(GRPC_CALL_OK ==
-               grpc_server_request_registered_call(
-                   server, tag_, &call_, &deadline_, &request_metadata_,
-                   has_request_payload_ ? &request_payload_ : nullptr, cq_,
-                   notify_cq, this));
+    if (tag_) {
+      GPR_ASSERT(GRPC_CALL_OK ==
+                 grpc_server_request_registered_call(
+                     server, tag_, &call_, &deadline_, &request_metadata_,
+                     has_request_payload_ ? &request_payload_ : nullptr, cq_,
+                     notify_cq, this));
+    } else {
+      if (!call_details_) {
+        call_details_ = new grpc_call_details;
+        grpc_call_details_init(call_details_);
+      }
+      GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                     server, &call_, call_details_,
+                                     &request_metadata_, cq_, notify_cq, this));
+    }
   }
 
   bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
     if (!*status) {
       grpc_completion_queue_destroy(cq_);
     }
+    if (call_details_) {
+      deadline_ = call_details_->deadline;
+      grpc_call_details_destroy(call_details_);
+      grpc_call_details_init(call_details_);
+    }
     return true;
   }
 
@@ -157,6 +178,7 @@
   bool in_flight_;
   const bool has_request_payload_;
   grpc_call* call_;
+  grpc_call_details* call_details_;
   gpr_timespec deadline_;
   grpc_metadata_array request_metadata_;
   grpc_byte_buffer* request_payload_;
@@ -170,9 +192,9 @@
     arg.key = const_cast<char*>(GRPC_ARG_MAX_MESSAGE_LENGTH);
     arg.value.integer = max_message_size;
     grpc_channel_args args = {1, &arg};
-    return grpc_server_create(&args);
+    return grpc_server_create(&args, nullptr);
   } else {
-    return grpc_server_create(nullptr);
+    return grpc_server_create(nullptr, nullptr);
   }
 }
 
@@ -183,10 +205,11 @@
       shutdown_(false),
       num_running_cb_(0),
       sync_methods_(new std::list<SyncRequest>),
+      has_generic_service_(false),
       server_(CreateServer(max_message_size)),
       thread_pool_(thread_pool),
       thread_pool_owned_(thread_pool_owned) {
-  grpc_server_register_completion_queue(server_, cq_.cq());
+  grpc_server_register_completion_queue(server_, cq_.cq(), nullptr);
 }
 
 Server::~Server() {
@@ -217,13 +240,13 @@
               method->name());
       return false;
     }
-    SyncRequest request(method, tag);
-    sync_methods_->emplace_back(request);
+    sync_methods_->emplace_back(method, tag);
   }
   return true;
 }
 
-bool Server::RegisterAsyncService(const grpc::string *host, AsynchronousService* service) {
+bool Server::RegisterAsyncService(const grpc::string* host,
+                                  AsynchronousService* service) {
   GPR_ASSERT(service->server_ == nullptr &&
              "Can only register an asynchronous service against one server.");
   service->server_ = this;
@@ -245,6 +268,7 @@
   GPR_ASSERT(service->server_ == nullptr &&
              "Can only register an async generic service against one server.");
   service->server_ = this;
+  has_generic_service_ = true;
 }
 
 int Server::AddListeningPort(const grpc::string& addr,
@@ -258,6 +282,14 @@
   started_ = true;
   grpc_server_start(server_);
 
+  if (!has_generic_service_) {
+    unknown_method_.reset(new RpcServiceMethod(
+        "unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler));
+    // Use of emplace_back with just constructor arguments is not accepted here
+    // by gcc-4.4 because it can't match the anonymous nullptr with a proper
+    // constructor implicitly. Construct the object and use push_back.
+    sync_methods_->push_back(SyncRequest(unknown_method_.get(), nullptr));
+  }
   // Start processing rpcs.
   if (!sync_methods_->empty()) {
     for (auto m = sync_methods_->begin(); m != sync_methods_->end(); m++) {
@@ -297,8 +329,8 @@
   size_t nops = 0;
   grpc_op cops[MAX_OPS];
   ops->FillOps(cops, &nops);
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call->call(), cops, nops, ops));
+  auto result = grpc_call_start_batch(call->call(), cops, nops, ops, nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == result);
 }
 
 Server::BaseAsyncRequest::BaseAsyncRequest(
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index f723d46..0911887 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -38,6 +38,7 @@
 #include <grpc++/impl/service_type.h>
 #include <grpc++/server.h>
 #include <grpc++/thread_pool_interface.h>
+#include <grpc++/fixed_size_thread_pool.h>
 
 namespace grpc {
 
@@ -100,10 +101,17 @@
     thread_pool_ = CreateDefaultThreadPool();
     thread_pool_owned = true;
   }
+  // Async services only, create a thread pool to handle requests to unknown
+  // services.
+  if (!thread_pool_ && !generic_service_ && !async_services_.empty()) {
+    thread_pool_ = new FixedSizeThreadPool(1);
+    thread_pool_owned = true;
+  }
   std::unique_ptr<Server> server(
       new Server(thread_pool_, thread_pool_owned, max_message_size_));
   for (auto cq = cqs_.begin(); cq != cqs_.end(); ++cq) {
-    grpc_server_register_completion_queue(server->server_, (*cq)->cq());
+    grpc_server_register_completion_queue(server->server_, (*cq)->cq(),
+                                          nullptr);
   }
   for (auto service = services_.begin(); service != services_.end();
        service++) {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 0437339..bb34040 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -91,6 +91,7 @@
   ops->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   ops->data.recv_close_on_server.cancelled = &cancelled_;
   ops->flags = 0;
+  ops->reserved = NULL;
   *nops = 1;
 }
 
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index 2dc10d2..f1f8f7c 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -15,7 +15,7 @@
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
 	<dependencies>
-	  <dependency id="Google.Apis.Auth" version="1.9.2" />
+	  <dependency id="Google.Apis.Auth" version="1.9.3" />
 	  <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
diff --git a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs b/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs
new file mode 100644
index 0000000..2dc10eb
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs
@@ -0,0 +1,62 @@
+#region Copyright notice and license
+
+// Copyright 2015, 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.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+    public class ClientBaseTest
+    {
+        [Test]
+        public void GetAuthUriBase_Valid()
+        {
+            Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com"));
+            Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com/"));
+            Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com:443/"));
+            Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com:443/"));
+        }
+
+        [Test]
+        public void GetAuthUriBase_Invalid()
+        {
+            Assert.IsNull(ClientBase.GetAuthUriBase("some.googleapi.com:"));
+            Assert.IsNull(ClientBase.GetAuthUriBase("https://some.googleapi.com/"));
+            Assert.IsNull(ClientBase.GetAuthUriBase("dns://some.googleapi.com:443"));  // just two slashes
+            Assert.IsNull(ClientBase.GetAuthUriBase(""));
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 97ee045..d6a8f52 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -63,6 +63,7 @@
     <Compile Include="..\Grpc.Core\Version.cs">
       <Link>Version.cs</Link>
     </Compile>
+    <Compile Include="ClientBaseTest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ClientServerTest.cs" />
     <Compile Include="ServerTest.cs" />
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index f461844..f240d77 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -33,9 +33,10 @@
 
 using System;
 using System.Collections.Generic;
+using System.Text.RegularExpressions;
 
 using Grpc.Core.Internal;
-using System.Text.RegularExpressions;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
@@ -46,15 +47,16 @@
     /// </summary>
     public abstract class ClientBase
     {
-        static readonly Regex TrailingPortPattern = new Regex(":[0-9]+/?$");
+        // Regex for removal of the optional DNS scheme, trailing port, and trailing backslash
+        static readonly Regex ChannelTargetPattern = new Regex(@"^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$");
+
         readonly Channel channel;
         readonly string authUriBase;
 
         public ClientBase(Channel channel)
         {
             this.channel = channel;
-            // TODO(jtattermush): we shouldn't need to hand-curate the channel.Target contents.
-            this.authUriBase = "https://" + TrailingPortPattern.Replace(channel.Target, "") + "/";
+            this.authUriBase = GetAuthUriBase(channel.Target);
         }
 
         /// <summary>
@@ -104,10 +106,23 @@
                 {
                     options = options.WithHeaders(new Metadata());
                 }
-                var authUri = authUriBase + method.ServiceName;
+                var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
                 interceptor(authUri, options.Headers);
             }
             return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
         }
+
+        /// <summary>
+        /// Creates Auth URI base from channel's target (the one passed at channel creation).
+        /// Fully-qualified service name is to be appended to this.
+        /// </summary>
+        internal static string GetAuthUriBase(string target)
+        {
+            var match = ChannelTargetPattern.Match(target);
+            if (!match.Success) {
+                return null;
+            }
+            return "https://" + match.Groups[2].Value + "/";
+        }
     }
 }
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 9379ae0..bf2bbd8 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -339,7 +339,7 @@
 
 GPR_EXPORT grpc_completion_queue *GPR_CALLTYPE
 grpcsharp_completion_queue_create(void) {
-  return grpc_completion_queue_create();
+  return grpc_completion_queue_create(NULL);
 }
 
 GPR_EXPORT void GPR_CALLTYPE
@@ -354,13 +354,14 @@
 
 GPR_EXPORT grpc_event GPR_CALLTYPE
 grpcsharp_completion_queue_next(grpc_completion_queue *cq) {
-  return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
+  return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                    NULL);
 }
 
 GPR_EXPORT grpc_event GPR_CALLTYPE
 grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) {
   return grpc_completion_queue_pluck(cq, tag,
-                                     gpr_inf_future(GPR_CLOCK_REALTIME));
+                                     gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
 }
 
 /* Channel */
@@ -368,7 +369,7 @@
 GPR_EXPORT grpc_channel *GPR_CALLTYPE
 
 grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) {
-  return grpc_insecure_channel_create(target, args);
+  return grpc_insecure_channel_create(target, args, NULL);
 }
 
 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) {
@@ -382,7 +383,7 @@
                               const char *method, const char *host,
                               gpr_timespec deadline) {
   return grpc_channel_create_call(channel, parent_call, propagation_mask, cq,
-                                  method, host, deadline);
+                                  method, host, deadline, NULL);
 }
 
 GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE
@@ -475,13 +476,13 @@
 /* Call */
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel(grpc_call *call) {
-  return grpc_call_cancel(call);
+  return grpc_call_cancel(call, NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
 grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status,
                                   const char *description) {
-  return grpc_call_cancel_with_status(call, status, description);
+  return grpc_call_cancel_with_status(call, status, description, NULL);
 }
 
 GPR_EXPORT char *GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call *call) {
@@ -538,7 +539,8 @@
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[5].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -575,7 +577,8 @@
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[3].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
@@ -615,7 +618,8 @@
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[4].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -648,7 +652,8 @@
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[2].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -668,7 +673,7 @@
   ops[1].data.send_initial_metadata.metadata = NULL;
   ops[1].flags = 0;
 
-  return grpc_call_start_batch(call, ops, nops, ctx);
+  return grpc_call_start_batch(call, ops, nops, ctx, NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -679,7 +684,8 @@
   ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   ops[0].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
@@ -705,7 +711,7 @@
   ops[1].data.send_initial_metadata.metadata = NULL;
   ops[1].flags = 0;
 
-  return grpc_call_start_batch(call, ops, nops, ctx);
+  return grpc_call_start_batch(call, ops, nops, ctx, NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -715,7 +721,8 @@
   ops[0].op = GRPC_OP_RECV_MESSAGE;
   ops[0].data.recv_message = &(ctx->recv_message);
   ops[0].flags = 0;
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -727,7 +734,8 @@
       (&ctx->recv_close_on_server_cancelled);
   ops[0].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -744,7 +752,8 @@
       ctx->send_initial_metadata.metadata;
   ops[0].flags = 0;
 
-  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
+  return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+                               NULL);
 }
 
 /* Server */
@@ -752,8 +761,8 @@
 GPR_EXPORT grpc_server *GPR_CALLTYPE
 grpcsharp_server_create(grpc_completion_queue *cq,
                         const grpc_channel_args *args) {
-  grpc_server *server = grpc_server_create(args);
-  grpc_server_register_completion_queue(server, cq);
+  grpc_server *server = grpc_server_create(args, NULL);
+  grpc_server_register_completion_queue(server, cq, NULL);
   return server;
 }
 
diff --git a/src/node/examples/perf_test.js b/src/node/examples/perf_test.js
index 214b938..ba8fbf8 100644
--- a/src/node/examples/perf_test.js
+++ b/src/node/examples/perf_test.js
@@ -40,7 +40,7 @@
 
 function runTest(iterations, callback) {
   var testServer = interop_server.getServer(0, false);
-  testServer.server.listen();
+  testServer.server.start();
   var client = new testProto.TestService('localhost:' + testServer.port,
                                          grpc.Credentials.createInsecure());
 
diff --git a/src/node/examples/qps_test.js b/src/node/examples/qps_test.js
index 1ce4dbe..ec968b8 100644
--- a/src/node/examples/qps_test.js
+++ b/src/node/examples/qps_test.js
@@ -60,7 +60,7 @@
  */
 function runTest(concurrent_calls, seconds, callback) {
   var testServer = interop_server.getServer(0, false);
-  testServer.server.listen();
+  testServer.server.start();
   var client = new testProto.TestService('localhost:' + testServer.port,
                                          grpc.Credentials.createInsecure());
 
diff --git a/src/node/examples/route_guide_server.js b/src/node/examples/route_guide_server.js
index bb8e79b..465b32f 100644
--- a/src/node/examples/route_guide_server.js
+++ b/src/node/examples/route_guide_server.js
@@ -248,7 +248,7 @@
       throw err;
     }
     feature_list = JSON.parse(data);
-    routeServer.listen();
+    routeServer.start();
   });
 }
 
diff --git a/src/node/examples/stock_server.js b/src/node/examples/stock_server.js
index dfcfe30..12e5479 100644
--- a/src/node/examples/stock_server.js
+++ b/src/node/examples/stock_server.js
@@ -81,7 +81,7 @@
 
 if (require.main === module) {
   stockServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
-  stockServer.listen();
+  stockServer.start();
 }
 
 module.exports = stockServer;
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index c5c8313..705c80f 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -502,6 +502,22 @@
         return NanThrowTypeError(
             "Call's third argument must be a date or a number");
       }
+      // These arguments are at the end because they are optional
+      grpc_call *parent_call = NULL;
+      if (Call::HasInstance(args[4])) {
+        Call *parent_obj = ObjectWrap::Unwrap<Call>(args[4]->ToObject());
+        parent_call = parent_obj->wrapped_call;
+      } else if (!(args[4]->IsUndefined() || args[4]->IsNull())) {
+        return NanThrowTypeError(
+            "Call's fifth argument must be another call, if provided");
+      }
+      gpr_uint32 propagate_flags = GRPC_PROPAGATE_DEFAULTS;
+      if (args[5]->IsUint32()) {
+        propagate_flags = args[5]->Uint32Value();
+      } else if (!(args[5]->IsUndefined() || args[5]->IsNull())) {
+        return NanThrowTypeError(
+            "Call's sixth argument must be propagate flags, if provided");
+      }
       Handle<Object> channel_object = args[0]->ToObject();
       Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object);
       if (channel->GetWrappedChannel() == NULL) {
@@ -514,14 +530,14 @@
       if (args[3]->IsString()) {
         NanUtf8String host_override(args[3]);
         wrapped_call = grpc_channel_create_call(
-            wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+            wrapped_channel, parent_call, propagate_flags,
             CompletionQueueAsyncWorker::GetQueue(), *method,
-            *host_override, MillisecondsToTimespec(deadline));
+            *host_override, MillisecondsToTimespec(deadline), NULL);
       } else if (args[3]->IsUndefined() || args[3]->IsNull()) {
         wrapped_call = grpc_channel_create_call(
-            wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+            wrapped_channel, parent_call, propagate_flags,
             CompletionQueueAsyncWorker::GetQueue(), *method,
-            NULL, MillisecondsToTimespec(deadline));
+            NULL, MillisecondsToTimespec(deadline), NULL);
       } else {
         return NanThrowTypeError("Call's fourth argument must be a string");
       }
@@ -601,7 +617,7 @@
   NanCallback *callback = new NanCallback(callback_func);
   grpc_call_error error = grpc_call_start_batch(
       call->wrapped_call, &ops[0], nops, new struct tag(
-          callback, op_vector.release(), resources));
+          callback, op_vector.release(), resources), NULL);
   if (error != GRPC_CALL_OK) {
     return NanThrowError("startBatch failed", error);
   }
@@ -615,7 +631,7 @@
     return NanThrowTypeError("cancel can only be called on Call objects");
   }
   Call *call = ObjectWrap::Unwrap<Call>(args.This());
-  grpc_call_error error = grpc_call_cancel(call->wrapped_call);
+  grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL);
   if (error != GRPC_CALL_OK) {
     return NanThrowError("cancel failed", error);
   }
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 457a58c..a61c830 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -33,12 +33,17 @@
 
 #include <vector>
 
+#include "grpc/support/log.h"
+
 #include <node.h>
 #include <nan.h>
 #include "grpc/grpc.h"
 #include "grpc/grpc_security.h"
+#include "call.h"
 #include "channel.h"
+#include "completion_queue_async_worker.h"
 #include "credentials.h"
+#include "timeval.h"
 
 namespace grpc {
 namespace node {
@@ -51,6 +56,7 @@
 using v8::HandleScope;
 using v8::Integer;
 using v8::Local;
+using v8::Number;
 using v8::Object;
 using v8::Persistent;
 using v8::String;
@@ -76,6 +82,12 @@
                           NanNew<FunctionTemplate>(Close)->GetFunction());
   NanSetPrototypeTemplate(tpl, "getTarget",
                           NanNew<FunctionTemplate>(GetTarget)->GetFunction());
+  NanSetPrototypeTemplate(
+      tpl, "getConnectivityState",
+      NanNew<FunctionTemplate>(GetConnectivityState)->GetFunction());
+  NanSetPrototypeTemplate(
+      tpl, "watchConnectivityState",
+      NanNew<FunctionTemplate>(WatchConnectivityState)->GetFunction());
   NanAssignPersistent(fun_tpl, tpl);
   Handle<Function> ctr = tpl->GetFunction();
   constructor = new NanCallback(ctr);
@@ -111,7 +123,7 @@
     grpc_channel_args *channel_args_ptr;
     if (args[2]->IsUndefined()) {
       channel_args_ptr = NULL;
-      wrapped_channel = grpc_insecure_channel_create(*host, NULL);
+      wrapped_channel = grpc_insecure_channel_create(*host, NULL, NULL);
     } else if (args[2]->IsObject()) {
       Handle<Object> args_hash(args[2]->ToObject()->Clone());
       Handle<Array> keys(args_hash->GetOwnPropertyNames());
@@ -145,7 +157,8 @@
       return NanThrowTypeError("Channel expects a string and an object");
     }
     if (creds == NULL) {
-      wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr);
+      wrapped_channel = grpc_insecure_channel_create(*host, channel_args_ptr,
+                                                     NULL);
     } else {
       wrapped_channel =
           grpc_secure_channel_create(creds, *host, channel_args_ptr);
@@ -185,5 +198,52 @@
   NanReturnValue(NanNew(grpc_channel_get_target(channel->wrapped_channel)));
 }
 
+NAN_METHOD(Channel::GetConnectivityState) {
+  NanScope();
+  if (!HasInstance(args.This())) {
+    return NanThrowTypeError(
+        "getConnectivityState can only be called on Channel objects");
+  }
+  Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+  int try_to_connect = (int)args[0]->Equals(NanTrue());
+  NanReturnValue(grpc_channel_check_connectivity_state(channel->wrapped_channel,
+                                                       try_to_connect));
+}
+
+NAN_METHOD(Channel::WatchConnectivityState) {
+  NanScope();
+  if (!HasInstance(args.This())) {
+    return NanThrowTypeError(
+        "watchConnectivityState can only be called on Channel objects");
+  }
+  if (!args[0]->IsUint32()) {
+    return NanThrowTypeError(
+        "watchConnectivityState's first argument must be a channel state");
+  }
+  if (!(args[1]->IsNumber() || args[1]->IsDate())) {
+    return NanThrowTypeError(
+        "watchConnectivityState's second argument must be a date or a number");
+  }
+  if (!args[2]->IsFunction()) {
+    return NanThrowTypeError(
+        "watchConnectivityState's third argument must be a callback");
+  }
+  grpc_connectivity_state last_state =
+      static_cast<grpc_connectivity_state>(args[0]->Uint32Value());
+  double deadline = args[1]->NumberValue();
+  Handle<Function> callback_func = args[2].As<Function>();
+  NanCallback *callback = new NanCallback(callback_func);
+  Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+  unique_ptr<OpVec> ops(new OpVec());
+  grpc_channel_watch_connectivity_state(
+      channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline),
+      CompletionQueueAsyncWorker::GetQueue(),
+      new struct tag(callback,
+                     ops.release(),
+                     shared_ptr<Resources>(nullptr)));
+  CompletionQueueAsyncWorker::Next();
+  NanReturnUndefined();
+}
+
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h
index e2182cb..458f71d 100644
--- a/src/node/ext/channel.h
+++ b/src/node/ext/channel.h
@@ -64,6 +64,8 @@
   static NAN_METHOD(New);
   static NAN_METHOD(Close);
   static NAN_METHOD(GetTarget);
+  static NAN_METHOD(GetConnectivityState);
+  static NAN_METHOD(WatchConnectivityState);
   static NanCallback *constructor;
   static v8::Persistent<v8::FunctionTemplate> fun_tpl;
 
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index 1215c97..bf2cd94 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -63,9 +63,9 @@
 
 void CompletionQueueAsyncWorker::Execute() {
   result =
-      grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME));
+      grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   if (!result.success) {
-    SetErrorMessage("The batch encountered an error");
+    SetErrorMessage("The async function encountered an error");
   }
 }
 
@@ -85,7 +85,7 @@
   NanScope();
   current_threads = 0;
   waiting_next_calls = 0;
-  queue = grpc_completion_queue_create();
+  queue = grpc_completion_queue_create(NULL);
 }
 
 void CompletionQueueAsyncWorker::HandleOKCallback() {
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index 4e31cba..d93dafd 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -159,12 +159,51 @@
   op_type->Set(NanNew("RECV_CLOSE_ON_SERVER"), RECV_CLOSE_ON_SERVER);
 }
 
+void InitPropagateConstants(Handle<Object> exports) {
+  NanScope();
+  Handle<Object> propagate = NanNew<Object>();
+  exports->Set(NanNew("propagate"), propagate);
+  Handle<Value> DEADLINE(NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_DEADLINE));
+  propagate->Set(NanNew("DEADLINE"), DEADLINE);
+  Handle<Value> CENSUS_STATS_CONTEXT(
+      NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT));
+  propagate->Set(NanNew("CENSUS_STATS_CONTEXT"), CENSUS_STATS_CONTEXT);
+  Handle<Value> CENSUS_TRACING_CONTEXT(
+      NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT));
+  propagate->Set(NanNew("CENSUS_TRACING_CONTEXT"), CENSUS_TRACING_CONTEXT);
+  Handle<Value> CANCELLATION(
+      NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CANCELLATION));
+  propagate->Set(NanNew("CANCELLATION"), CANCELLATION);
+  Handle<Value> DEFAULTS(NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_DEFAULTS));
+  propagate->Set(NanNew("DEFAULTS"), DEFAULTS);
+}
+
+void InitConnectivityStateConstants(Handle<Object> exports) {
+  NanScope();
+  Handle<Object> channel_state = NanNew<Object>();
+  exports->Set(NanNew("connectivityState"), channel_state);
+  Handle<Value> IDLE(NanNew<Uint32, uint32_t>(GRPC_CHANNEL_IDLE));
+  channel_state->Set(NanNew("IDLE"), IDLE);
+  Handle<Value> CONNECTING(NanNew<Uint32, uint32_t>(GRPC_CHANNEL_CONNECTING));
+  channel_state->Set(NanNew("CONNECTING"), CONNECTING);
+  Handle<Value> READY(NanNew<Uint32, uint32_t>(GRPC_CHANNEL_READY));
+  channel_state->Set(NanNew("READY"), READY);
+  Handle<Value> TRANSIENT_FAILURE(
+      NanNew<Uint32, uint32_t>(GRPC_CHANNEL_TRANSIENT_FAILURE));
+  channel_state->Set(NanNew("TRANSIENT_FAILURE"), TRANSIENT_FAILURE);
+  Handle<Value> FATAL_FAILURE(
+      NanNew<Uint32, uint32_t>(GRPC_CHANNEL_FATAL_FAILURE));
+  channel_state->Set(NanNew("FATAL_FAILURE"), FATAL_FAILURE);
+}
+
 void init(Handle<Object> exports) {
   NanScope();
   grpc_init();
   InitStatusConstants(exports);
   InitCallErrorConstants(exports);
   InitOpTypeConstants(exports);
+  InitPropagateConstants(exports);
+  InitConnectivityStateConstants(exports);
 
   grpc::node::Call::Init(exports);
   grpc::node::Channel::Init(exports);
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 1dc179d..8e39644 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -113,8 +113,8 @@
 };
 
 Server::Server(grpc_server *server) : wrapped_server(server) {
-  shutdown_queue = grpc_completion_queue_create();
-  grpc_server_register_completion_queue(server, shutdown_queue);
+  shutdown_queue = grpc_completion_queue_create(NULL);
+  grpc_server_register_completion_queue(server, shutdown_queue, NULL);
 }
 
 Server::~Server() {
@@ -158,7 +158,7 @@
                                     this->shutdown_queue,
                                     NULL);
     grpc_completion_queue_pluck(this->shutdown_queue, NULL,
-                                gpr_inf_future(GPR_CLOCK_REALTIME));
+                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
     this->wrapped_server = NULL;
   }
 }
@@ -176,7 +176,7 @@
   grpc_server *wrapped_server;
   grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue();
   if (args[0]->IsUndefined()) {
-    wrapped_server = grpc_server_create(NULL);
+    wrapped_server = grpc_server_create(NULL, NULL);
   } else if (args[0]->IsObject()) {
     Handle<Object> args_hash(args[0]->ToObject());
     Handle<Array> keys(args_hash->GetOwnPropertyNames());
@@ -205,12 +205,12 @@
         return NanThrowTypeError("Arg values must be strings");
       }
     }
-    wrapped_server = grpc_server_create(&channel_args);
+    wrapped_server = grpc_server_create(&channel_args, NULL);
     free(channel_args.args);
   } else {
     return NanThrowTypeError("Server expects an object");
   }
-  grpc_server_register_completion_queue(wrapped_server, queue);
+  grpc_server_register_completion_queue(wrapped_server, queue, NULL);
   Server *server = new Server(wrapped_server);
   server->Wrap(args.This());
   NanReturnValue(args.This());
diff --git a/src/node/index.js b/src/node/index.js
index b26ab35..93c65ac 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -135,6 +135,11 @@
 exports.status = grpc.status;
 
 /**
+ * Propagate flag name to number mapping
+ */
+exports.propagate = grpc.propagate;
+
+/**
  * Call error name to code number mapping
  */
 exports.callError = grpc.callError;
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 27f6c19..6d6f9a3 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -298,7 +298,9 @@
       assert.strictEqual(resp.payload.type, 'COMPRESSABLE');
       assert.strictEqual(resp.payload.body.length, 314159);
       assert.strictEqual(resp.username, expected_user);
-      assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
+      if (scope) {
+        assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
+      }
       if (done) {
         done();
       }
@@ -335,7 +337,7 @@
           if (done) {
             done();
           }
-        });
+        }, client_metadata);
       };
       if (per_rpc) {
         updateMetadata('', {}, makeTestCall);
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index ece22cc..1242a0f 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -194,7 +194,7 @@
   });
   var server_obj = getServer(argv.port, argv.use_tls === 'true');
   console.log('Server attaching to port ' + argv.port);
-  server_obj.server.listen();
+  server_obj.server.start();
 }
 
 /**
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 87c7690..50cbf4a 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -216,14 +216,19 @@
 function getCall(channel, method, options) {
   var deadline;
   var host;
+  var parent;
+  var propagate_flags;
   if (options) {
     deadline = options.deadline;
     host = options.host;
+    parent = _.get(options, 'parent.call');
+    propagate_flags = options.propagate_flags;
   }
   if (deadline === undefined) {
     deadline = Infinity;
   }
-  return new grpc.Call(channel, method, deadline, host);
+  return new grpc.Call(channel, method, deadline, host,
+                       parent, propagate_flags);
 }
 
 /**
@@ -526,7 +531,7 @@
  * requestSerialize: function to serialize request objects
  * responseDeserialize: function to deserialize response objects
  * @param {Object} methods An object mapping method names to method attributes
- * @param {string} serviceName The name of the service
+ * @param {string} serviceName The fully qualified name of the service
  * @return {function(string, Object)} New client constructor
  */
 exports.makeClientConstructor = function(methods, serviceName) {
@@ -551,11 +556,42 @@
     }
     options['grpc.primary_user_agent'] = 'grpc-node/' + version;
     this.channel = new grpc.Channel(address, credentials, options);
-    this.server_address = address.replace(/\/$/, '');
-    this.auth_uri = this.server_address + '/' + serviceName;
+    // Remove the optional DNS scheme, trailing port, and trailing backslash
+    address = address.replace(/^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$/, '$2');
+    this.server_address = address;
+    this.auth_uri = 'https://' + this.server_address + '/' + serviceName;
     this.updateMetadata = updateMetadata;
   }
 
+  /**
+   * Wait for the client to be ready. The callback will be called when the
+   * client has successfully connected to the server, and it will be called
+   * with an error if the attempt to connect to the server has unrecoverablly
+   * failed or if the deadline expires. This function will make the channel
+   * start connecting if it has not already done so.
+   * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
+   *     Infinity to wait forever.
+   * @param {function(Error)} callback The callback to call when done attempting
+   *     to connect.
+   */
+  Client.prototype.$waitForReady = function(deadline, callback) {
+    var self = this;
+    var checkState = function(err) {
+      if (err) {
+        callback(new Error('Failed to connect before the deadline'));
+      }
+      var new_state = self.channel.getConnectivityState(true);
+      if (new_state === grpc.connectivityState.READY) {
+        callback();
+      } else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
+        callback(new Error('Failed to connect to server'));
+      } else {
+        self.channel.watchConnectivityState(new_state, deadline, checkState);
+      }
+    };
+    checkState();
+  };
+
   _.each(methods, function(attrs, name) {
     var method_type;
     if (attrs.requestStream) {
@@ -590,7 +626,8 @@
  */
 exports.makeProtobufClientConstructor =  function(service) {
   var method_attrs = common.getProtobufServiceAttrs(service, service.name);
-  var Client = exports.makeClientConstructor(method_attrs);
+  var Client = exports.makeClientConstructor(
+      method_attrs, common.fullyQualifiedName(service));
   Client.service = service;
   return Client;
 };
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 5c62f59..8b86173 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -432,6 +432,7 @@
   });
   emitter.metadata = metadata;
   waitForCancel(call, emitter);
+  emitter.call = call;
   var batch = {};
   batch[grpc.opType.RECV_MESSAGE] = true;
   call.startBatch(batch, function(err, result) {
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
index c991d7b..d81df2a 100644
--- a/src/node/test/channel_test.js
+++ b/src/node/test/channel_test.js
@@ -36,6 +36,26 @@
 var assert = require('assert');
 var grpc = require('bindings')('grpc.node');
 
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ *     complete.
+ * @param {number} count The number of calls to the resulting function if the
+ *     test passes.
+ * @return {function()} The function that should be called at the end of each
+ *     sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+  return function() {
+    count -= 1;
+    if (count <= 0) {
+      done();
+    }
+  };
+}
 var insecureCreds = grpc.Credentials.createInsecure();
 
 describe('channel', function() {
@@ -86,14 +106,16 @@
     });
   });
   describe('close', function() {
+    var channel;
+    beforeEach(function() {
+      channel = new grpc.Channel('hostname', insecureCreds, {});
+    });
     it('should succeed silently', function() {
-      var channel = new grpc.Channel('hostname', insecureCreds, {});
       assert.doesNotThrow(function() {
         channel.close();
       });
     });
     it('should be idempotent', function() {
-      var channel = new grpc.Channel('hostname', insecureCreds, {});
       assert.doesNotThrow(function() {
         channel.close();
         channel.close();
@@ -101,9 +123,68 @@
     });
   });
   describe('getTarget', function() {
+    var channel;
+    beforeEach(function() {
+      channel = new grpc.Channel('hostname', insecureCreds, {});
+    });
     it('should return a string', function() {
-      var channel = new grpc.Channel('localhost', insecureCreds, {});
       assert.strictEqual(typeof channel.getTarget(), 'string');
     });
   });
+  describe('getConnectivityState', function() {
+    var channel;
+    beforeEach(function() {
+      channel = new grpc.Channel('hostname', insecureCreds, {});
+    });
+    it('should return IDLE for a new channel', function() {
+      assert.strictEqual(channel.getConnectivityState(),
+                         grpc.connectivityState.IDLE);
+    });
+  });
+  describe('watchConnectivityState', function() {
+    var channel;
+    beforeEach(function() {
+      channel = new grpc.Channel('localhost', insecureCreds, {});
+    });
+    afterEach(function() {
+      channel.close();
+    });
+    it('should time out if called alone', function(done) {
+      var old_state = channel.getConnectivityState();
+      var deadline = new Date();
+      deadline.setSeconds(deadline.getSeconds() + 1);
+      channel.watchConnectivityState(old_state, deadline, function(err, value) {
+        assert(err);
+        done();
+      });
+    });
+    it('should complete if a connection attempt is forced', function(done) {
+      var old_state = channel.getConnectivityState();
+      var deadline = new Date();
+      deadline.setSeconds(deadline.getSeconds() + 1);
+      channel.watchConnectivityState(old_state, deadline, function(err, value) {
+        assert.ifError(err);
+        assert.notEqual(value.new_state, old_state);
+        done();
+      });
+      channel.getConnectivityState(true);
+    });
+    it('should complete twice if called twice', function(done) {
+      done = multiDone(done, 2);
+      var old_state = channel.getConnectivityState();
+      var deadline = new Date();
+      deadline.setSeconds(deadline.getSeconds() + 1);
+      channel.watchConnectivityState(old_state, deadline, function(err, value) {
+        assert.ifError(err);
+        assert.notEqual(value.new_state, old_state);
+        done();
+      });
+      channel.watchConnectivityState(old_state, deadline, function(err, value) {
+        assert.ifError(err);
+        assert.notEqual(value.new_state, old_state);
+        done();
+      });
+      channel.getConnectivityState(true);
+    });
+  });
 });
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
index ecc98ec..fa06ad4 100644
--- a/src/node/test/constant_test.js
+++ b/src/node/test/constant_test.js
@@ -78,6 +78,31 @@
   'INVALID_FLAGS'
 ];
 
+/**
+ * List of all propagate flag names
+ * @const
+ * @type {Array.<string>}
+ */
+var propagateFlagNames = [
+  'DEADLINE',
+  'CENSUS_STATS_CONTEXT',
+  'CENSUS_TRACING_CONTEXT',
+  'CANCELLATION',
+  'DEFAULTS'
+];
+/*
+ * List of all connectivity state names
+ * @const
+ * @type {Array.<string>}
+ */
+var connectivityStateNames = [
+  'IDLE',
+  'CONNECTING',
+  'READY',
+  'TRANSIENT_FAILURE',
+  'FATAL_FAILURE'
+];
+
 describe('constants', function() {
   it('should have all of the status constants', function() {
     for (var i = 0; i < statusNames.length; i++) {
@@ -91,4 +116,16 @@
              'call error missing: ' + callErrorNames[i]);
     }
   });
+  it('should have all of the propagate flags', function() {
+    for (var i = 0; i < propagateFlagNames.length; i++) {
+      assert(grpc.propagate.hasOwnProperty(propagateFlagNames[i]),
+             'call error missing: ' + propagateFlagNames[i]);
+    }
+  });
+  it('should have all of the connectivity states', function() {
+    for (var i = 0; i < connectivityStateNames.length; i++) {
+      assert(grpc.connectivityState.hasOwnProperty(connectivityStateNames[i]),
+             'connectivity status missing: ' + connectivityStateNames[i]);
+    }
+  });
 });
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index a9df439..20c9a07 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -83,7 +83,7 @@
       server = new grpc.Server();
     });
   });
-  describe('listen', function() {
+  describe('start', function() {
     var server;
     before(function() {
       server = new grpc.Server();
@@ -92,7 +92,7 @@
     after(function() {
       server.shutdown();
     });
-    it('should listen without error', function() {
+    it('should start without error', function() {
       assert.doesNotThrow(function() {
         server.start();
       });
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index dda2f8d..52515cc 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -47,6 +47,27 @@
 
 var _ = require('lodash');
 
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ *     complete.
+ * @param {number} count The number of calls to the resulting function if the
+ *     test passes.
+ * @return {function()} The function that should be called at the end of each
+ *     sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+  return function() {
+    count -= 1;
+    if (count <= 0) {
+      done();
+    }
+  };
+}
+
 var server_insecure_creds = grpc.ServerCredentials.createInsecure();
 
 describe('File loader', function() {
@@ -112,6 +133,58 @@
     });
   });
 });
+describe('Client#$waitForReady', function() {
+  var server;
+  var port;
+  var Client;
+  var client;
+  before(function() {
+    server = new grpc.Server();
+    port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
+    server.start();
+    Client = surface_client.makeProtobufClientConstructor(mathService);
+  });
+  beforeEach(function() {
+    client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+  });
+  after(function() {
+    server.shutdown();
+  });
+  it('should complete when called alone', function(done) {
+    client.$waitForReady(Infinity, function(error) {
+      assert.ifError(error);
+      done();
+    });
+  });
+  it('should complete when a call is initiated', function(done) {
+    client.$waitForReady(Infinity, function(error) {
+      assert.ifError(error);
+      done();
+    });
+    var call = client.div({}, function(err, response) {});
+    call.cancel();
+  });
+  it('should complete if called more than once', function(done) {
+    done = multiDone(done, 2);
+    client.$waitForReady(Infinity, function(error) {
+      assert.ifError(error);
+      done();
+    });
+    client.$waitForReady(Infinity, function(error) {
+      assert.ifError(error);
+      done();
+    });
+  });
+  it('should complete if called when already ready', function(done) {
+    client.$waitForReady(Infinity, function(error) {
+      assert.ifError(error);
+      client.$waitForReady(Infinity, function(error) {
+        assert.ifError(error);
+        done();
+      });
+    });
+  });
+});
 describe('Echo service', function() {
   var server;
   var client;
@@ -272,12 +345,14 @@
   });
 });
 describe('Other conditions', function() {
+  var test_service;
+  var Client;
   var client;
   var server;
   var port;
   before(function() {
     var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
-    var test_service = test_proto.lookup('TestService');
+    test_service = test_proto.lookup('TestService');
     server = new grpc.Server();
     server.addProtoService(test_service, {
       unary: function(call, cb) {
@@ -339,7 +414,7 @@
       }
     });
     port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
     server.start();
   });
@@ -592,6 +667,166 @@
       });
     });
   });
+  describe('Call propagation', function() {
+    var proxy;
+    var proxy_impl;
+    beforeEach(function() {
+      proxy = new grpc.Server();
+      proxy_impl = {
+        unary: function(call) {},
+        clientStream: function(stream) {},
+        serverStream: function(stream) {},
+        bidiStream: function(stream) {}
+      };
+    });
+    afterEach(function() {
+      console.log('Shutting down server');
+      proxy.shutdown();
+    });
+    describe('Cancellation', function() {
+      it('With a unary call', function(done) {
+        done = multiDone(done, 2);
+        proxy_impl.unary = function(parent, callback) {
+          client.unary(parent.request, function(err, value) {
+            try {
+              assert(err);
+              assert.strictEqual(err.code, grpc.status.CANCELLED);
+            } finally {
+              callback(err, value);
+              done();
+            }
+          }, null, {parent: parent});
+          call.cancel();
+        };
+        proxy.addProtoService(test_service, proxy_impl);
+        var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+        proxy.start();
+        var proxy_client = new Client('localhost:' + proxy_port,
+                                      grpc.Credentials.createInsecure());
+        var call = proxy_client.unary({}, function(err, value) {
+          done();
+        });
+      });
+      it('With a client stream call', function(done) {
+        done = multiDone(done, 2);
+        proxy_impl.clientStream = function(parent, callback) {
+          client.clientStream(function(err, value) {
+            try {
+              assert(err);
+              assert.strictEqual(err.code, grpc.status.CANCELLED);
+            } finally {
+              callback(err, value);
+              done();
+            }
+          }, null, {parent: parent});
+          call.cancel();
+        };
+        proxy.addProtoService(test_service, proxy_impl);
+        var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+        proxy.start();
+        var proxy_client = new Client('localhost:' + proxy_port,
+                                      grpc.Credentials.createInsecure());
+        var call = proxy_client.clientStream(function(err, value) {
+          done();
+        });
+      });
+      it('With a server stream call', function(done) {
+        done = multiDone(done, 2);
+        proxy_impl.serverStream = function(parent) {
+          var child = client.serverStream(parent.request, null,
+                                          {parent: parent});
+          child.on('error', function(err) {
+            assert(err);
+            assert.strictEqual(err.code, grpc.status.CANCELLED);
+            done();
+          });
+          call.cancel();
+        };
+        proxy.addProtoService(test_service, proxy_impl);
+        var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+        proxy.start();
+        var proxy_client = new Client('localhost:' + proxy_port,
+                                      grpc.Credentials.createInsecure());
+        var call = proxy_client.serverStream({});
+        call.on('error', function(err) {
+          done();
+        });
+      });
+      it('With a bidi stream call', function(done) {
+        done = multiDone(done, 2);
+        proxy_impl.bidiStream = function(parent) {
+          var child = client.bidiStream(null, {parent: parent});
+          child.on('error', function(err) {
+            assert(err);
+            assert.strictEqual(err.code, grpc.status.CANCELLED);
+            done();
+          });
+          call.cancel();
+        };
+        proxy.addProtoService(test_service, proxy_impl);
+        var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+        proxy.start();
+        var proxy_client = new Client('localhost:' + proxy_port,
+                                      grpc.Credentials.createInsecure());
+        var call = proxy_client.bidiStream();
+        call.on('error', function(err) {
+          done();
+        });
+      });
+    });
+    describe('Deadline', function() {
+      /* jshint bitwise:false */
+      var deadline_flags = (grpc.propagate.DEFAULTS &
+          ~grpc.propagate.CANCELLATION);
+      it('With a client stream call', function(done) {
+        done = multiDone(done, 2);
+        proxy_impl.clientStream = function(parent, callback) {
+          client.clientStream(function(err, value) {
+            try {
+              assert(err);
+              assert.strictEqual(err.code, grpc.status.DEADLINE_EXCEEDED);
+            } finally {
+              callback(err, value);
+              done();
+            }
+          }, null, {parent: parent, propagate_flags: deadline_flags});
+        };
+        proxy.addProtoService(test_service, proxy_impl);
+        var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+        proxy.start();
+        var proxy_client = new Client('localhost:' + proxy_port,
+                                      grpc.Credentials.createInsecure());
+        var deadline = new Date();
+        deadline.setSeconds(deadline.getSeconds() + 1);
+        proxy_client.clientStream(function(err, value) {
+          done();
+        }, null, {deadline: deadline});
+      });
+      it('With a bidi stream call', function(done) {
+        done = multiDone(done, 2);
+        proxy_impl.bidiStream = function(parent) {
+          var child = client.bidiStream(
+              null, {parent: parent, propagate_flags: deadline_flags});
+          child.on('error', function(err) {
+            assert(err);
+            assert.strictEqual(err.code, grpc.status.DEADLINE_EXCEEDED);
+            done();
+          });
+        };
+        proxy.addProtoService(test_service, proxy_impl);
+        var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+        proxy.start();
+        var proxy_client = new Client('localhost:' + proxy_port,
+                                      grpc.Credentials.createInsecure());
+        var deadline = new Date();
+        deadline.setSeconds(deadline.getSeconds() + 1);
+        var call = proxy_client.bidiStream(null, {deadline: deadline});
+        call.on('error', function(err) {
+          done();
+        });
+      });
+    });
+  });
 });
 describe('Cancelling surface client', function() {
   var client;
diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m
index ed39d4b..83b0de1 100644
--- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m
+++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.m
@@ -40,7 +40,7 @@
 @implementation GRPCCall (OAuth2)
 
 - (NSString *)oauth2AccessToken {
-  NSString *headerValue = self.requestMetadata[kAuthorizationHeader];
+  NSString *headerValue = self.requestHeaders[kAuthorizationHeader];
   if ([headerValue hasPrefix:kBearerPrefix]) {
     return [headerValue substringFromIndex:kBearerPrefix.length];
   } else {
@@ -50,14 +50,14 @@
 
 - (void)setOauth2AccessToken:(NSString *)token {
   if (token) {
-    self.requestMetadata[kAuthorizationHeader] = [kBearerPrefix stringByAppendingString:token];
+    self.requestHeaders[kAuthorizationHeader] = [kBearerPrefix stringByAppendingString:token];
   } else {
-    [self.requestMetadata removeObjectForKey:kAuthorizationHeader];
+    [self.requestHeaders removeObjectForKey:kAuthorizationHeader];
   }
 }
 
 - (NSString *)oauth2ChallengeHeader {
-  return self.responseMetadata[kChallengeHeader];
+  return self.responseHeaders[kChallengeHeader];
 }
 
 @end
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 4a8b7ff..4eda499 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -48,8 +48,10 @@
 #import <Foundation/Foundation.h>
 #import <RxLibrary/GRXWriter.h>
 
-// Key used in |NSError|'s |userInfo| dictionary to store the response metadata sent by the server.
-extern id const kGRPCStatusMetadataKey;
+// Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by
+// the server.
+extern id const kGRPCHeadersKey;
+extern id const kGRPCTrailersKey;
 
 // Represents a single gRPC remote call.
 @interface GRPCCall : GRXWriter
@@ -57,43 +59,49 @@
 // These HTTP headers will be passed to the server as part of this call. Each HTTP header is a
 // name-value pair with string names and either string or binary values.
 //
-// The passed dictionary has to use NSString keys, corresponding to the header names. The
-// value associated to each can be a NSString object or a NSData object. E.g.:
+// The passed dictionary has to use NSString keys, corresponding to the header names. The value
+// associated to each can be a NSString object or a NSData object. E.g.:
 //
-// call.requestMetadata = @{@"Authorization": @"Bearer ..."};
+// call.requestHeaders = @{@"authorization": @"Bearer ..."};
 //
-// call.requestMetadata[@"SomeBinaryHeader"] = someData;
+// call.requestHeaders[@"my-header-bin"] = someData;
 //
-// After the call is started, modifying this won't have any effect.
+// After the call is started, trying to modify this property is an error.
 //
 // For convenience, the property is initialized to an empty NSMutableDictionary, and the setter
 // accepts (and copies) both mutable and immutable dictionaries.
-- (NSMutableDictionary *)requestMetadata; // nonatomic
-- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy
+- (NSMutableDictionary *)requestHeaders; // nonatomic
+- (void)setRequestHeaders:(NSDictionary *)requestHeaders; // nonatomic, copy
 
-// This dictionary is populated with the HTTP headers received from the server. When the RPC ends,
-// the HTTP trailers received are added to the dictionary too. It has the same structure as the
-// request metadata dictionary.
+// This dictionary is populated with the HTTP headers received from the server. This happens before
+// any response message is received from the server. It has the same structure as the request
+// headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a
+// NSData value; the others have a NSString value.
 //
-// The first time this object calls |writeValue| on the writeable passed to |startWithWriteable|,
-// the |responseMetadata| dictionary already contains the response headers. When it calls
-// |writesFinishedWithError|, the dictionary contains both the response headers and trailers.
-@property(atomic, readonly) NSDictionary *responseMetadata;
+// The value of this property is nil until all response headers are received, and will change before
+// any of -writeValue: or -writesFinishedWithError: are sent to the writeable.
+@property(atomic, readonly) NSDictionary *responseHeaders;
+
+// Same as responseHeaders, but populated with the HTTP trailers received from the server before the
+// call finishes.
+//
+// The value of this property is nil until all response trailers are received, and will change
+// before -writesFinishedWithError: is sent to the writeable.
+@property(atomic, readonly) NSDictionary *responseTrailers;
 
 // The request writer has to write NSData objects into the provided Writeable. The server will
-// receive each of those separately and in order.
-// A gRPC call might not complete until the request writer finishes. On the other hand, the
-// request finishing doesn't necessarily make the call to finish, as the server might continue
-// sending messages to the response side of the call indefinitely (depending on the semantics of
-// the specific remote method called).
+// receive each of those separately and in order as distinct messages.
+// A gRPC call might not complete until the request writer finishes. On the other hand, the request
+// finishing doesn't necessarily make the call to finish, as the server might continue sending
+// messages to the response side of the call indefinitely (depending on the semantics of the
+// specific remote method called).
 // To finish a call right away, invoke cancel.
 - (instancetype)initWithHost:(NSString *)host
                         path:(NSString *)path
               requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER;
 
-// Finishes the request side of this call, notifies the server that the RPC
-// should be cancelled, and finishes the response side of the call with an error
-// of code CANCELED.
+// Finishes the request side of this call, notifies the server that the RPC should be cancelled, and
+// finishes the response side of the call with an error of code CANCELED.
 - (void)cancel;
 
 // TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 0f4c811..ff5d1c5 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -42,9 +42,13 @@
 #import "private/NSDictionary+GRPC.h"
 #import "private/NSError+GRPC.h"
 
-NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
+NSString * const kGRPCHeadersKey = @"io.grpc.HeadersKey";
+NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 
 @interface GRPCCall () <GRXWriteable>
+// Make them read-write.
+@property(atomic, strong) NSDictionary *responseHeaders;
+@property(atomic, strong) NSDictionary *responseTrailers;
 @end
 
 // The following methods of a C gRPC call object aren't reentrant, and thus
@@ -89,8 +93,7 @@
   // the response arrives.
   GRPCCall *_retainSelf;
 
-  NSMutableDictionary *_requestMetadata;
-  NSMutableDictionary *_responseMetadata;
+  NSMutableDictionary *_requestHeaders;
 }
 
 @synthesize state = _state;
@@ -121,24 +124,19 @@
 
     _requestWriter = requestWriter;
 
-    _requestMetadata = [NSMutableDictionary dictionary];
-    _responseMetadata = [NSMutableDictionary dictionary];
+    _requestHeaders = [NSMutableDictionary dictionary];
   }
   return self;
 }
 
 #pragma mark Metadata
 
-- (NSMutableDictionary *)requestMetadata {
-  return _requestMetadata;
+- (NSMutableDictionary *)requestHeaders {
+  return _requestHeaders;
 }
 
-- (void)setRequestMetadata:(NSDictionary *)requestMetadata {
-  _requestMetadata = [NSMutableDictionary dictionaryWithDictionary:requestMetadata];
-}
-
-- (NSDictionary *)responseMetadata {
-  return _responseMetadata;
+- (void)setRequestHeaders:(NSDictionary *)requestHeaders {
+  _requestHeaders = [NSMutableDictionary dictionaryWithDictionary:requestHeaders];
 }
 
 #pragma mark Finish
@@ -232,11 +230,10 @@
 
 #pragma mark Send headers
 
-// TODO(jcanizales): Rename to commitHeaders.
-- (void)sendHeaders:(NSDictionary *)metadata {
+- (void)sendHeaders:(NSDictionary *)headers {
   // TODO(jcanizales): Add error handlers for async failures
   [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc]
-                                            initWithMetadata:metadata ?: @{} handler:nil]]];
+                                            initWithMetadata:headers ?: @{} handler:nil]]];
 }
 
 #pragma mark GRXWriteable implementation
@@ -305,35 +302,45 @@
 
 // Both handlers will eventually be called, from the network queue. Writes can start immediately
 // after this.
-// The first one (metadataHandler), when the response headers are received.
+// The first one (headersHandler), when the response headers are received.
 // The second one (completionHandler), whenever the RPC finishes for any reason.
-- (void)invokeCallWithMetadataHandler:(void(^)(NSDictionary *))metadataHandler
+- (void)invokeCallWithHeadersHandler:(void(^)(NSDictionary *))headersHandler
                     completionHandler:(void(^)(NSError *, NSDictionary *))completionHandler {
   // TODO(jcanizales): Add error handlers for async failures
   [_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvMetadata alloc]
-                                            initWithHandler:metadataHandler]]];
+                                            initWithHandler:headersHandler]]];
   [_wrappedCall startBatchWithOperations:@[[[GRPCOpRecvStatus alloc]
                                             initWithHandler:completionHandler]]];
 }
 
 - (void)invokeCall {
   __weak GRPCCall *weakSelf = self;
-  [self invokeCallWithMetadataHandler:^(NSDictionary *headers) {
+  [self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
     // Response headers received.
     GRPCCall *strongSelf = weakSelf;
     if (strongSelf) {
-      [strongSelf->_responseMetadata addEntriesFromDictionary:headers];
+      strongSelf.responseHeaders = headers;
       [strongSelf startNextRead];
     }
   } completionHandler:^(NSError *error, NSDictionary *trailers) {
     GRPCCall *strongSelf = weakSelf;
     if (strongSelf) {
-      [strongSelf->_responseMetadata addEntriesFromDictionary:trailers];
+      strongSelf.responseTrailers = trailers;
 
       if (error) {
-        NSMutableDictionary *userInfo =
-            [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
-        userInfo[kGRPCStatusMetadataKey] = strongSelf->_responseMetadata;
+        NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+        if (error.userInfo) {
+          [userInfo addEntriesFromDictionary:error.userInfo];
+        }
+        userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
+        // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
+        // called before this one, so an error might end up with trailers but no headers. We
+        // shouldn't call finishWithError until ater both blocks are called. It is also when this is
+        // done that we can provide a merged view of response headers and trailers in a thread-safe
+        // way.
+        if (strongSelf.responseHeaders) {
+          userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
+        }
         error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
       }
       [strongSelf finishWithError:error];
@@ -356,7 +363,7 @@
   _retainSelf = self;
 
   _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
-  [self sendHeaders:_requestMetadata];
+  [self sendHeaders:_requestHeaders];
   [self invokeCall];
 }
 
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index 696069c..ea2b01e 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -43,7 +43,7 @@
 
 - (instancetype)init {
   if ((self = [super init])) {
-    _unmanagedQueue = grpc_completion_queue_create();
+    _unmanagedQueue = grpc_completion_queue_create(NULL);
 
     // This is for the following block to capture the pointer by value (instead
     // of retaining self and doing self->_unmanagedQueue). This is essential
@@ -64,7 +64,8 @@
       while (YES) {
         // The following call blocks until an event is available.
         grpc_event event = grpc_completion_queue_next(unmanagedQueue,
-                                                      gpr_inf_future(GPR_CLOCK_REALTIME));
+                                                      gpr_inf_future(GPR_CLOCK_REALTIME),
+                                                      NULL);
         GRPCQueueCompletionHandler handler;
         switch (event.type) {
           case GRPC_OP_COMPLETE:
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index d902f95..a7142d0 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -97,7 +97,7 @@
                                   queue.unmanagedQueue,
                                   path.UTF8String,
                                   self.hostName.UTF8String,
-                                  gpr_inf_future(GPR_CLOCK_REALTIME));
+                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
 }
 
 - (GRPCChannel *)channel {
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
index 070a529..15b6ffc 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
@@ -38,7 +38,7 @@
 @implementation GRPCUnsecuredChannel
 
 - (instancetype)initWithHost:(NSString *)host {
-  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]);
+  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL, NULL)]);
 }
 
 // TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index 951c051..fe3d51d 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -282,7 +282,7 @@
     for (GRPCOperation *operation in operations) {
       [operation finish];
     }
-  }));
+  }), NULL);
   gpr_free(ops_array);
 
   if (error != GRPC_CALL_OK) {
@@ -293,7 +293,7 @@
 }
 
 - (void)cancel {
-  grpc_call_cancel(_call);
+  grpc_call_cancel(_call, NULL);
 }
 
 - (void)dealloc {
diff --git a/src/objective-c/RxLibrary/GRXWriteable.h b/src/objective-c/RxLibrary/GRXWriteable.h
index 216de30..45613d6 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.h
+++ b/src/objective-c/RxLibrary/GRXWriteable.h
@@ -48,15 +48,15 @@
 
 typedef void (^GRXValueHandler)(id value);
 typedef void (^GRXCompletionHandler)(NSError *errorOrNil);
-typedef void (^GRXSingleValueHandler)(id value, NSError *errorOrNil);
-typedef void (^GRXStreamHandler)(BOOL done, id value, NSError *error);
+typedef void (^GRXSingleHandler)(id value, NSError *errorOrNil);
+typedef void (^GRXEventHandler)(BOOL done, id value, NSError *error);
 
 // Utility to create objects that conform to the GRXWriteable protocol, from
 // blocks that handle each of the two methods of the protocol.
 @interface GRXWriteable : NSObject<GRXWriteable>
 
-+ (instancetype)writeableWithSingleValueHandler:(GRXSingleValueHandler)handler;
-+ (instancetype)writeableWithStreamHandler:(GRXStreamHandler)handler;
++ (instancetype)writeableWithSingleHandler:(GRXSingleHandler)handler;
++ (instancetype)writeableWithEventHandler:(GRXEventHandler)handler;
 
 - (instancetype)initWithValueHandler:(GRXValueHandler)valueHandler
                    completionHandler:(GRXCompletionHandler)completionHandler
diff --git a/src/objective-c/RxLibrary/GRXWriteable.m b/src/objective-c/RxLibrary/GRXWriteable.m
index 63f7c3e..2729d62 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.m
+++ b/src/objective-c/RxLibrary/GRXWriteable.m
@@ -38,7 +38,7 @@
   GRXCompletionHandler _completionHandler;
 }
 
-+ (instancetype)writeableWithSingleValueHandler:(GRXSingleValueHandler)handler {
++ (instancetype)writeableWithSingleHandler:(GRXSingleHandler)handler {
   if (!handler) {
     return [[self alloc] init];
   }
@@ -51,7 +51,7 @@
   }];
 }
 
-+ (instancetype)writeableWithStreamHandler:(GRXStreamHandler)handler {
++ (instancetype)writeableWithEventHandler:(GRXEventHandler)handler {
   if (!handler) {
     return [[self alloc] init];
   }
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index f231029..06581e7 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -168,11 +168,13 @@
   } completionHandler:^(NSError *errorOrNil) {
     XCTAssertNotNil(errorOrNil, @"Finished without error!");
     XCTAssertEqual(errorOrNil.code, 16, @"Finished with unexpected error: %@", errorOrNil);
-    XCTAssertEqualObjects(call.responseMetadata, errorOrNil.userInfo[kGRPCStatusMetadataKey],
-                          @"Metadata in the NSError object and call object differ.");
+    XCTAssertEqualObjects(call.responseHeaders, errorOrNil.userInfo[kGRPCHeadersKey],
+                          @"Headers in the NSError object and call object differ.");
+    XCTAssertEqualObjects(call.responseTrailers, errorOrNil.userInfo[kGRPCTrailersKey],
+                          @"Trailers in the NSError object and call object differ.");
     NSString *challengeHeader = call.oauth2ChallengeHeader;
     XCTAssertGreaterThan(challengeHeader.length, 0,
-                         @"No challenge in response headers %@", call.responseMetadata);
+                         @"No challenge in response headers %@", call.responseHeaders);
     [expectation fulfill];
   }];
 
diff --git a/src/objective-c/tests/RxLibraryUnitTests.m b/src/objective-c/tests/RxLibraryUnitTests.m
index 5e31628..a67a4c6 100644
--- a/src/objective-c/tests/RxLibraryUnitTests.m
+++ b/src/objective-c/tests/RxLibraryUnitTests.m
@@ -55,7 +55,7 @@
   return [[self alloc] init];
 }
 
-- (GRXSingleValueHandler)block {
+- (GRXSingleHandler)block {
   return ^(id value, NSError *errorOrNil) {
     ++_timesCalled;
     _value = value;
@@ -71,13 +71,13 @@
 
 #pragma mark Writeable
 
-- (void)testWriteableSingleValueHandlerIsCalledForValue {
+- (void)testWriteableSingleHandlerIsCalledForValue {
   // Given:
   CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
   id anyValue = @7;
 
   // If:
-  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleValueHandler:handler.block];
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
   [writeable writeValue:anyValue];
 
   // Then:
@@ -86,13 +86,13 @@
   XCTAssertEqualObjects(handler.errorOrNil, nil);
 }
 
-- (void)testWriteableSingleValueHandlerIsCalledForError {
+- (void)testWriteableSingleHandlerIsCalledForError {
   // Given:
   CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
   NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil];
 
   // If:
-  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleValueHandler:handler.block];
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
   [writeable writesFinishedWithError:anyError];
 
   // Then:
@@ -106,7 +106,7 @@
 - (void)testBufferedPipePropagatesValue {
   // Given:
   CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
-  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleValueHandler:handler.block];
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
   id anyValue = @7;
 
   // If:
@@ -123,7 +123,7 @@
 - (void)testBufferedPipePropagatesError {
   // Given:
   CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
-  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleValueHandler:handler.block];
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
   NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil];
 
   // If:
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 01ec909..1cf766c 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -241,7 +241,7 @@
           deadline_obj TSRMLS_CC);
   call->wrapped = grpc_channel_create_call(
       channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS, completion_queue, method,
-      channel->target, deadline->wrapped);
+      channel->target, deadline->wrapped, NULL);
 }
 
 /**
@@ -400,7 +400,8 @@
     ops[op_num].flags = 0;
     op_num++;
   }
-  error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped);
+  error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
+                                NULL);
   if (error != GRPC_CALL_OK) {
     zend_throw_exception(spl_ce_LogicException,
                          "start_batch was called incorrectly",
@@ -408,7 +409,7 @@
     goto cleanup;
   }
   event = grpc_completion_queue_pluck(completion_queue, call->wrapped,
-                                      gpr_inf_future(GPR_CLOCK_REALTIME));
+                                      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   if (!event.success) {
     zend_throw_exception(spl_ce_LogicException,
                          "The batch failed for some reason",
@@ -489,7 +490,7 @@
 PHP_METHOD(Call, cancel) {
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  grpc_call_cancel(call->wrapped);
+  grpc_call_cancel(call->wrapped, NULL);
 }
 
 static zend_function_entry call_methods[] = {
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 7d8a6f8..f8ce04d 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -51,8 +51,10 @@
 #include <grpc/support/log.h>
 #include <grpc/grpc_security.h>
 
-#include "server.h"
+#include "completion_queue.h"
 #include "credentials.h"
+#include "server.h"
+#include "timeval.h"
 
 zend_class_entry *grpc_ce_channel;
 
@@ -152,7 +154,7 @@
   override = target;
   override_len = target_length;
   if (args_array == NULL) {
-    channel->wrapped = grpc_insecure_channel_create(target, NULL);
+    channel->wrapped = grpc_insecure_channel_create(target, NULL, NULL);
   } else {
     array_hash = Z_ARRVAL_P(args_array);
     if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
@@ -182,7 +184,7 @@
     }
     php_grpc_read_args_array(args_array, &args);
     if (creds == NULL) {
-      channel->wrapped = grpc_insecure_channel_create(target, &args);
+      channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
     } else {
       gpr_log(GPR_DEBUG, "Initialized secure channel");
       channel->wrapped =
@@ -205,6 +207,59 @@
 }
 
 /**
+ * Get the connectivity state of the channel
+ * @param bool (optional) try to connect on the channel
+ * @return long The grpc connectivity state
+ */
+PHP_METHOD(Channel, getConnectivityState) {
+  wrapped_grpc_channel *channel =
+      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  bool try_to_connect;
+  /* "|b" == 1 optional bool */
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect) ==
+      FAILURE) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+                         "getConnectivityState expects a bool", 1 TSRMLS_CC);
+    return;
+  }
+  RETURN_LONG(grpc_channel_check_connectivity_state(channel->wrapped,
+                                                    (int)try_to_connect));
+}
+
+/**
+ * Watch the connectivity state of the channel until it changed
+ * @param long The previous connectivity state of the channel
+ * @param Timeval The deadline this function should wait until
+ * @return bool If the connectivity state changes from last_state
+ *              before deadline
+ */
+PHP_METHOD(Channel, watchConnectivityState) {
+  wrapped_grpc_channel *channel =
+      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  long last_state;
+  zval *deadline_obj;
+  /* "lO" == 1 long 1 object */
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
+          &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+        "watchConnectivityState expects 1 long 1 timeval",
+        1 TSRMLS_CC);
+    return;
+  }
+
+  wrapped_grpc_timeval *deadline =
+      (wrapped_grpc_timeval *)zend_object_store_get_object(
+          deadline_obj TSRMLS_CC);
+  grpc_channel_watch_connectivity_state(
+      channel->wrapped, (grpc_connectivity_state)last_state,
+      deadline->wrapped, completion_queue, NULL);
+  grpc_event event = grpc_completion_queue_pluck(
+      completion_queue, NULL,
+      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  RETURN_BOOL(event.success);
+}
+
+/**
  * Close the channel
  */
 PHP_METHOD(Channel, close) {
@@ -219,6 +274,8 @@
 static zend_function_entry channel_methods[] = {
     PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
     PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Channel, getConnectivityState, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Channel, watchConnectivityState, NULL, ZEND_ACC_PUBLIC)
     PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
     PHP_FE_END};
 
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
index c653a59..741204b 100644
--- a/src/php/ext/grpc/completion_queue.c
+++ b/src/php/ext/grpc/completion_queue.c
@@ -38,14 +38,13 @@
 grpc_completion_queue *completion_queue;
 
 void grpc_php_init_completion_queue(TSRMLS_D) {
-  completion_queue = grpc_completion_queue_create();
+  completion_queue = grpc_completion_queue_create(NULL);
 }
 
 void grpc_php_shutdown_completion_queue(TSRMLS_D) {
   grpc_completion_queue_shutdown(completion_queue);
   while (grpc_completion_queue_next(completion_queue,
-                                    gpr_inf_future(GPR_CLOCK_REALTIME))
-             .type != GRPC_QUEUE_SHUTDOWN)
-    ;
+                                    gpr_inf_future(GPR_CLOCK_REALTIME),
+                                    NULL).type != GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(completion_queue);
 }
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index fedcf0f..0f730ea 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -183,6 +183,18 @@
   REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
                          GRPC_OP_RECV_CLOSE_ON_SERVER, CONST_CS);
 
+  /* Register connectivity state constants */
+  REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE",
+                         GRPC_CHANNEL_IDLE, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING",
+                         GRPC_CHANNEL_CONNECTING, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY",
+                         GRPC_CHANNEL_READY, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE",
+                         GRPC_CHANNEL_TRANSIENT_FAILURE, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_FATAL_FAILURE",
+                         GRPC_CHANNEL_FATAL_FAILURE, CONST_CS);
+
   grpc_init_call(TSRMLS_C);
   grpc_init_channel(TSRMLS_C);
   grpc_init_server(TSRMLS_C);
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index d58aa88..ca129e7 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -66,7 +66,7 @@
     grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
     grpc_server_cancel_all_calls(server->wrapped);
     grpc_completion_queue_pluck(completion_queue, NULL,
-                                gpr_inf_future(GPR_CLOCK_REALTIME));
+                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
     grpc_server_destroy(server->wrapped);
   }
   efree(server);
@@ -109,13 +109,14 @@
     return;
   }
   if (args_array == NULL) {
-    server->wrapped = grpc_server_create(NULL);
+    server->wrapped = grpc_server_create(NULL, NULL);
   } else {
     php_grpc_read_args_array(args_array, &args);
-    server->wrapped = grpc_server_create(&args);
+    server->wrapped = grpc_server_create(&args, NULL);
     efree(args.args);
   }
-  grpc_server_register_completion_queue(server->wrapped, completion_queue);
+  grpc_server_register_completion_queue(server->wrapped, completion_queue,
+                                        NULL);
 }
 
 /**
@@ -146,7 +147,7 @@
     goto cleanup;
   }
   event = grpc_completion_queue_pluck(completion_queue, NULL,
-                                      gpr_inf_future(GPR_CLOCK_REALTIME));
+                                      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   if (!event.success) {
     zend_throw_exception(spl_ce_LogicException,
                          "Failed to request a call for some reason",
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index a0c6779..9d6a77b 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -75,6 +75,51 @@
   }
 
   /**
+   * @param $try_to_connect bool
+   * @return int The grpc connectivity state
+   */
+  public function getConnectivityState($try_to_connect = false) {
+    return $this->channel->getConnectivityState($try_to_connect);
+  }
+
+  /**
+   * @param $timeout in microseconds
+   * @return bool true if channel is ready
+   * @throw Exception if channel is in FATAL_ERROR state
+   */
+  public function waitForReady($timeout) {
+    $new_state = $this->getConnectivityState(true);
+    if ($this->_checkConnectivityState($new_state)) {
+      return true;
+    }
+
+    $now = Timeval::now();
+    $delta = new Timeval($timeout);
+    $deadline = $now->add($delta);
+
+    while ($this->channel->watchConnectivityState($new_state, $deadline)) {
+      // state has changed before deadline
+      $new_state = $this->getConnectivityState();
+      if ($this->_checkConnectivityState($new_state)) {
+        return true;
+      }
+    }
+    // deadline has passed
+    $new_state = $this->getConnectivityState();
+    return $this->_checkConnectivityState($new_state);
+  }
+
+  private function _checkConnectivityState($new_state) {
+    if ($new_state == Grpc\CHANNEL_READY) {
+      return true;
+    }
+    if ($new_state == Grpc\CHANNEL_FATAL_ERROR) {
+      throw new Exception('Failed to connect to server');
+    }
+    return false;
+  }
+
+  /**
    * Close the communication channel associated with this stub
    */
   public function close() {
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 27e27cd..4c0cf91 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -153,4 +153,50 @@
   public function testGetTarget() {
     $this->assertTrue(is_string($this->channel->getTarget()));
   }
+
+  public function testGetConnectivityState() {
+    $this->assertTrue($this->channel->getConnectivityState() == Grpc\CHANNEL_IDLE);
+  }
+
+  public function testWatchConnectivityStateFailed() {
+    $idle_state = $this->channel->getConnectivityState(true);
+    $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
+
+    $now = Grpc\Timeval::now();
+    $delta = new Grpc\Timeval(1);
+    $deadline = $now->add($delta);
+
+    $this->assertFalse($this->channel->watchConnectivityState(
+        $idle_state, $deadline));
+  }
+
+  public function testWatchConnectivityStateSuccess() {
+    $idle_state = $this->channel->getConnectivityState(true);
+    $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
+
+    $now = Grpc\Timeval::now();
+    $delta = new Grpc\Timeval(3000000); // should finish well before
+    $deadline = $now->add($delta);
+
+    $this->assertTrue($this->channel->watchConnectivityState(
+        $idle_state, $deadline));
+
+    $new_state = $this->channel->getConnectivityState();
+    $this->assertTrue($idle_state != $new_state);
+  }
+
+  public function testWatchConnectivityStateDoNothing() {
+    $idle_state = $this->channel->getConnectivityState();
+    $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE);
+
+    $now = Grpc\Timeval::now();
+    $delta = new Grpc\Timeval(100000);
+    $deadline = $now->add($delta);
+
+    $this->assertFalse($this->channel->watchConnectivityState(
+        $idle_state, $deadline));
+
+    $new_state = $this->channel->getConnectivityState();
+    $this->assertTrue($new_state == Grpc\CHANNEL_IDLE);
+  }
 }
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h
index 4e0da4a..f646465 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types.h
+++ b/src/python/grpcio/grpc/_adapter/_c/types.h
@@ -113,6 +113,7 @@
 void pygrpc_Call_dealloc(Call *self);
 PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs);
 PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs);
+PyObject *pygrpc_Call_peer(Call *self);
 extern PyTypeObject pygrpc_Call_type;
 
 
@@ -129,6 +130,11 @@
 void pygrpc_Channel_dealloc(Channel *self);
 Call *pygrpc_Channel_create_call(
     Channel *self, PyObject *args, PyObject *kwargs);
+PyObject *pygrpc_Channel_check_connectivity_state(Channel *self, PyObject *args,
+                                                  PyObject *kwargs);
+PyObject *pygrpc_Channel_watch_connectivity_state(Channel *self, PyObject *args,
+                                                  PyObject *kwargs);
+PyObject *pygrpc_Channel_target(Channel *self);
 extern PyTypeObject pygrpc_Channel_type;
 
 
@@ -181,6 +187,9 @@
 /* Construct a tag associated with a server shutdown. */
 pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag);
 
+/* Construct a tag associated with a channel state change. */
+pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag);
+
 /* Frees all resources owned by the tag and the tag itself. */
 void pygrpc_discard_tag(pygrpc_tag *tag);
 
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c
index 0739070..42a5015 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/call.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/call.c
@@ -42,6 +42,7 @@
 PyMethodDef pygrpc_Call_methods[] = {
     {"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""},
     {"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""},
+    {"peer", (PyCFunction)pygrpc_Call_peer, METH_NOARGS, ""},
     {NULL}
 };
 const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call.";
@@ -131,7 +132,7 @@
     }
   }
   tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops);
-  errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag);
+  errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag, NULL);
   gpr_free(ops);
   return PyInt_FromLong(errcode);
 }
@@ -151,13 +152,20 @@
       return NULL;
     }
     code = PyInt_AsLong(py_code);
-    errcode = grpc_call_cancel_with_status(self->c_call, code, details);
+    errcode = grpc_call_cancel_with_status(self->c_call, code, details, NULL);
   } else if (py_code != NULL || details != NULL) {
     PyErr_SetString(PyExc_ValueError,
                     "if `code` is specified, so must `details`");
     return NULL;
   } else {
-    errcode = grpc_call_cancel(self->c_call);
+    errcode = grpc_call_cancel(self->c_call, NULL);
   }
   return PyInt_FromLong(errcode);
 }
+
+PyObject *pygrpc_Call_peer(Call *self) {
+  char *peer = grpc_call_get_peer(self->c_call);
+  PyObject *py_peer = PyString_FromString(peer);
+  gpr_free(peer);
+  return py_peer;
+}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
index 9631047..c577ac0 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
@@ -36,10 +36,14 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
 
 
 PyMethodDef pygrpc_Channel_methods[] = {
     {"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""},
+    {"check_connectivity_state", (PyCFunction)pygrpc_Channel_check_connectivity_state, METH_KEYWORDS, ""},
+    {"watch_connectivity_state", (PyCFunction)pygrpc_Channel_watch_connectivity_state, METH_KEYWORDS, ""},
+    {"target", (PyCFunction)pygrpc_Channel_target, METH_NOARGS, ""},
     {NULL}
 };
 const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel.";
@@ -104,7 +108,7 @@
   if (creds) {
     self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args);
   } else {
-    self->c_chan = grpc_insecure_channel_create(target, &c_args);
+    self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL);
   }
   pygrpc_discard_channel_args(c_args);
   return self;
@@ -122,13 +126,61 @@
   const char *host;
   double deadline;
   char *keywords[] = {"cq", "method", "host", "deadline", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!ssd:create_call", keywords,
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!szd:create_call", keywords,
         &pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) {
     return NULL;
   }
   call = pygrpc_Call_new_empty(cq);
   call->c_call = grpc_channel_create_call(
       self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host,
-      pygrpc_cast_double_to_gpr_timespec(deadline));
+      pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
   return call;
 }
+
+PyObject *pygrpc_Channel_check_connectivity_state(
+    Channel *self, PyObject *args, PyObject *kwargs) {
+  PyObject *py_try_to_connect;
+  int try_to_connect;
+  char *keywords[] = {"try_to_connect", NULL};
+  grpc_connectivity_state state;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:connectivity_state", keywords,
+                                   &py_try_to_connect)) {
+    return NULL;
+  }
+  if (!PyBool_Check(py_try_to_connect)) {
+    Py_XDECREF(py_try_to_connect);
+    return NULL;
+  }
+  try_to_connect = Py_True == py_try_to_connect;
+  Py_DECREF(py_try_to_connect);
+  state = grpc_channel_check_connectivity_state(self->c_chan, try_to_connect);
+  return PyInt_FromLong(state);
+}
+
+PyObject *pygrpc_Channel_watch_connectivity_state(
+    Channel *self, PyObject *args, PyObject *kwargs) {
+  PyObject *tag;
+  double deadline;
+  int last_observed_state;
+  CompletionQueue *completion_queue;
+  char *keywords[] = {"last_observed_state", "deadline",
+                      "completion_queue", "tag"};
+  if (!PyArg_ParseTupleAndKeywords(
+      args, kwargs, "idO!O:watch_connectivity_state", keywords,
+      &last_observed_state, &deadline, &pygrpc_CompletionQueue_type,
+      &completion_queue, &tag)) {
+    return NULL;
+  }
+  grpc_channel_watch_connectivity_state(
+      self->c_chan, (grpc_connectivity_state)last_observed_state,
+      pygrpc_cast_double_to_gpr_timespec(deadline), completion_queue->c_cq,
+      pygrpc_produce_channel_state_change_tag(tag));
+  Py_RETURN_NONE;
+}
+
+PyObject *pygrpc_Channel_target(Channel *self) {
+  char *target = grpc_channel_get_target(self->c_chan);
+  PyObject *py_target = PyString_FromString(target);
+  gpr_free(target);
+  return py_target;
+}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
index 2dd44b6..d8bb89c 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
@@ -90,7 +90,7 @@
 CompletionQueue *pygrpc_CompletionQueue_new(
     PyTypeObject *type, PyObject *args, PyObject *kwargs) {
   CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0);
-  self->c_cq = grpc_completion_queue_create();
+  self->c_cq = grpc_completion_queue_create(NULL);
   return self;
 }
 
@@ -111,7 +111,7 @@
   }
   Py_BEGIN_ALLOW_THREADS;
   event = grpc_completion_queue_next(
-      self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline));
+      self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
   Py_END_ALLOW_THREADS;
   transliterated_event = pygrpc_consume_event(event);
   return transliterated_event;
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server.c b/src/python/grpcio/grpc/_adapter/_c/types/server.c
index 2a11d09..15c98f2 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/server.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/server.c
@@ -104,8 +104,8 @@
     return NULL;
   }
   self = (Server *)type->tp_alloc(type, 0);
-  self->c_serv = grpc_server_create(&c_args);
-  grpc_server_register_completion_queue(self->c_serv, cq->c_cq);
+  self->c_serv = grpc_server_create(&c_args, NULL);
+  grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL);
   pygrpc_discard_channel_args(c_args);
   self->cq = cq;
   Py_INCREF(self->cq);
diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c
index 51f3c9b..2eea0e1 100644
--- a/src/python/grpcio/grpc/_adapter/_c/utility.c
+++ b/src/python/grpcio/grpc/_adapter/_c/utility.c
@@ -88,6 +88,19 @@
   return tag;
 }
 
+pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag) {
+  pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
+  tag->user_tag = user_tag;
+  Py_XINCREF(tag->user_tag);
+  tag->call = NULL;
+  tag->ops = NULL;
+  tag->nops = 0;
+  grpc_call_details_init(&tag->request_call_details);
+  grpc_metadata_array_init(&tag->request_metadata);
+  tag->is_new_call = 0;
+  return tag;
+}
+
 void pygrpc_discard_tag(pygrpc_tag *tag) {
   if (!tag) {
     return;
@@ -139,7 +152,7 @@
 }
 
 int pygrpc_produce_op(PyObject *op, grpc_op *result) {
-  static const int OP_TUPLE_SIZE = 5;
+  static const int OP_TUPLE_SIZE = 6;
   static const int STATUS_TUPLE_SIZE = 2;
   static const int TYPE_INDEX = 0;
   static const int INITIAL_METADATA_INDEX = 1;
@@ -148,6 +161,7 @@
   static const int STATUS_INDEX = 4;
   static const int STATUS_CODE_INDEX = 0;
   static const int STATUS_DETAILS_INDEX = 1;
+  static const int WRITE_FLAGS_INDEX = 5;
   int type;
   Py_ssize_t message_size;
   char *message;
@@ -170,7 +184,10 @@
     return 0;
   }
   c_op.op = type;
-  c_op.flags = 0;
+  c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX));
+  if (PyErr_Occurred()) {
+    return 0;
+  }
   switch (type) {
   case GRPC_OP_SEND_INITIAL_METADATA:
     if (!pygrpc_cast_pyseq_to_send_metadata(
diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
index 3c7f0a2..e7bf9dc 100644
--- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py
+++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
@@ -127,7 +127,7 @@
 
   def write(self, message, tag):
     return self._internal.start_batch([
-          _types.OpArgs.send_message(message)
+          _types.OpArgs.send_message(message, 0)
       ], _TagAdapter(tag, Event.Kind.WRITE_ACCEPTED))
 
   def complete(self, tag):
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index 239aac8..147086e 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -75,6 +75,9 @@
     else:
       return self.call.cancel(code, details)
 
+  def peer(self):
+    return self.call.peer()
+
 
 class Channel(_types.Channel):
 
@@ -88,6 +91,17 @@
   def create_call(self, completion_queue, method, host, deadline=None):
     return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline))
 
+  def check_connectivity_state(self, try_to_connect):
+    return self.channel.check_connectivity_state(try_to_connect)
+
+  def watch_connectivity_state(self, last_observed_state, deadline,
+                               completion_queue, tag):
+    self.channel.watch_connectivity_state(
+        last_observed_state, deadline, completion_queue.completion_queue, tag)
+
+  def target(self):
+    return self.channel.target()
+
 
 _NO_TAG = object()
 
diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py
index 5ddb177..5470d2d 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -31,13 +31,12 @@
 import collections
 import enum
 
-# TODO(atash): decide whether or not to move these enums to the _c module to
-# force build errors with upstream changes.
 
 class GrpcChannelArgumentKeys(enum.Enum):
   """Mirrors keys used in grpc_channel_args for GRPC-specific arguments."""
   SSL_TARGET_NAME_OVERRIDE = 'grpc.ssl_target_name_override'
 
+
 @enum.unique
 class CallError(enum.IntEnum):
   """Mirrors grpc_call_error in the C core."""
@@ -53,6 +52,7 @@
   ERROR_INVALID_FLAGS       = 9
   ERROR_INVALID_METADATA    = 10
 
+
 @enum.unique
 class StatusCode(enum.IntEnum):
   """Mirrors grpc_status_code in the C core."""
@@ -74,6 +74,14 @@
   DATA_LOSS           = 15
   UNAUTHENTICATED     = 16
 
+
+@enum.unique
+class OpWriteFlags(enum.IntEnum):
+  """Mirrors defined write-flag constants in the C core."""
+  WRITE_BUFFER_HINT = 1
+  WRITE_NO_COMPRESS = 2
+
+
 @enum.unique
 class OpType(enum.IntEnum):
   """Mirrors grpc_op_type in the C core."""
@@ -86,12 +94,24 @@
   RECV_STATUS_ON_CLIENT   = 6
   RECV_CLOSE_ON_SERVER    = 7
 
+
 @enum.unique
 class EventType(enum.IntEnum):
   """Mirrors grpc_completion_type in the C core."""
-  QUEUE_SHUTDOWN  = 0
-  QUEUE_TIMEOUT   = 1  # if seen on the Python side, something went horridly wrong
-  OP_COMPLETE     = 2
+  QUEUE_SHUTDOWN = 0
+  QUEUE_TIMEOUT  = 1  # if seen on the Python side, something went horridly wrong
+  OP_COMPLETE    = 2
+
+
+@enum.unique
+class ConnectivityState(enum.IntEnum):
+  """Mirrors grpc_connectivity_state in the C core."""
+  IDLE              = 0
+  CONNECTING        = 1
+  READY             = 2
+  TRANSIENT_FAILURE = 3
+  FATAL_FAILURE     = 4
+
 
 class Status(collections.namedtuple(
     'Status', [
@@ -105,6 +125,7 @@
     details (str): ...
   """
 
+
 class CallDetails(collections.namedtuple(
     'CallDetails', [
         'method',
@@ -119,6 +140,7 @@
     deadline (float): ...
   """
 
+
 class OpArgs(collections.namedtuple(
     'OpArgs', [
         'type',
@@ -126,6 +148,7 @@
         'trailing_metadata',
         'message',
         'status',
+        'write_flags',
     ])):
   """Arguments passed into a GRPC operation.
 
@@ -138,39 +161,40 @@
     message (bytes): Only valid if type == OpType.SEND_MESSAGE, else is None.
     status (Status): Only valid if type == OpType.SEND_STATUS_FROM_SERVER, else
       is None.
+    write_flags (int): a bit OR'ing of 0 or more OpWriteFlags values.
   """
 
   @staticmethod
   def send_initial_metadata(initial_metadata):
-    return OpArgs(OpType.SEND_INITIAL_METADATA, initial_metadata, None, None, None)
+    return OpArgs(OpType.SEND_INITIAL_METADATA, initial_metadata, None, None, None, 0)
 
   @staticmethod
-  def send_message(message):
-    return OpArgs(OpType.SEND_MESSAGE, None, None, message, None)
+  def send_message(message, flags):
+    return OpArgs(OpType.SEND_MESSAGE, None, None, message, None, flags)
 
   @staticmethod
   def send_close_from_client():
-    return OpArgs(OpType.SEND_CLOSE_FROM_CLIENT, None, None, None, None)
+    return OpArgs(OpType.SEND_CLOSE_FROM_CLIENT, None, None, None, None, 0)
 
   @staticmethod
   def send_status_from_server(trailing_metadata, status_code, status_details):
-    return OpArgs(OpType.SEND_STATUS_FROM_SERVER, None, trailing_metadata, None, Status(status_code, status_details))
+    return OpArgs(OpType.SEND_STATUS_FROM_SERVER, None, trailing_metadata, None, Status(status_code, status_details), 0)
 
   @staticmethod
   def recv_initial_metadata():
-    return OpArgs(OpType.RECV_INITIAL_METADATA, None, None, None, None);
+    return OpArgs(OpType.RECV_INITIAL_METADATA, None, None, None, None, 0);
 
   @staticmethod
   def recv_message():
-    return OpArgs(OpType.RECV_MESSAGE, None, None, None, None)
+    return OpArgs(OpType.RECV_MESSAGE, None, None, None, None, 0)
 
   @staticmethod
   def recv_status_on_client():
-    return OpArgs(OpType.RECV_STATUS_ON_CLIENT, None, None, None, None)
+    return OpArgs(OpType.RECV_STATUS_ON_CLIENT, None, None, None, None, 0)
 
   @staticmethod
   def recv_close_on_server():
-    return OpArgs(OpType.RECV_CLOSE_ON_SERVER, None, None, None, None)
+    return OpArgs(OpType.RECV_CLOSE_ON_SERVER, None, None, None, None, 0)
 
 
 class OpResult(collections.namedtuple(
@@ -290,6 +314,15 @@
     """
     return CallError.ERROR
 
+  @abc.abstractmethod
+  def peer(self):
+    """Get the peer of this call.
+
+    Returns:
+      str: the peer of this call.
+    """
+    return None
+
 
 class Channel:
   __metaclass__ = abc.ABCMeta
@@ -321,6 +354,40 @@
     """
     return None
 
+  @abc.abstractmethod
+  def check_connectivity_state(self, try_to_connect):
+    """Check and optionally repair the connectivity state of the channel.
+
+    Args:
+      try_to_connect (bool): whether or not to try to connect the channel if
+      disconnected.
+
+    Returns:
+      ConnectivityState: state of the channel at the time of this invocation.
+    """
+    return None
+
+  @abc.abstractmethod
+  def watch_connectivity_state(self, last_observed_state, deadline,
+                               completion_queue, tag):
+    """Watch for connectivity state changes from the last_observed_state.
+
+    Args:
+      last_observed_state (ConnectivityState): ...
+      deadline (float): ...
+      completion_queue (CompletionQueue): ...
+      tag (object) ...
+    """
+
+  @abc.abstractmethod
+  def target(self):
+    """Get the target of this channel.
+
+    Returns:
+      str: the target of this channel.
+    """
+    return None
+
 
 class Server:
   __metaclass__ = abc.ABCMeta
diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index 7783e91..5c636d6 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -44,7 +44,10 @@
 @enum.unique
 class _Read(enum.Enum):
   READING = 'reading'
-  AWAITING_ALLOWANCE = 'awaiting allowance'
+  # TODO(issue 2916): This state will again be necessary after eliminating the
+  # "early_read" field of _RPCState and going back to only reading when granted
+  # allowance to read.
+  # AWAITING_ALLOWANCE = 'awaiting allowance'
   CLOSED = 'closed'
 
 
@@ -67,12 +70,15 @@
 
   def __init__(
       self, request_deserializer, response_serializer, sequence_number, read,
-      allowance, high_write, low_write, premetadataed, terminal_metadata, code,
-      message):
+      early_read, allowance, high_write, low_write, premetadataed,
+      terminal_metadata, code, message):
     self.request_deserializer = request_deserializer
     self.response_serializer = response_serializer
     self.sequence_number = sequence_number
     self.read = read
+    # TODO(issue 2916): Eliminate this by eliminating the necessity of calling
+    # call.read just to advance the RPC.
+    self.early_read = early_read  # A raw (not deserialized) read.
     self.allowance = allowance
     self.high_write = high_write
     self.low_write = low_write
@@ -120,7 +126,7 @@
 
     call.read(call)
     self._rpc_states[call] = _RPCState(
-        request_deserializer, response_serializer, 1, _Read.READING, 0,
+        request_deserializer, response_serializer, 1, _Read.READING, None, 1,
         _HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None)
     ticket = links.Ticket(
         call, 0, group, method, links.Ticket.Subscription.FULL,
@@ -140,12 +146,15 @@
       termination = links.Ticket.Termination.COMPLETION
     else:
       if 0 < rpc_state.allowance:
+        payload = rpc_state.request_deserializer(event.bytes)
+        termination = None
         rpc_state.allowance -= 1
         call.read(call)
       else:
-        rpc_state.read = _Read.AWAITING_ALLOWANCE
-      payload = rpc_state.request_deserializer(event.bytes)
-      termination = None
+        rpc_state.early_read = event.bytes
+        return
+        # TODO(issue 2916): Instead of returning:
+        # rpc_state.read = _Read.AWAITING_ALLOWANCE
     ticket = links.Ticket(
         call, rpc_state.sequence_number, None, None, None, None, None, None,
         payload, None, None, None, termination)
@@ -237,12 +246,22 @@
           rpc_state.premetadataed = True
 
       if ticket.allowance is not None:
-        if rpc_state.read is _Read.AWAITING_ALLOWANCE:
-          rpc_state.allowance += ticket.allowance - 1
-          call.read(call)
-          rpc_state.read = _Read.READING
-        else:
+        if rpc_state.early_read is None:
           rpc_state.allowance += ticket.allowance
+        else:
+          payload = rpc_state.request_deserializer(rpc_state.early_read)
+          rpc_state.allowance += ticket.allowance - 1
+          rpc_state.early_read = None
+          if rpc_state.read is _Read.READING:
+            call.read(call)
+            termination = None
+          else:
+            termination = links.Ticket.Termination.COMPLETION
+          ticket = links.Ticket(
+              call, rpc_state.sequence_number, None, None, None, None, None,
+              None, payload, None, None, None, termination)
+          rpc_state.sequence_number += 1
+          self._relay.add_value(ticket)
 
       if ticket.payload is not None:
         call.write(rpc_state.response_serializer(ticket.payload), call)
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/python/grpcio/grpc/framework/interfaces/base/__init__.py
similarity index 83%
copy from src/ruby/bin/interop/test/cpp/interop/test.rb
copy to src/python/grpcio/grpc/framework/interfaces/base/__init__.py
index 5948b50..7086519 100644
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/python/grpcio/grpc/framework/interfaces/base/__init__.py
@@ -27,17 +27,4 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
 
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py
new file mode 100644
index 0000000..9d1651d
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py
@@ -0,0 +1,273 @@
+# Copyright 2015, 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.
+
+"""The base interface of RPC Framework."""
+
+import abc
+import enum
+
+# abandonment is referenced from specification in this module.
+from grpc.framework.foundation import abandonment  # pylint: disable=unused-import
+
+
+class NoSuchMethodError(Exception):
+  """Indicates that an unrecognized operation has been called."""
+
+
+@enum.unique
+class Outcome(enum.Enum):
+  """Operation outcomes."""
+
+  COMPLETED = 'completed'
+  CANCELLED = 'cancelled'
+  EXPIRED = 'expired'
+  LOCAL_SHUTDOWN = 'local shutdown'
+  REMOTE_SHUTDOWN = 'remote shutdown'
+  RECEPTION_FAILURE = 'reception failure'
+  TRANSMISSION_FAILURE = 'transmission failure'
+  LOCAL_FAILURE = 'local failure'
+  REMOTE_FAILURE = 'remote failure'
+
+
+class Completion(object):
+  """An aggregate of the values exchanged upon operation completion.
+
+  Attributes:
+    terminal_metadata: A terminal metadata value for the operaton.
+    code: A code value for the operation.
+    message: A message value for the operation.
+  """
+  __metaclass__ = abc.ABCMeta
+
+
+class OperationContext(object):
+  """Provides operation-related information and action."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def outcome(self):
+    """Indicates the operation's outcome (or that the operation is ongoing).
+
+    Returns:
+      None if the operation is still active or the Outcome value for the
+        operation if it has terminated.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def add_termination_callback(self, callback):
+    """Adds a function to be called upon operation termination.
+
+    Args:
+      callback: A callable to be passed an Outcome value on operation
+        termination.
+
+    Returns:
+      None if the operation has not yet terminated and the passed callback will
+        later be called when it does terminate, or if the operation has already
+        terminated an Outcome value describing the operation termination and the
+        passed callback will not be called as a result of this method call.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def time_remaining(self):
+    """Describes the length of allowed time remaining for the operation.
+
+    Returns:
+      A nonnegative float indicating the length of allowed time in seconds
+      remaining for the operation to complete before it is considered to have
+      timed out. Zero is returned if the operation has terminated.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def cancel(self):
+    """Cancels the operation if the operation has not yet terminated."""
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def fail(self, exception):
+    """Indicates that the operation has failed.
+
+    Args:
+      exception: An exception germane to the operation failure. May be None.
+    """
+    raise NotImplementedError()
+
+
+class Operator(object):
+  """An interface through which to participate in an operation."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def advance(
+      self, initial_metadata=None, payload=None, completion=None,
+      allowance=None):
+    """Progresses the operation.
+
+    Args:
+      initial_metadata: An initial metadata value. Only one may ever be
+        communicated in each direction for an operation, and they must be
+        communicated no later than either the first payload or the completion.
+      payload: A payload value.
+      completion: A Completion value. May only ever be non-None once in either
+        direction, and no payloads may be passed after it has been communicated.
+      allowance: A positive integer communicating the number of additional
+        payloads allowed to be passed by the remote side of the operation.
+    """
+    raise NotImplementedError()
+
+
+class Subscription(object):
+  """Describes customer code's interest in values from the other side.
+
+  Attributes:
+    kind: A Kind value describing the overall kind of this value.
+    termination_callback: A callable to be passed the Outcome associated with
+      the operation after it has terminated. Must be non-None if kind is
+      Kind.TERMINATION_ONLY. Must be None otherwise.
+    allowance: A callable behavior that accepts positive integers representing
+      the number of additional payloads allowed to be passed to the other side
+      of the operation. Must be None if kind is Kind.FULL. Must not be None
+      otherwise.
+    operator: An Operator to be passed values from the other side of the
+      operation. Must be non-None if kind is Kind.FULL. Must be None otherwise.
+  """
+
+  @enum.unique
+  class Kind(enum.Enum):
+
+    NONE = 'none'
+    TERMINATION_ONLY = 'termination only'
+    FULL = 'full'
+
+
+class Servicer(object):
+  """Interface for service implementations."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def service(self, group, method, context, output_operator):
+    """Services an operation.
+
+    Args:
+      group: The group identifier of the operation to be serviced.
+      method: The method identifier of the operation to be serviced.
+      context: An OperationContext object affording contextual information and
+        actions.
+      output_operator: An Operator that will accept output values of the
+        operation.
+
+    Returns:
+      A Subscription via which this object may or may not accept more values of
+        the operation.
+
+    Raises:
+      NoSuchMethodError: If this Servicer does not handle operations with the
+        given group and method.
+      abandonment.Abandoned: If the operation has been aborted and there no
+        longer is any reason to service the operation.
+    """
+    raise NotImplementedError()
+
+
+class End(object):
+  """Common type for entry-point objects on both sides of an operation."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def start(self):
+    """Starts this object's service of operations."""
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop_gracefully(self):
+    """Gracefully stops this object's service of operations.
+
+    Operations in progress will be allowed to complete, and this method blocks
+    until all of them have.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop_immediately(self):
+    """Immediately stops this object's service of operations.
+
+    Operations in progress will not be allowed to complete.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def operate(
+      self, group, method, subscription, timeout, initial_metadata=None,
+      payload=None, completion=None):
+    """Commences an operation.
+
+    Args:
+      group: The group identifier of the invoked operation.
+      method: The method identifier of the invoked operation.
+      subscription: A Subscription to which the results of the operation will be
+        passed.
+      timeout: A length of time in seconds to allow for the operation.
+      initial_metadata: An initial metadata value to be sent to the other side
+        of the operation. May be None if the initial metadata will be later
+        passed via the returned operator or if there will be no initial metadata
+        passed at all.
+      payload: An initial payload for the operation.
+      completion: A Completion value indicating the end of transmission to the
+        other side of the operation.
+
+    Returns:
+      A pair of objects affording information about the operation and action
+        continuing the operation. The first element of the returned pair is an
+        OperationContext for the operation and the second element of the
+        returned pair is an Operator to which operation values not passed in
+        this call should later be passed.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def operation_stats(self):
+    """Reports the number of terminated operations broken down by outcome.
+
+    Returns:
+      A dictionary from Outcome value to an integer identifying the number
+        of operations that terminated with that outcome.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def add_idle_action(self, action):
+    """Adds an action to be called when this End has no ongoing operations.
+
+    Args:
+      action: A callable that accepts no arguments.
+    """
+    raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/utilities.py b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
new file mode 100644
index 0000000..a9ee1a0
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
@@ -0,0 +1,79 @@
+# Copyright 2015, 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.
+
+"""Utilities for use with the base interface of RPC Framework."""
+
+import collections
+
+from grpc.framework.interfaces.base import base
+
+
+class _Completion(
+    base.Completion,
+    collections.namedtuple(
+        '_Completion', ('terminal_metadata', 'code', 'message',))):
+  """A trivial implementation of base.Completion."""
+
+
+class _Subscription(
+    base.Subscription,
+    collections.namedtuple(
+        '_Subscription',
+        ('kind', 'termination_callback', 'allowance', 'operator',))):
+  """A trivial implementation of base.Subscription."""
+
+_NONE_SUBSCRIPTION = _Subscription(
+    base.Subscription.Kind.NONE, None, None, None)
+
+
+def completion(terminal_metadata, code, message):
+  """Creates a base.Completion aggregating the given operation values.
+
+  Args:
+    terminal_metadata: A terminal metadata value for an operaton.
+    code: A code value for an operation.
+    message: A message value for an operation.
+
+  Returns:
+    A base.Completion aggregating the given operation values.
+  """
+  return _Completion(terminal_metadata, code, message)
+
+
+def full_subscription(operator):
+  """Creates a "full" base.Subscription for the given base.Operator.
+
+  Args:
+    operator: A base.Operator to be used in an operation.
+
+  Returns:
+    A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given
+      base.Operator.
+  """
+  return _Subscription(base.Subscription.Kind.FULL, None, None, operator)
diff --git a/src/python/grpcio_health_checking/MANIFEST.in b/src/python/grpcio_health_checking/MANIFEST.in
new file mode 100644
index 0000000..498b55f
--- /dev/null
+++ b/src/python/grpcio_health_checking/MANIFEST.in
@@ -0,0 +1,2 @@
+graft grpc
+include commands.py
diff --git a/src/python/grpcio_health_checking/README.rst b/src/python/grpcio_health_checking/README.rst
new file mode 100644
index 0000000..600734e
--- /dev/null
+++ b/src/python/grpcio_health_checking/README.rst
@@ -0,0 +1,9 @@
+gRPC Python Health Checking
+===========================
+
+Reference package for GRPC Python health checking.
+
+Dependencies
+------------
+
+Depends on the `grpcio` package, available from PyPI via `pip install grpcio`.
diff --git a/src/python/grpcio_health_checking/commands.py b/src/python/grpcio_health_checking/commands.py
new file mode 100644
index 0000000..6a95e67
--- /dev/null
+++ b/src/python/grpcio_health_checking/commands.py
@@ -0,0 +1,80 @@
+# Copyright 2015, 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.
+
+"""Provides distutils command classes for the GRPC Python setup process."""
+
+import distutils
+import glob
+import os
+import os.path
+import subprocess
+import sys
+
+import setuptools
+from setuptools.command import build_py
+
+
+class BuildProtoModules(setuptools.Command):
+  """Command to generate project *_pb2.py modules from proto files."""
+
+  description = ''
+  user_options = []
+
+  def initialize_options(self):
+    pass
+
+  def finalize_options(self):
+    self.protoc_command = 'protoc'
+    self.grpc_python_plugin_command = distutils.spawn.find_executable(
+        'grpc_python_plugin')
+
+  def run(self):
+    paths = []
+    root_directory = os.getcwd()
+    for walk_root, directories, filenames in os.walk(root_directory):
+      for filename in filenames:
+        if filename.endswith('.proto'):
+          paths.append(os.path.join(walk_root, filename))
+    command = [
+        self.protoc_command,
+        '--plugin=protoc-gen-python-grpc={}'.format(
+            self.grpc_python_plugin_command),
+        '-I {}'.format(root_directory),
+        '--python_out={}'.format(root_directory),
+        '--python-grpc_out={}'.format(root_directory),
+    ] + paths
+    subprocess.check_call(' '.join(command), cwd=root_directory, shell=True)
+
+
+class BuildPy(build_py.build_py):
+  """Custom project build command."""
+
+  def run(self):
+    self.run_command('build_proto_modules')
+    build_py.build_py.run(self)
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/python/grpcio_health_checking/grpc/__init__.py
similarity index 83%
copy from src/ruby/bin/interop/test/cpp/interop/test.rb
copy to src/python/grpcio_health_checking/grpc/__init__.py
index 5948b50..7086519 100644
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/python/grpcio_health_checking/grpc/__init__.py
@@ -27,17 +27,4 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
 
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/python/grpcio_health_checking/grpc/health/__init__.py
similarity index 83%
copy from src/ruby/bin/interop/test/cpp/interop/test.rb
copy to src/python/grpcio_health_checking/grpc/health/__init__.py
index 5948b50..7086519 100644
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/python/grpcio_health_checking/grpc/health/__init__.py
@@ -27,17 +27,4 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
 
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/python/grpcio_health_checking/grpc/health/v1alpha/__init__.py
similarity index 83%
copy from src/ruby/bin/interop/test/cpp/interop/test.rb
copy to src/python/grpcio_health_checking/grpc/health/v1alpha/__init__.py
index 5948b50..7086519 100644
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/python/grpcio_health_checking/grpc/health/v1alpha/__init__.py
@@ -27,17 +27,4 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
 
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
diff --git a/src/python/grpcio_health_checking/grpc/health/v1alpha/health.proto b/src/python/grpcio_health_checking/grpc/health/v1alpha/health.proto
new file mode 100644
index 0000000..57f4aaa
--- /dev/null
+++ b/src/python/grpcio_health_checking/grpc/health/v1alpha/health.proto
@@ -0,0 +1,49 @@
+// Copyright 2015, 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.
+
+syntax = "proto3";
+
+package grpc.health.v1alpha;
+
+message HealthCheckRequest {
+  string service = 1;
+}
+
+message HealthCheckResponse {
+  enum ServingStatus {
+    UNKNOWN = 0;
+    SERVING = 1;
+    NOT_SERVING = 2;
+  }
+  ServingStatus status = 1;
+}
+
+service Health {
+  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
diff --git a/src/python/grpcio_health_checking/grpc/health/v1alpha/health.py b/src/python/grpcio_health_checking/grpc/health/v1alpha/health.py
new file mode 100644
index 0000000..9dfcd96
--- /dev/null
+++ b/src/python/grpcio_health_checking/grpc/health/v1alpha/health.py
@@ -0,0 +1,129 @@
+# Copyright 2015, 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.
+
+"""Reference implementation for health checking in gRPC Python."""
+
+import abc
+import enum
+import threading
+
+from grpc.health.v1alpha import health_pb2
+
+
+@enum.unique
+class HealthStatus(enum.Enum):
+  """Statuses for a service mirroring the reference health.proto's values."""
+  UNKNOWN = health_pb2.HealthCheckResponse.UNKNOWN
+  SERVING = health_pb2.HealthCheckResponse.SERVING
+  NOT_SERVING = health_pb2.HealthCheckResponse.NOT_SERVING
+
+
+class _HealthServicer(health_pb2.EarlyAdopterHealthServicer):
+  """Servicer handling RPCs for service statuses."""
+
+  def __init__(self):
+    self._server_status_lock = threading.Lock()
+    self._server_status = {}
+
+  def Check(self, request, context):
+    with self._server_status_lock:
+      if request.service not in self._server_status:
+        # TODO(atash): once the Python API has a way of setting the server
+        # status, bring us into conformance with the health check spec by
+        # returning the NOT_FOUND status here.
+        raise NotImplementedError()
+      else:
+        return health_pb2.HealthCheckResponse(
+            status=self._server_status[request.service].value)
+
+  def set(service, status):
+    if not isinstance(status, HealthStatus):
+      raise TypeError('expected grpc.health.v1alpha.health.HealthStatus '
+                      'for argument `status` but got {}'.format(status))
+    with self._server_status_lock:
+      self._server_status[service] = status
+
+
+class HealthServer(health_pb2.EarlyAdopterHealthServer):
+  """Interface for the reference gRPC Python health server."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def start(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def set(self, service, status):
+    """Set the status of the given service.
+
+    Args:
+      service (str): service name of the service to set the reported status of
+      status (HealthStatus): status to set for the specified service
+    """
+    raise NotImplementedError()
+
+
+class _HealthServerImplementation(HealthServer):
+  """Implementation for the reference gRPC Python health server."""
+
+  def __init__(self, server, servicer):
+    self._server = server
+    self._servicer = servicer
+
+  def start(self):
+    self._server.start()
+
+  def stop(self):
+    self._server.stop()
+
+  def set(self, service, status):
+    self._servicer.set(service, status)
+
+
+def create_Health_server(port, private_key=None, certificate_chain=None):
+  """Get a HealthServer instance.
+
+  Args:
+    port (int): port number passed through to health_pb2 server creation
+      routine.
+    private_key (str): to-be-created server's desired private key
+    certificate_chain (str): to-be-created server's desired certificate chain
+
+  Returns:
+    An instance of HealthServer (conforming thus to
+    EarlyAdopterHealthServer and providing a method to set server status)."""
+  servicer = _HealthServicer()
+  server = health_pb2.early_adopter_create_Health_server(
+      servicer, port=port, private_key=private_key,
+      certificate_chain=certificate_chain)
+  return _HealthServerImplementation(server, servicer)
diff --git a/src/ruby/bin/interop/test/cpp/interop/empty.rb b/src/python/grpcio_health_checking/setup.py
similarity index 61%
rename from src/ruby/bin/interop/test/cpp/interop/empty.rb
rename to src/python/grpcio_health_checking/setup.py
index 3579fa5..fcde0da 100644
--- a/src/ruby/bin/interop/test/cpp/interop/empty.rb
+++ b/src/python/grpcio_health_checking/setup.py
@@ -27,18 +27,46 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/empty.proto
+"""Setup module for the GRPC Python package's optional health checking."""
 
-require 'google/protobuf'
+import os
+import os.path
+import sys
 
-Google::Protobuf::DescriptorPool.generated_pool.build do
-  add_message "grpc.testing.Empty" do
-  end
-end
+from distutils import core as _core
+import setuptools
 
-module Grpc
-  module Testing
-    Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass
-  end
-end
+# Ensure we're in the proper directory whether or not we're being used by pip.
+os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+# Break import-style to ensure we can actually find our commands module.
+import commands
+
+_PACKAGES = (
+    setuptools.find_packages('.')
+)
+
+_PACKAGE_DIRECTORIES = {
+    '': '.',
+}
+
+_INSTALL_REQUIRES = (
+    'grpcio>=0.10.0a0',
+)
+
+_SETUP_REQUIRES = _INSTALL_REQUIRES
+
+_COMMAND_CLASS = {
+    'build_proto_modules': commands.BuildProtoModules,
+    'build_py': commands.BuildPy,
+}
+
+setuptools.setup(
+    name='grpcio_health_checking',
+    version='0.10.0a0',
+    packages=list(_PACKAGES),
+    package_dir=_PACKAGE_DIRECTORIES,
+    install_requires=_INSTALL_REQUIRES,
+    setup_requires=_SETUP_REQUIRES,
+    cmdclass=_COMMAND_CLASS
+)
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py b/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
index b658366..44fe760 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
+++ b/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
@@ -117,7 +117,7 @@
     client_initial_metadata = [(CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE), (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)]
     client_start_batch_result = client_call.start_batch([
         _types.OpArgs.send_initial_metadata(client_initial_metadata),
-        _types.OpArgs.send_message(REQUEST),
+        _types.OpArgs.send_message(REQUEST, 0),
         _types.OpArgs.send_close_from_client(),
         _types.OpArgs.recv_initial_metadata(),
         _types.OpArgs.recv_message(),
@@ -144,6 +144,15 @@
     self.assertEquals(HOST, request_event.call_details.host)
     self.assertLess(abs(DEADLINE - request_event.call_details.deadline), DEADLINE_TOLERANCE)
 
+    # Check that the channel is connected, and that both it and the call have
+    # the proper target and peer; do this after the first flurry of messages to
+    # avoid the possibility that connection was delayed by the core until the
+    # first message was sent.
+    self.assertEqual(_types.ConnectivityState.READY,
+                     self.client_channel.check_connectivity_state(False))
+    self.assertIsNotNone(self.client_channel.target())
+    self.assertIsNotNone(client_call.peer())
+
     server_call_tag = object()
     server_call = request_event.call
     server_initial_metadata = [(SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]
@@ -151,7 +160,7 @@
     server_start_batch_result = server_call.start_batch([
         _types.OpArgs.send_initial_metadata(server_initial_metadata),
         _types.OpArgs.recv_message(),
-        _types.OpArgs.send_message(RESPONSE),
+        _types.OpArgs.send_message(RESPONSE, 0),
         _types.OpArgs.recv_close_on_server(),
         _types.OpArgs.send_status_from_server(server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
     ], server_call_tag)
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py b/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
index 26ca035..1e575d1 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
@@ -303,16 +303,9 @@
         invocation_message, links.Ticket.Termination.COMPLETION)
     self._invocation_link.accept_ticket(original_invocation_ticket)
 
-    # TODO(nathaniel): This shouldn't be necessary. Detecting the end of the
-    # invocation-side ticket sequence shouldn't require granting allowance for
-    # another payload.
     self._service_mate.block_until_tickets_satisfy(
         at_least_n_payloads_received_predicate(1))
     service_operation_id = self._service_mate.tickets()[0].operation_id
-    self._service_link.accept_ticket(
-        links.Ticket(
-            service_operation_id, 0, None, None, links.Ticket.Subscription.FULL,
-            None, 1, None, None, None, None, None, None))
 
     self._service_mate.block_until_tickets_satisfy(terminated)
     self._assert_is_valid_invocation_sequence(
@@ -321,7 +314,7 @@
         invocation_terminal_metadata, links.Ticket.Termination.COMPLETION)
 
     original_service_ticket = links.Ticket(
-        service_operation_id, 1, None, None, links.Ticket.Subscription.FULL,
+        service_operation_id, 0, None, None, links.Ticket.Subscription.FULL,
         timeout, 0, service_initial_metadata, service_payload,
         service_terminal_metadata, service_code, service_message,
         links.Ticket.Termination.COMPLETION)
diff --git a/src/ruby/.rspec b/src/ruby/.rspec
index cd7c5fb..2320752 100755
--- a/src/ruby/.rspec
+++ b/src/ruby/.rspec
@@ -1,4 +1,5 @@
 -I.
+-Ipb
 --require spec_helper
 --format documentation
 --color
diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml
index 47e382a..312bdca 100644
--- a/src/ruby/.rubocop.yml
+++ b/src/ruby/.rubocop.yml
@@ -5,6 +5,7 @@
 AllCops:
   Exclude:
     - 'bin/apis/**/*'
-    - 'bin/interop/test/**/*'
     - 'bin/math.rb'
     - 'bin/math_services.rb'
+    - 'pb/grpc/health/v1alpha/*'
+    - 'pb/test/**/*'
diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile
index 02af9a8..cc7832b 100755
--- a/src/ruby/Rakefile
+++ b/src/ruby/Rakefile
@@ -20,7 +20,8 @@
   { id: :bidi, title: 'bidi tests', dir: %w(spec/generic),
     tag: 'bidi' },
   { id: :server, title: 'rpc server thread tests', dir: %w(spec/generic),
-    tag: 'server' }
+    tag: 'server' },
+  { id: :pb, title: 'protobuf service tests', dir: %w(spec/pb) }
 ]
 namespace :suite do
   SPEC_SUITES.each do |suite|
@@ -50,7 +51,8 @@
 task 'suite:idiomatic' => 'suite:wrapper'
 task 'suite:bidi' => 'suite:wrapper'
 task 'suite:server' => 'suite:wrapper'
+task 'suite:pb' => 'suite:server'
 
 desc 'Compiles the gRPC extension then runs all the tests'
-task all: ['suite:idiomatic', 'suite:bidi', 'suite:server']
+task all: ['suite:idiomatic', 'suite:bidi', 'suite:pb', 'suite:server']
 task default: :all
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/ruby/bin/grpc_ruby_interop_client
old mode 100644
new mode 100755
similarity index 83%
copy from src/ruby/bin/interop/test/cpp/interop/test.rb
copy to src/ruby/bin/grpc_ruby_interop_client
index 5948b50..e79fd33
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/ruby/bin/grpc_ruby_interop_client
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -27,17 +29,5 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
-
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
+# Provides a gem binary entry point for the interop client.
+require 'test/client'
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/ruby/bin/grpc_ruby_interop_server
old mode 100644
new mode 100755
similarity index 83%
rename from src/ruby/bin/interop/test/cpp/interop/test.rb
rename to src/ruby/bin/grpc_ruby_interop_server
index 5948b50..656a5f7
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/src/ruby/bin/grpc_ruby_interop_server
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -27,17 +29,5 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
-
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
+# Provides a gem binary entry point for the interop server
+require 'test/server'
diff --git a/src/ruby/bin/interop/README.md b/src/ruby/bin/interop/README.md
deleted file mode 100644
index 84fc663..0000000
--- a/src/ruby/bin/interop/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Interop test protos
-===================
-
-These ruby classes were generated with protoc v3, using grpc's ruby compiler
-plugin.
-
-- As of 2015/01 protoc v3 is available in the
-[google-protobuf](https://github.com/google/protobuf) repo
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
index da4caa8..239083f 100755
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/bin/interop/interop_client.rb
@@ -29,6 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+# #######################################################################
+# DEPRECATED: The behaviour in this file has been moved to pb/test/client.rb
+#
+# This file remains to support existing tools and scripts that use it.
+# ######################################################################
+#
 # interop_client is a testing tool that accesses a gRPC interop testing
 # server and runs a test on it.
 #
@@ -39,339 +45,7 @@
 #                                    --test_case=<testcase_name>
 
 this_dir = File.expand_path(File.dirname(__FILE__))
-lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
-$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
-$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
 
-require 'optparse'
-require 'minitest'
-require 'minitest/assertions'
-
-require 'grpc'
-require 'googleauth'
-require 'google/protobuf'
-
-require 'test/cpp/interop/test_services'
-require 'test/cpp/interop/messages'
-require 'test/cpp/interop/empty'
-
-require 'signet/ssl_config'
-
-AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
-
-# loads the certificates used to access the test server securely.
-def load_test_certs
-  this_dir = File.expand_path(File.dirname(__FILE__))
-  data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
-  files = ['ca.pem', 'server1.key', 'server1.pem']
-  files.map { |f| File.open(File.join(data_dir, f)).read }
-end
-
-# loads the certificates used to access the test server securely.
-def load_prod_cert
-  fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
-  GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
-  File.open(ENV['SSL_CERT_FILE']).read
-end
-
-# creates SSL Credentials from the test certificates.
-def test_creds
-  certs = load_test_certs
-  GRPC::Core::Credentials.new(certs[0])
-end
-
-# creates SSL Credentials from the production certificates.
-def prod_creds
-  cert_text = load_prod_cert
-  GRPC::Core::Credentials.new(cert_text)
-end
-
-# creates the SSL Credentials.
-def ssl_creds(use_test_ca)
-  return test_creds if use_test_ca
-  prod_creds
-end
-
-# creates a test stub that accesses host:port securely.
-def create_stub(opts)
-  address = "#{opts.host}:#{opts.port}"
-  if opts.secure
-    stub_opts = {
-      :creds => ssl_creds(opts.use_test_ca),
-      GRPC::Core::Channel::SSL_TARGET => opts.host_override
-    }
-
-    # Add service account creds if specified
-    wants_creds = %w(all compute_engine_creds service_account_creds)
-    if wants_creds.include?(opts.test_case)
-      unless opts.oauth_scope.nil?
-        auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
-        stub_opts[:update_metadata] = auth_creds.updater_proc
-      end
-    end
-
-    if opts.test_case == 'jwt_token_creds'  # don't use a scope
-      auth_creds = Google::Auth.get_application_default
-      stub_opts[:update_metadata] = auth_creds.updater_proc
-    end
-
-    GRPC.logger.info("... connecting securely to #{address}")
-    Grpc::Testing::TestService::Stub.new(address, **stub_opts)
-  else
-    GRPC.logger.info("... connecting insecurely to #{address}")
-    Grpc::Testing::TestService::Stub.new(address)
-  end
-end
-
-# produces a string of null chars (\0) of length l.
-def nulls(l)
-  fail 'requires #{l} to be +ve' if l < 0
-  [].pack('x' * l).force_encoding('utf-8')
-end
-
-# a PingPongPlayer implements the ping pong bidi test.
-class PingPongPlayer
-  include Minitest::Assertions
-  include Grpc::Testing
-  include Grpc::Testing::PayloadType
-  attr_accessor :assertions # required by Minitest::Assertions
-  attr_accessor :queue
-  attr_accessor :canceller_op
-
-  # reqs is the enumerator over the requests
-  def initialize(msg_sizes)
-    @queue = Queue.new
-    @msg_sizes = msg_sizes
-    @assertions = 0  # required by Minitest::Assertions
-    @canceller_op = nil  # used to cancel after the first response
-  end
-
-  def each_item
-    return enum_for(:each_item) unless block_given?
-    req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters  # short
-    count = 0
-    @msg_sizes.each do |m|
-      req_size, resp_size = m
-      req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
-                        response_type: :COMPRESSABLE,
-                        response_parameters: [p_cls.new(size: resp_size)])
-      yield req
-      resp = @queue.pop
-      assert_equal(:COMPRESSABLE, resp.payload.type, 'payload type is wrong')
-      assert_equal(resp_size, resp.payload.body.length,
-                   "payload body #{count} has the wrong length")
-      p "OK: ping_pong #{count}"
-      count += 1
-      unless @canceller_op.nil?
-        canceller_op.cancel
-        break
-      end
-    end
-  end
-end
-
-# defines methods corresponding to each interop test case.
-class NamedTests
-  include Minitest::Assertions
-  include Grpc::Testing
-  include Grpc::Testing::PayloadType
-  attr_accessor :assertions # required by Minitest::Assertions
-
-  def initialize(stub, args)
-    @assertions = 0  # required by Minitest::Assertions
-    @stub = stub
-    @args = args
-  end
-
-  def empty_unary
-    resp = @stub.empty_call(Empty.new)
-    assert resp.is_a?(Empty), 'empty_unary: invalid response'
-    p 'OK: empty_unary'
-  end
-
-  def large_unary
-    perform_large_unary
-    p 'OK: large_unary'
-  end
-
-  def service_account_creds
-    # ignore this test if the oauth options are not set
-    if @args.oauth_scope.nil?
-      p 'NOT RUN: service_account_creds; no service_account settings'
-      return
-    end
-    json_key = File.read(ENV[AUTH_ENV])
-    wanted_email = MultiJson.load(json_key)['client_email']
-    resp = perform_large_unary(fill_username: true,
-                               fill_oauth_scope: true)
-    assert_equal(wanted_email, resp.username,
-                 'service_account_creds: incorrect username')
-    assert(@args.oauth_scope.include?(resp.oauth_scope),
-           'service_account_creds: incorrect oauth_scope')
-    p 'OK: service_account_creds'
-  end
-
-  def jwt_token_creds
-    json_key = File.read(ENV[AUTH_ENV])
-    wanted_email = MultiJson.load(json_key)['client_email']
-    resp = perform_large_unary(fill_username: true)
-    assert_equal(wanted_email, resp.username,
-                 'service_account_creds: incorrect username')
-    p 'OK: jwt_token_creds'
-  end
-
-  def compute_engine_creds
-    resp = perform_large_unary(fill_username: true,
-                               fill_oauth_scope: true)
-    assert_equal(@args.default_service_account, resp.username,
-                 'compute_engine_creds: incorrect username')
-    p 'OK: compute_engine_creds'
-  end
-
-  def client_streaming
-    msg_sizes = [27_182, 8, 1828, 45_904]
-    wanted_aggregate_size = 74_922
-    reqs = msg_sizes.map do |x|
-      req = Payload.new(body: nulls(x))
-      StreamingInputCallRequest.new(payload: req)
-    end
-    resp = @stub.streaming_input_call(reqs)
-    assert_equal(wanted_aggregate_size, resp.aggregated_payload_size,
-                 'client_streaming: aggregate payload size is incorrect')
-    p 'OK: client_streaming'
-  end
-
-  def server_streaming
-    msg_sizes = [31_415, 9, 2653, 58_979]
-    response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
-    req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
-                                         response_parameters: response_spec)
-    resps = @stub.streaming_output_call(req)
-    resps.each_with_index do |r, i|
-      assert i < msg_sizes.length, 'too many responses'
-      assert_equal(:COMPRESSABLE, r.payload.type,
-                   'payload type is wrong')
-      assert_equal(msg_sizes[i], r.payload.body.length,
-                   'payload body #{i} has the wrong length')
-    end
-    p 'OK: server_streaming'
-  end
-
-  def ping_pong
-    msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
-    ppp = PingPongPlayer.new(msg_sizes)
-    resps = @stub.full_duplex_call(ppp.each_item)
-    resps.each { |r| ppp.queue.push(r) }
-    p 'OK: ping_pong'
-  end
-
-  def cancel_after_begin
-    msg_sizes = [27_182, 8, 1828, 45_904]
-    reqs = msg_sizes.map do |x|
-      req = Payload.new(body: nulls(x))
-      StreamingInputCallRequest.new(payload: req)
-    end
-    op = @stub.streaming_input_call(reqs, return_op: true)
-    op.cancel
-    assert_raises(GRPC::Cancelled) { op.execute }
-    assert(op.cancelled, 'call operation should be CANCELLED')
-    p 'OK: cancel_after_begin'
-  end
-
-  def cancel_after_first_response
-    msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
-    ppp = PingPongPlayer.new(msg_sizes)
-    op = @stub.full_duplex_call(ppp.each_item, return_op: true)
-    ppp.canceller_op = op  # causes ppp to cancel after the 1st message
-    op.execute.each { |r| ppp.queue.push(r) }
-    op.wait
-    assert(op.cancelled, 'call operation was not CANCELLED')
-    p 'OK: cancel_after_first_response'
-  end
-
-  def all
-    all_methods = NamedTests.instance_methods(false).map(&:to_s)
-    all_methods.each do |m|
-      next if m == 'all' || m.start_with?('assert')
-      p "TESTCASE: #{m}"
-      method(m).call
-    end
-  end
-
-  private
-
-  def perform_large_unary(fill_username: false, fill_oauth_scope: false)
-    req_size, wanted_response_size = 271_828, 314_159
-    payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
-    req = SimpleRequest.new(response_type: :COMPRESSABLE,
-                            response_size: wanted_response_size,
-                            payload: payload)
-    req.fill_username = fill_username
-    req.fill_oauth_scope = fill_oauth_scope
-    resp = @stub.unary_call(req)
-    assert_equal(:COMPRESSABLE, resp.payload.type,
-                 'large_unary: payload had the wrong type')
-    assert_equal(wanted_response_size, resp.payload.body.length,
-                 'large_unary: payload had the wrong length')
-    assert_equal(nulls(wanted_response_size), resp.payload.body,
-                 'large_unary: payload content is invalid')
-    resp
-  end
-end
-
-# Args is used to hold the command line info.
-Args = Struct.new(:default_service_account, :host, :host_override,
-                  :oauth_scope, :port, :secure, :test_case,
-                  :use_test_ca)
-
-# validates the the command line options, returning them as a Hash.
-def parse_args
-  args = Args.new
-  args.host_override = 'foo.test.google.fr'
-  OptionParser.new do |opts|
-    opts.on('--oauth_scope scope',
-            'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
-    opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
-      args['host'] = v
-    end
-    opts.on('--default_service_account email_address',
-            'email address of the default service account') do |v|
-      args['default_service_account'] = v
-    end
-    opts.on('--server_host_override HOST_OVERRIDE',
-            'override host via a HTTP header') do |v|
-      args['host_override'] = v
-    end
-    opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
-    # instance_methods(false) gives only the methods defined in that class
-    test_cases = NamedTests.instance_methods(false).map(&:to_s)
-    test_case_list = test_cases.join(',')
-    opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
-            "  (#{test_case_list})") { |v| args['test_case'] = v }
-    opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
-      args['secure'] = v
-    end
-    opts.on('-t', '--use_test_ca',
-            'if secure, use the test certificate?') do |v|
-      args['use_test_ca'] = v
-    end
-  end.parse!
-  _check_args(args)
-end
-
-def _check_args(args)
-  %w(host port test_case).each do |a|
-    if args[a].nil?
-      fail(OptionParser::MissingArgument, "please specify --#{arg}")
-    end
-  end
-  args
-end
-
-def main
-  opts = parse_args
-  stub = create_stub(opts)
-  NamedTests.new(stub, opts).method(opts['test_case']).call
-end
-
-main
+require 'test/client'
diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb
index 2ba8d2c..c6b0d00 100755
--- a/src/ruby/bin/interop/interop_server.rb
+++ b/src/ruby/bin/interop/interop_server.rb
@@ -29,6 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+# #######################################################################
+# DEPRECATED: The behaviour in this file has been moved to pb/test/server.rb
+#
+# This file remains to support existing tools and scripts that use it.
+# ######################################################################
+#
 # interop_server is a Testing app that runs a gRPC interop testing server.
 #
 # It helps validate interoperation b/w gRPC in different environments
@@ -38,157 +44,7 @@
 # Usage: $ path/to/interop_server.rb --port
 
 this_dir = File.expand_path(File.dirname(__FILE__))
-lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
-$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
-$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
 
-require 'forwardable'
-require 'optparse'
-
-require 'grpc'
-
-require 'test/cpp/interop/test_services'
-require 'test/cpp/interop/messages'
-require 'test/cpp/interop/empty'
-
-# loads the certificates by the test server.
-def load_test_certs
-  this_dir = File.expand_path(File.dirname(__FILE__))
-  data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
-  files = ['ca.pem', 'server1.key', 'server1.pem']
-  files.map { |f| File.open(File.join(data_dir, f)).read }
-end
-
-# creates a ServerCredentials from the test certificates.
-def test_server_creds
-  certs = load_test_certs
-  GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
-end
-
-# produces a string of null chars (\0) of length l.
-def nulls(l)
-  fail 'requires #{l} to be +ve' if l < 0
-  [].pack('x' * l).force_encoding('utf-8')
-end
-
-# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
-class EnumeratorQueue
-  extend Forwardable
-  def_delegators :@q, :push
-
-  def initialize(sentinel)
-    @q = Queue.new
-    @sentinel = sentinel
-  end
-
-  def each_item
-    return enum_for(:each_item) unless block_given?
-    loop do
-      r = @q.pop
-      break if r.equal?(@sentinel)
-      fail r if r.is_a? Exception
-      yield r
-    end
-  end
-end
-
-# A runnable implementation of the schema-specified testing service, with each
-# service method implemented as required by the interop testing spec.
-class TestTarget < Grpc::Testing::TestService::Service
-  include Grpc::Testing
-  include Grpc::Testing::PayloadType
-
-  def empty_call(_empty, _call)
-    Empty.new
-  end
-
-  def unary_call(simple_req, _call)
-    req_size = simple_req.response_size
-    SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
-                                            body: nulls(req_size)))
-  end
-
-  def streaming_input_call(call)
-    sizes = call.each_remote_read.map { |x| x.payload.body.length }
-    sum = sizes.inject { |s, x| s + x }
-    StreamingInputCallResponse.new(aggregated_payload_size: sum)
-  end
-
-  def streaming_output_call(req, _call)
-    cls = StreamingOutputCallResponse
-    req.response_parameters.map do |p|
-      cls.new(payload: Payload.new(type: req.response_type,
-                                   body: nulls(p.size)))
-    end
-  end
-
-  def full_duplex_call(reqs)
-    # reqs is a lazy Enumerator of the requests sent by the client.
-    q = EnumeratorQueue.new(self)
-    cls = StreamingOutputCallResponse
-    Thread.new do
-      begin
-        GRPC.logger.info('interop-server: started receiving')
-        reqs.each do |req|
-          resp_size = req.response_parameters[0].size
-          GRPC.logger.info("read a req, response size is #{resp_size}")
-          resp = cls.new(payload: Payload.new(type: req.response_type,
-                                              body: nulls(resp_size)))
-          q.push(resp)
-        end
-        GRPC.logger.info('interop-server: finished receiving')
-        q.push(self)
-      rescue StandardError => e
-        GRPC.logger.info('interop-server: failed')
-        GRPC.logger.warn(e)
-        q.push(e)  # share the exception with the enumerator
-      end
-    end
-    q.each_item
-  end
-
-  def half_duplex_call(reqs)
-    # TODO: update with unique behaviour of the half_duplex_call if that's
-    # ever required by any of the tests.
-    full_duplex_call(reqs)
-  end
-end
-
-# validates the the command line options, returning them as a Hash.
-def parse_options
-  options = {
-    'port' => nil,
-    'secure' => false
-  }
-  OptionParser.new do |opts|
-    opts.banner = 'Usage: --port port'
-    opts.on('--port PORT', 'server port') do |v|
-      options['port'] = v
-    end
-    opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
-      options['secure'] = v
-    end
-  end.parse!
-
-  if options['port'].nil?
-    fail(OptionParser::MissingArgument, 'please specify --port')
-  end
-  options
-end
-
-def main
-  opts = parse_options
-  host = "0.0.0.0:#{opts['port']}"
-  s = GRPC::RpcServer.new
-  if opts['secure']
-    s.add_http2_port(host, test_server_creds)
-    GRPC.logger.info("... running securely on #{host}")
-  else
-    s.add_http2_port(host)
-    GRPC.logger.info("... running insecurely on #{host}")
-  end
-  s.handle(TestTarget)
-  s.run_till_terminated
-end
-
-main
+require 'test/server'
diff --git a/src/ruby/bin/interop/test/cpp/interop/test_services.rb b/src/ruby/bin/interop/test/cpp/interop/test_services.rb
deleted file mode 100644
index 5a3146c..0000000
--- a/src/ruby/bin/interop/test/cpp/interop/test_services.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2015, 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.
-
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: test/cpp/interop/test.proto for package 'grpc.testing'
-
-require 'grpc'
-require 'test/cpp/interop/test'
-
-module Grpc
-  module Testing
-    module TestService
-
-      # TODO: add proto service documentation here
-      class Service
-
-        include GRPC::GenericService
-
-        self.marshal_class_method = :encode
-        self.unmarshal_class_method = :decode
-        self.service_name = 'grpc.testing.TestService'
-
-        rpc :EmptyCall, Empty, Empty
-        rpc :UnaryCall, SimpleRequest, SimpleResponse
-        rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
-        rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse
-        rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
-        rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
-      end
-
-      Stub = Service.rpc_stub_class
-    end
-  end
-end
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 88659da..b09d4e2 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -170,7 +170,7 @@
   grpc_call *call = NULL;
   grpc_call_error err;
   TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
-  err = grpc_call_cancel(call);
+  err = grpc_call_cancel(call, NULL);
   if (err != GRPC_CALL_OK) {
     rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
              grpc_call_error_detail_of(err), err);
@@ -615,7 +615,7 @@
 
   /* call grpc_call_start_batch, then wait for it to complete using
    * pluck_event */
-  err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag));
+  err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag), NULL);
   if (err != GRPC_CALL_OK) {
     grpc_run_batch_stack_cleanup(&st);
     rb_raise(grpc_rb_eCallError,
@@ -629,13 +629,9 @@
     rb_raise(grpc_rb_eOutOfTime, "grpc_call_start_batch timed out");
     return Qnil;
   }
-  if (!ev.success) {
-    grpc_run_batch_stack_cleanup(&st);
-    rb_raise(grpc_rb_eCallError, "start_batch completion failed");
-    return Qnil;
-  }
 
-  /* Build and return the BatchResult struct result */
+  /* Build and return the BatchResult struct result,
+     if there is an error, it's reflected in the status */
   result = grpc_run_batch_stack_build_result(&st);
   grpc_run_batch_stack_cleanup(&st);
   return result;
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index ac591f1..6491aa4 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -147,7 +147,7 @@
   target_chars = StringValueCStr(target);
   grpc_rb_hash_convert_to_channel_args(channel_args, &args);
   if (credentials == Qnil) {
-    ch = grpc_insecure_channel_create(target_chars, &args);
+    ch = grpc_insecure_channel_create(target_chars, &args, NULL);
   } else {
     creds = grpc_rb_get_wrapped_credentials(credentials);
     ch = grpc_secure_channel_create(creds, target_chars, &args);
@@ -165,6 +165,65 @@
   return self;
 }
 
+/*
+  call-seq:
+    insecure_channel = Channel:new("myhost:8080", {'arg1': 'value1'})
+    creds = ...
+    secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds)
+
+  Creates channel instances. */
+static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv,
+                                                    VALUE self) {
+  VALUE try_to_connect = Qfalse;
+  grpc_rb_channel *wrapper = NULL;
+  grpc_channel *ch = NULL;
+
+  /* "01" == 0 mandatory args, 1 (try_to_connect) is optional */
+  rb_scan_args(argc, argv, "01", try_to_connect);
+
+  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
+  ch = wrapper->wrapped;
+  if (ch == NULL) {
+    rb_raise(rb_eRuntimeError, "closed!");
+    return Qnil;
+  }
+  return NUM2LONG(
+      grpc_channel_check_connectivity_state(ch, (int)try_to_connect));
+}
+
+/* Watch for a change in connectivity state.
+
+   Once the channel connectivity state is different from the last observed
+   state, tag will be enqueued on cq with success=1
+
+   If deadline expires BEFORE the state is changed, tag will be enqueued on
+   the completion queue with success=0 */
+static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
+                                                      VALUE last_state,
+                                                      VALUE cqueue,
+                                                      VALUE deadline,
+                                                      VALUE tag) {
+  grpc_rb_channel *wrapper = NULL;
+  grpc_channel *ch = NULL;
+  grpc_completion_queue *cq = NULL;
+
+  cq = grpc_rb_get_wrapped_completion_queue(cqueue);
+  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
+  ch = wrapper->wrapped;
+  if (ch == NULL) {
+    rb_raise(rb_eRuntimeError, "closed!");
+    return Qnil;
+  }
+  grpc_channel_watch_connectivity_state(
+      ch,
+      NUM2LONG(last_state),
+      grpc_rb_time_timeval(deadline, /* absolute time */ 0),
+      cq,
+      ROBJECT(tag));
+
+  return Qnil;
+}
+
 /* Clones Channel instances.
 
    Gives Channel a consistent implementation of Ruby's object copy/dup
@@ -195,18 +254,28 @@
 
 /* Create a call given a grpc_channel, in order to call method. The request
    is not sent until grpc_call_invoke is called. */
-static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method,
-                                         VALUE host, VALUE deadline) {
+static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue,
+                                         VALUE parent, VALUE mask,
+                                         VALUE method, VALUE host,
+                                         VALUE deadline) {
   VALUE res = Qnil;
   grpc_rb_channel *wrapper = NULL;
   grpc_call *call = NULL;
+  grpc_call *parent_call = NULL;
   grpc_channel *ch = NULL;
   grpc_completion_queue *cq = NULL;
+  int flags = GRPC_PROPAGATE_DEFAULTS;
   char *method_chars = StringValueCStr(method);
   char *host_chars = NULL;
   if (host != Qnil) {
     host_chars = StringValueCStr(host);
   }
+  if (mask != Qnil) {
+    flags = NUM2UINT(mask);
+  }
+  if (parent != Qnil) {
+    parent_call = grpc_rb_get_wrapped_call(parent);
+  }
 
   cq = grpc_rb_get_wrapped_completion_queue(cqueue);
   TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
@@ -216,10 +285,10 @@
     return Qnil;
   }
 
-  call = grpc_channel_create_call(ch, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
-                                  method_chars, host_chars,
-                                  grpc_rb_time_timeval(deadline,
-                                                       /* absolute time */ 0));
+  call = grpc_channel_create_call(ch, parent_call, flags, cq, method_chars,
+                                  host_chars, grpc_rb_time_timeval(
+                                      deadline,
+                                      /* absolute time */ 0), NULL);
   if (call == NULL) {
     rb_raise(rb_eRuntimeError, "cannot create call with method %s",
              method_chars);
@@ -237,6 +306,7 @@
   return res;
 }
 
+
 /* Closes the channel, calling it's destroy method */
 static VALUE grpc_rb_channel_destroy(VALUE self) {
   grpc_rb_channel *wrapper = NULL;
@@ -268,6 +338,38 @@
   return res;
 }
 
+static void Init_grpc_propagate_masks() {
+  /* Constants representing call propagation masks in grpc.h */
+  VALUE grpc_rb_mPropagateMasks = rb_define_module_under(
+      grpc_rb_mGrpcCore, "PropagateMasks");
+  rb_define_const(grpc_rb_mPropagateMasks, "DEADLINE",
+                  UINT2NUM(GRPC_PROPAGATE_DEADLINE));
+  rb_define_const(grpc_rb_mPropagateMasks, "CENSUS_STATS_CONTEXT",
+                  UINT2NUM(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT));
+  rb_define_const(grpc_rb_mPropagateMasks, "CENSUS_TRACING_CONTEXT",
+                  UINT2NUM(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT));
+  rb_define_const(grpc_rb_mPropagateMasks, "CANCELLATION",
+                  UINT2NUM(GRPC_PROPAGATE_CANCELLATION));
+  rb_define_const(grpc_rb_mPropagateMasks, "DEFAULTS",
+                  UINT2NUM(GRPC_PROPAGATE_DEFAULTS));
+}
+
+static void Init_grpc_connectivity_states() {
+  /* Constants representing call propagation masks in grpc.h */
+  VALUE grpc_rb_mConnectivityStates = rb_define_module_under(
+      grpc_rb_mGrpcCore, "ConnectivityStates");
+  rb_define_const(grpc_rb_mConnectivityStates, "IDLE",
+                  LONG2NUM(GRPC_CHANNEL_IDLE));
+  rb_define_const(grpc_rb_mConnectivityStates, "CONNECTING",
+                  LONG2NUM(GRPC_CHANNEL_CONNECTING));
+  rb_define_const(grpc_rb_mConnectivityStates, "READY",
+                  LONG2NUM(GRPC_CHANNEL_READY));
+  rb_define_const(grpc_rb_mConnectivityStates, "TRANSIENT_FAILURE",
+                  LONG2NUM(GRPC_CHANNEL_TRANSIENT_FAILURE));
+  rb_define_const(grpc_rb_mConnectivityStates, "FATAL_FAILURE",
+                  LONG2NUM(GRPC_CHANNEL_FATAL_FAILURE));
+}
+
 void Init_grpc_channel() {
   grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
   grpc_rb_cChannel =
@@ -282,8 +384,13 @@
                    grpc_rb_channel_init_copy, 1);
 
   /* Add ruby analogues of the Channel methods. */
+  rb_define_method(grpc_rb_cChannel, "connectivity_state",
+                   grpc_rb_channel_get_connectivity_state,
+                   -1);
+  rb_define_method(grpc_rb_cChannel, "watch_connectivity_state",
+                   grpc_rb_channel_watch_connectivity_state, 4);
   rb_define_method(grpc_rb_cChannel, "create_call",
-                   grpc_rb_channel_create_call, 4);
+                   grpc_rb_channel_create_call, 6);
   rb_define_method(grpc_rb_cChannel, "target", grpc_rb_channel_get_target, 0);
   rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
   rb_define_alias(grpc_rb_cChannel, "close", "destroy");
@@ -299,6 +406,8 @@
                   ID2SYM(rb_intern(GRPC_ARG_MAX_CONCURRENT_STREAMS)));
   rb_define_const(grpc_rb_cChannel, "MAX_MESSAGE_LENGTH",
                   ID2SYM(rb_intern(GRPC_ARG_MAX_MESSAGE_LENGTH)));
+  Init_grpc_propagate_masks();
+  Init_grpc_connectivity_states();
 }
 
 /* Gets the wrapped channel from the ruby wrapper */
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index b6674d7..0bc9eb2 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -56,7 +56,7 @@
 static void *grpc_rb_completion_queue_next_no_gil(void *param) {
   next_call_stack *const next_call = (next_call_stack*)param;
   next_call->event =
-      grpc_completion_queue_next(next_call->cq, next_call->timeout);
+      grpc_completion_queue_next(next_call->cq, next_call->timeout, NULL);
   return NULL;
 }
 
@@ -64,7 +64,7 @@
 static void *grpc_rb_completion_queue_pluck_no_gil(void *param) {
   next_call_stack *const next_call = (next_call_stack*)param;
   next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag,
-                                                 next_call->timeout);
+                                                 next_call->timeout, NULL);
   return NULL;
 }
 
@@ -128,7 +128,7 @@
 
 /* Allocates a completion queue. */
 static VALUE grpc_rb_completion_queue_alloc(VALUE cls) {
-  grpc_completion_queue *cq = grpc_completion_queue_create();
+  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
   if (cq == NULL) {
     rb_raise(rb_eArgError, "could not create a completion queue: not sure why");
   }
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 79a4ae8..7e76349 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -128,7 +128,7 @@
   TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type,
                        wrapper);
   grpc_rb_hash_convert_to_channel_args(channel_args, &args);
-  srv = grpc_server_create(&args);
+  srv = grpc_server_create(&args, NULL);
 
   if (args.args != NULL) {
     xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
@@ -136,7 +136,7 @@
   if (srv == NULL) {
     rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why");
   }
-  grpc_server_register_completion_queue(srv, cq);
+  grpc_server_register_completion_queue(srv, cq, NULL);
   wrapper->wrapped = srv;
 
   /* Add the cq as the server's mark object. This ensures the ruby cq can't be
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 45f3132..20a6206 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -22,18 +22,18 @@
   s.files += Dir.glob('bin/**/*')
   s.test_files = Dir.glob('spec/**/*')
   %w(math noproto).each do |b|
-    s.executables += [ "#{b}_client.rb", "#{b}_server.rb" ]
+    s.executables += ["#{b}_client.rb", "#{b}_server.rb"]
   end
-  s.require_paths = %w( bin lib )
+  s.executables += %w(grpc_ruby_interop_client grpc_ruby_interop_server)
+  s.require_paths = %w( bin lib pb )
   s.platform      = Gem::Platform::RUBY
 
   s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1'
-  s.add_dependency 'googleauth', '~> 0.4'  # reqd for interop tests
-  s.add_dependency 'logging', '~> 2.0'
-  s.add_dependency 'minitest', '~> 5.4'  # reqd for interop tests
+  s.add_dependency 'googleauth', '~> 0.4'
 
-  s.add_development_dependency 'simplecov', '~> 0.9'
   s.add_development_dependency 'bundler', '~> 1.9'
+  s.add_development_dependency 'logging', '~> 2.0'
+  s.add_development_dependency 'simplecov', '~> 0.9'
   s.add_development_dependency 'rake', '~> 10.4'
   s.add_development_dependency 'rake-compiler', '~> 0.9'
   s.add_development_dependency 'rspec', '~> 3.2'
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 215c006..17da401 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -74,8 +74,7 @@
     #
     # @param call [Call] a call on which to start and invocation
     # @param q [CompletionQueue] the completion queue
-    # @param deadline [Fixnum,TimeSpec] the deadline
-    def self.client_invoke(call, q, _deadline, **kw)
+    def self.client_invoke(call, q, **kw)
       fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
       unless q.is_a? Core::CompletionQueue
         fail(TypeError, '!Core::CompletionQueue')
@@ -418,7 +417,7 @@
     # @return [Enumerator, nil] a response Enumerator
     def bidi_streamer(requests, **kw, &blk)
       start_call(**kw) unless @started
-      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
+      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal)
       bd.run_on_client(requests, @op_notifier, &blk)
     end
 
@@ -434,7 +433,7 @@
     #
     # @param gen_each_reply [Proc] generates the BiDi stream replies
     def run_server_bidi(gen_each_reply)
-      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
+      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal)
       bd.run_on_server(gen_each_reply)
     end
 
@@ -456,7 +455,7 @@
     # Starts the call if not already started
     def start_call(**kw)
       return if @started
-      @metadata_tag = ActiveCall.client_invoke(@call, @cq, @deadline, **kw)
+      @metadata_tag = ActiveCall.client_invoke(@call, @cq, **kw)
       @started = true
     end
 
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 3b0c713..9dbbb74 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -56,15 +56,13 @@
     #          the call
     # @param marshal [Function] f(obj)->string that marshal requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param deadline [Fixnum] the deadline for the call to complete
-    def initialize(call, q, marshal, unmarshal, deadline)
+    def initialize(call, q, marshal, unmarshal)
       fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
       unless q.is_a? Core::CompletionQueue
         fail(ArgumentError, 'not a CompletionQueue')
       end
       @call = call
       @cq = q
-      @deadline = deadline
       @marshal = marshal
       @op_notifier = nil  # signals completion on clients
       @readq = Queue.new
@@ -99,7 +97,7 @@
     # @param gen_each_reply [Proc] generates the BiDi stream replies.
     def run_on_server(gen_each_reply)
       replys = gen_each_reply.call(each_queued_msg)
-      @loop_th = start_read_loop
+      @loop_th = start_read_loop(is_client: false)
       write_loop(replys, is_client: false)
     end
 
@@ -127,7 +125,7 @@
         count += 1
         req = @readq.pop
         GRPC.logger.debug("each_queued_msg: req = #{req}")
-        throw req if req.is_a? StandardError
+        fail req if req.is_a? StandardError
         break if req.equal?(END_OF_READS)
         yield req
       end
@@ -147,12 +145,9 @@
       GRPC.logger.debug("bidi-write-loop: #{count} writes done")
       if is_client
         GRPC.logger.debug("bidi-write-loop: client sent #{count}, waiting")
-        batch_result = @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
-                                       SEND_CLOSE_FROM_CLIENT => nil,
-                                       RECV_STATUS_ON_CLIENT => nil)
-        @call.status = batch_result.status
-        batch_result.check_status
-        GRPC.logger.debug("bidi-write-loop: done status #{@call.status}")
+        @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
+                        SEND_CLOSE_FROM_CLIENT => nil)
+        GRPC.logger.debug('bidi-write-loop: done')
         notify_done
       end
       GRPC.logger.debug('bidi-write-loop: finished')
@@ -164,7 +159,7 @@
     end
 
     # starts the read loop
-    def start_read_loop
+    def start_read_loop(is_client: true)
       Thread.new do
         GRPC.logger.debug('bidi-read-loop: starting')
         begin
@@ -177,9 +172,19 @@
             # TODO: ensure metadata is read if available, currently it's not
             batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
                                            RECV_MESSAGE => nil)
+
             # handle the next message
             if batch_result.message.nil?
               GRPC.logger.debug("bidi-read-loop: null batch #{batch_result}")
+
+              if is_client
+                batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
+                                               RECV_STATUS_ON_CLIENT => nil)
+                @call.status = batch_result.status
+                batch_result.check_status
+                GRPC.logger.debug("bidi-read-loop: done status #{@call.status}")
+              end
+
               @readq.push(END_OF_READS)
               GRPC.logger.debug('bidi-read-loop: done reading!')
               break
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index a2f1ec6..24ec179 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -32,6 +32,8 @@
 
 # GRPC contains the General RPC module.
 module GRPC
+  # rubocop:disable Metrics/ParameterLists
+
   # ClientStub represents an endpoint used to send requests to GRPC servers.
   class ClientStub
     include Core::StatusCodes
@@ -68,6 +70,12 @@
       update_metadata
     end
 
+    # Allows users of the stub to modify the propagate mask.
+    #
+    # This is an advanced feature for use when making calls to another gRPC
+    # server whilst running in the handler of an existing one.
+    attr_writer :propagate_mask
+
     # Creates a new ClientStub.
     #
     # Minimally, a stub is created with the just the host of the gRPC service
@@ -91,8 +99,8 @@
     #
     # - :update_metadata
     # when present, this a func that takes a hash and returns a hash
-    # it can be used to update metadata, i.e, remove, change or update
-    # amend metadata values.
+    # it can be used to update metadata, i.e, remove, or amend
+    # metadata values.
     #
     # @param host [String] the host the stub connects to
     # @param q [Core::CompletionQueue] used to wait for events
@@ -105,6 +113,7 @@
                    channel_override: nil,
                    timeout: nil,
                    creds: nil,
+                   propagate_mask: nil,
                    update_metadata: nil,
                    **kw)
       fail(TypeError, '!CompletionQueue') unless q.is_a?(Core::CompletionQueue)
@@ -113,6 +122,7 @@
       @update_metadata = ClientStub.check_update_metadata(update_metadata)
       alt_host = kw[Core::Channel::SSL_TARGET]
       @host = alt_host.nil? ? host : alt_host
+      @propagate_mask = propagate_mask
       @timeout = timeout.nil? ? DEFAULT_TIMEOUT : timeout
     end
 
@@ -151,11 +161,21 @@
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
     # @param timeout [Numeric] (optional) the max completion time in seconds
+    # @param deadline [Time] (optional) the time the request should complete
+    # @param parent [Core::Call] a prior call whose reserved metadata
+    #   will be propagated by this one.
     # @param return_op [true|false] return an Operation if true
     # @return [Object] the response received from the server
-    def request_response(method, req, marshal, unmarshal, timeout = nil,
-                         return_op: false, **kw)
-      c = new_active_call(method, marshal, unmarshal, timeout)
+    def request_response(method, req, marshal, unmarshal,
+                         deadline: nil,
+                         timeout: nil,
+                         return_op: false,
+                         parent: parent,
+                         **kw)
+      c = new_active_call(method, marshal, unmarshal,
+                          deadline: deadline,
+                          timeout: timeout,
+                          parent: parent)
       kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
       return c.request_response(req, **md) unless return_op
@@ -208,12 +228,22 @@
     # @param requests [Object] an Enumerable of requests to send
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param timeout [Numeric] the max completion time in seconds
+    # @param timeout [Numeric] (optional) the max completion time in seconds
+    # @param deadline [Time] (optional) the time the request should complete
     # @param return_op [true|false] return an Operation if true
+    # @param parent [Core::Call] a prior call whose reserved metadata
+    #   will be propagated by this one.
     # @return [Object|Operation] the response received from the server
-    def client_streamer(method, requests, marshal, unmarshal, timeout = nil,
-                        return_op: false, **kw)
-      c = new_active_call(method, marshal, unmarshal, timeout)
+    def client_streamer(method, requests, marshal, unmarshal,
+                        deadline: nil,
+                        timeout: nil,
+                        return_op: false,
+                        parent: nil,
+                        **kw)
+      c = new_active_call(method, marshal, unmarshal,
+                          deadline: deadline,
+                          timeout: timeout,
+                          parent: parent)
       kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
       return c.client_streamer(requests, **md) unless return_op
@@ -274,13 +304,24 @@
     # @param req [Object] the request sent to the server
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param timeout [Numeric] the max completion time in seconds
+    # @param timeout [Numeric] (optional) the max completion time in seconds
+    # @param deadline [Time] (optional) the time the request should complete
     # @param return_op [true|false]return an Operation if true
+    # @param parent [Core::Call] a prior call whose reserved metadata
+    #   will be propagated by this one.
     # @param blk [Block] when provided, is executed for each response
     # @return [Enumerator|Operation|nil] as discussed above
-    def server_streamer(method, req, marshal, unmarshal, timeout = nil,
-                        return_op: false, **kw, &blk)
-      c = new_active_call(method, marshal, unmarshal, timeout)
+    def server_streamer(method, req, marshal, unmarshal,
+                        deadline: nil,
+                        timeout: nil,
+                        return_op: false,
+                        parent: nil,
+                        **kw,
+                        &blk)
+      c = new_active_call(method, marshal, unmarshal,
+                          deadline: deadline,
+                          timeout: timeout,
+                          parent: parent)
       kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
       return c.server_streamer(req, **md, &blk) unless return_op
@@ -381,12 +422,23 @@
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
     # @param timeout [Numeric] (optional) the max completion time in seconds
-    # @param blk [Block] when provided, is executed for each response
+    # @param deadline [Time] (optional) the time the request should complete
+    # @param parent [Core::Call] a prior call whose reserved metadata
+    #   will be propagated by this one.
     # @param return_op [true|false] return an Operation if true
+    # @param blk [Block] when provided, is executed for each response
     # @return [Enumerator|nil|Operation] as discussed above
-    def bidi_streamer(method, requests, marshal, unmarshal, timeout = nil,
-                      return_op: false, **kw, &blk)
-      c = new_active_call(method, marshal, unmarshal, timeout)
+    def bidi_streamer(method, requests, marshal, unmarshal,
+                      deadline: nil,
+                      timeout: nil,
+                      return_op: false,
+                      parent: nil,
+                      **kw,
+                      &blk)
+      c = new_active_call(method, marshal, unmarshal,
+                          deadline: deadline,
+                          timeout: timeout,
+                          parent: parent)
       kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
       return c.bidi_streamer(requests, **md, &blk) unless return_op
@@ -407,10 +459,22 @@
     # @param method [string] the method being called.
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
+    # @param parent [Grpc::Call] a parent call, available when calls are
+    #   made from server
     # @param timeout [TimeConst]
-    def new_active_call(method, marshal, unmarshal, timeout = nil)
-      deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
-      call = @ch.create_call(@queue, method, nil, deadline)
+    def new_active_call(method, marshal, unmarshal,
+                        deadline: nil,
+                        timeout: nil,
+                        parent: nil)
+      if deadline.nil?
+        deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
+      end
+      call = @ch.create_call(@queue,
+                             parent, # parent call
+                             @propagate_mask, # propagation options
+                             method,
+                             nil, # host use nil,
+                             deadline)
       ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false)
     end
   end
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 3b9743e..80ff669 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -174,26 +174,24 @@
             unmarshal = desc.unmarshal_proc(:output)
             route = "/#{route_prefix}/#{name}"
             if desc.request_response?
-              define_method(mth_name) do |req, deadline = nil, **kw|
+              define_method(mth_name) do |req, **kw|
                 GRPC.logger.debug("calling #{@host}:#{route}")
-                request_response(route, req, marshal, unmarshal, deadline, **kw)
+                request_response(route, req, marshal, unmarshal, **kw)
               end
             elsif desc.client_streamer?
-              define_method(mth_name) do |reqs, deadline = nil, **kw|
+              define_method(mth_name) do |reqs, **kw|
                 GRPC.logger.debug("calling #{@host}:#{route}")
-                client_streamer(route, reqs, marshal, unmarshal, deadline, **kw)
+                client_streamer(route, reqs, marshal, unmarshal, **kw)
               end
             elsif desc.server_streamer?
-              define_method(mth_name) do |req, deadline = nil, **kw, &blk|
+              define_method(mth_name) do |req, **kw, &blk|
                 GRPC.logger.debug("calling #{@host}:#{route}")
-                server_streamer(route, req, marshal, unmarshal, deadline, **kw,
-                                &blk)
+                server_streamer(route, req, marshal, unmarshal, **kw, &blk)
               end
             else  # is a bidi_stream
-              define_method(mth_name) do |reqs, deadline = nil, **kw, &blk|
+              define_method(mth_name) do |reqs, **kw, &blk|
                 GRPC.logger.debug("calling #{@host}:#{route}")
-                bidi_streamer(route, reqs, marshal, unmarshal, deadline, **kw,
-                              &blk)
+                bidi_streamer(route, reqs, marshal, unmarshal, **kw, &blk)
               end
             end
           end
diff --git a/src/ruby/lib/grpc/logconfig.rb b/src/ruby/lib/grpc/logconfig.rb
index e9b4aa3..2bb7c86 100644
--- a/src/ruby/lib/grpc/logconfig.rb
+++ b/src/ruby/lib/grpc/logconfig.rb
@@ -27,17 +27,32 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'logging'
-
 # GRPC contains the General RPC module.
 module GRPC
-  extend Logging.globally
+  # DefaultLogger is a module included in GRPC if no other logging is set up for
+  # it.  See ../spec/spec_helpers an example of where other logging is added.
+  module DefaultLogger
+    def logger
+      LOGGER
+    end
+
+    private
+
+    # NoopLogger implements the methods of Ruby's conventional logging interface
+    # that are actually used internally within gRPC with a noop implementation.
+    class NoopLogger
+      def info(_ignored)
+      end
+
+      def debug(_ignored)
+      end
+
+      def warn(_ignored)
+      end
+    end
+
+    LOGGER = NoopLogger.new
+  end
+
+  include DefaultLogger unless method_defined?(:logger)
 end
-
-Logging.logger.root.appenders = Logging.appenders.stdout
-Logging.logger.root.level = :info
-
-# TODO: provide command-line configuration for logging
-Logging.logger['GRPC'].level = :info
-Logging.logger['GRPC::ActiveCall'].level = :info
-Logging.logger['GRPC::BidiCall'].level = :info
diff --git a/src/ruby/pb/README.md b/src/ruby/pb/README.md
new file mode 100644
index 0000000..84644e1
--- /dev/null
+++ b/src/ruby/pb/README.md
@@ -0,0 +1,42 @@
+Protocol Buffers
+================
+
+This folder contains protocol buffers provided with gRPC ruby, and the generated
+code to them.
+
+PREREQUISITES
+-------------
+
+The code is is generated using the protoc (> 3.0.0.alpha.1) and the
+grpc_ruby_plugin.  These must be installed to regenerate the IDL defined
+classes, but that's not necessary just to use them.
+
+health_check/v1alpha
+--------------------
+
+This package defines the surface of a simple health check service that gRPC
+servers may choose to implement, and provides an implementation for it. To
+re-generate the surface.
+
+```bash
+$ # (from this directory)
+$ protoc -I . grpc/health/v1alpha/health.proto \
+    --grpc_out=. \
+    --ruby_out=. \
+    --plugin=protoc-gen-grpc=`which grpc_ruby_plugin`
+```
+
+test
+----
+
+This package defines the surface of the gRPC interop test service and client
+To re-generate the surface, it's necessary to have checked-out versions of
+the grpc interop test proto, e.g, by having the full gRPC repository. E.g,
+
+```bash
+$ # (from this directory within the grpc repo)
+$ protoc -I../../.. ../../../test/proto/{messages,test,empty}.proto \
+    --grpc_out=. \
+    --ruby_out=. \
+    --plugin=protoc-gen-grpc=`which grpc_ruby_plugin`
+```
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
new file mode 100644
index 0000000..8c692e7
--- /dev/null
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -0,0 +1,75 @@
+# Copyright 2015, 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.
+
+require 'grpc'
+require 'grpc/health/v1alpha/health_services'
+require 'thread'
+
+module Grpc
+  # Health contains classes and modules that support providing a health check
+  # service.
+  module Health
+    # Checker is implementation of the schema-specified health checking service.
+    class Checker < V1alpha::Health::Service
+      StatusCodes = GRPC::Core::StatusCodes
+      HealthCheckResponse = V1alpha::HealthCheckResponse
+
+      # Initializes the statuses of participating services
+      def initialize
+        @statuses = {}
+        @status_mutex = Mutex.new  # guards access to @statuses
+      end
+
+      # Implements the rpc IDL API method
+      def check(req, _call)
+        status = nil
+        @status_mutex.synchronize do
+          status = @statuses["#{req.host}/#{req.service}"]
+        end
+        fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil?
+        HealthCheckResponse.new(status: status)
+      end
+
+      # Adds the health status for a given host and service.
+      def add_status(host, service, status)
+        @status_mutex.synchronize { @statuses["#{host}/#{service}"] = status }
+      end
+
+      # Clears the status for the given host or service.
+      def clear_status(host, service)
+        @status_mutex.synchronize { @statuses.delete("#{host}/#{service}") }
+      end
+
+      # Clears alls the statuses.
+      def clear_all
+        @status_mutex.synchronize { @statuses = {} }
+      end
+    end
+  end
+end
diff --git a/src/ruby/pb/grpc/health/v1alpha/health.proto b/src/ruby/pb/grpc/health/v1alpha/health.proto
new file mode 100644
index 0000000..d31df1e
--- /dev/null
+++ b/src/ruby/pb/grpc/health/v1alpha/health.proto
@@ -0,0 +1,50 @@
+// Copyright 2015, 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.
+
+syntax = "proto3";
+
+package grpc.health.v1alpha;
+
+message HealthCheckRequest {
+  string host = 1;
+  string service = 2;
+}
+
+message HealthCheckResponse {
+  enum ServingStatus {
+    UNKNOWN = 0;
+    SERVING = 1;
+    NOT_SERVING = 2;
+  }
+  ServingStatus status = 1;
+}
+
+service Health {
+  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
\ No newline at end of file
diff --git a/src/ruby/pb/grpc/health/v1alpha/health.rb b/src/ruby/pb/grpc/health/v1alpha/health.rb
new file mode 100644
index 0000000..9c04298
--- /dev/null
+++ b/src/ruby/pb/grpc/health/v1alpha/health.rb
@@ -0,0 +1,29 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: grpc/health/v1alpha/health.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_message "grpc.health.v1alpha.HealthCheckRequest" do
+    optional :host, :string, 1
+    optional :service, :string, 2
+  end
+  add_message "grpc.health.v1alpha.HealthCheckResponse" do
+    optional :status, :enum, 1, "grpc.health.v1alpha.HealthCheckResponse.ServingStatus"
+  end
+  add_enum "grpc.health.v1alpha.HealthCheckResponse.ServingStatus" do
+    value :UNKNOWN, 0
+    value :SERVING, 1
+    value :NOT_SERVING, 2
+  end
+end
+
+module Grpc
+  module Health
+    module V1alpha
+      HealthCheckRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckRequest").msgclass
+      HealthCheckResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse").msgclass
+      HealthCheckResponse::ServingStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse.ServingStatus").enummodule
+    end
+  end
+end
diff --git a/src/ruby/pb/grpc/health/v1alpha/health_services.rb b/src/ruby/pb/grpc/health/v1alpha/health_services.rb
new file mode 100644
index 0000000..d5cba2e
--- /dev/null
+++ b/src/ruby/pb/grpc/health/v1alpha/health_services.rb
@@ -0,0 +1,28 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# Source: grpc/health/v1alpha/health.proto for package 'grpc.health.v1alpha'
+
+require 'grpc'
+require 'grpc/health/v1alpha/health'
+
+module Grpc
+  module Health
+    module V1alpha
+      module Health
+
+        # TODO: add proto service documentation here
+        class Service
+
+          include GRPC::GenericService
+
+          self.marshal_class_method = :encode
+          self.unmarshal_class_method = :decode
+          self.service_name = 'grpc.health.v1alpha.Health'
+
+          rpc :Check, HealthCheckRequest, HealthCheckResponse
+        end
+
+        Stub = Service.rpc_stub_class
+      end
+    end
+  end
+end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
new file mode 100755
index 0000000..164e304
--- /dev/null
+++ b/src/ruby/pb/test/client.rb
@@ -0,0 +1,453 @@
+#!/usr/bin/env ruby
+
+# Copyright 2015, 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.
+
+# client is a testing tool that accesses a gRPC interop testing server and runs
+# a test on it.
+#
+# Helps validate interoperation b/w different gRPC implementations.
+#
+# Usage: $ path/to/client.rb --server_host=<hostname> \
+#                            --server_port=<port> \
+#                            --test_case=<testcase_name>
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
+pb_dir = File.dirname(File.dirname(this_dir))
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'optparse'
+
+require 'grpc'
+require 'googleauth'
+require 'google/protobuf'
+
+require 'test/proto/empty'
+require 'test/proto/messages'
+require 'test/proto/test_services'
+
+require 'signet/ssl_config'
+
+AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
+
+# AssertionError is use to indicate interop test failures.
+class AssertionError < RuntimeError; end
+
+# Fails with AssertionError if the block does evaluate to true
+def assert(msg = 'unknown cause')
+  fail 'No assertion block provided' unless block_given?
+  fail AssertionError, msg unless yield
+end
+
+# loads the certificates used to access the test server securely.
+def load_test_certs
+  this_dir = File.expand_path(File.dirname(__FILE__))
+  data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
+  files = ['ca.pem', 'server1.key', 'server1.pem']
+  files.map { |f| File.open(File.join(data_dir, f)).read }
+end
+
+# loads the certificates used to access the test server securely.
+def load_prod_cert
+  fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
+  GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
+  File.open(ENV['SSL_CERT_FILE']).read
+end
+
+# creates SSL Credentials from the test certificates.
+def test_creds
+  certs = load_test_certs
+  GRPC::Core::Credentials.new(certs[0])
+end
+
+# creates SSL Credentials from the production certificates.
+def prod_creds
+  cert_text = load_prod_cert
+  GRPC::Core::Credentials.new(cert_text)
+end
+
+# creates the SSL Credentials.
+def ssl_creds(use_test_ca)
+  return test_creds if use_test_ca
+  prod_creds
+end
+
+# creates a test stub that accesses host:port securely.
+def create_stub(opts)
+  address = "#{opts.host}:#{opts.port}"
+  if opts.secure
+    stub_opts = {
+      :creds => ssl_creds(opts.use_test_ca),
+      GRPC::Core::Channel::SSL_TARGET => opts.host_override
+    }
+
+    # Add service account creds if specified
+    wants_creds = %w(all compute_engine_creds service_account_creds)
+    if wants_creds.include?(opts.test_case)
+      unless opts.oauth_scope.nil?
+        auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
+        stub_opts[:update_metadata] = auth_creds.updater_proc
+      end
+    end
+
+    if opts.test_case == 'oauth2_auth_token'
+      auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
+      kw = auth_creds.updater_proc.call({})  # gives as an auth token
+
+      # use a metadata update proc that just adds the auth token.
+      stub_opts[:update_metadata] = proc { |md| md.merge(kw) }
+    end
+
+    if opts.test_case == 'jwt_token_creds'  # don't use a scope
+      auth_creds = Google::Auth.get_application_default
+      stub_opts[:update_metadata] = auth_creds.updater_proc
+    end
+
+    GRPC.logger.info("... connecting securely to #{address}")
+    Grpc::Testing::TestService::Stub.new(address, **stub_opts)
+  else
+    GRPC.logger.info("... connecting insecurely to #{address}")
+    Grpc::Testing::TestService::Stub.new(address)
+  end
+end
+
+# produces a string of null chars (\0) of length l.
+def nulls(l)
+  fail 'requires #{l} to be +ve' if l < 0
+  [].pack('x' * l).force_encoding('utf-8')
+end
+
+# a PingPongPlayer implements the ping pong bidi test.
+class PingPongPlayer
+  include Grpc::Testing
+  include Grpc::Testing::PayloadType
+  attr_accessor :queue
+  attr_accessor :canceller_op
+
+  # reqs is the enumerator over the requests
+  def initialize(msg_sizes)
+    @queue = Queue.new
+    @msg_sizes = msg_sizes
+    @canceller_op = nil  # used to cancel after the first response
+  end
+
+  def each_item
+    return enum_for(:each_item) unless block_given?
+    req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters  # short
+    count = 0
+    @msg_sizes.each do |m|
+      req_size, resp_size = m
+      req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
+                        response_type: :COMPRESSABLE,
+                        response_parameters: [p_cls.new(size: resp_size)])
+      yield req
+      resp = @queue.pop
+      assert('payload type is wrong') { :COMPRESSABLE == resp.payload.type }
+      assert("payload body #{count} has the wrong length") do
+        resp_size == resp.payload.body.length
+      end
+      p "OK: ping_pong #{count}"
+      count += 1
+      unless @canceller_op.nil?
+        canceller_op.cancel
+        break
+      end
+    end
+  end
+end
+
+# defines methods corresponding to each interop test case.
+class NamedTests
+  include Grpc::Testing
+  include Grpc::Testing::PayloadType
+
+  def initialize(stub, args)
+    @stub = stub
+    @args = args
+  end
+
+  def empty_unary
+    resp = @stub.empty_call(Empty.new)
+    assert('empty_unary: invalid response') { resp.is_a?(Empty) }
+    p 'OK: empty_unary'
+  end
+
+  def large_unary
+    perform_large_unary
+    p 'OK: large_unary'
+  end
+
+  def service_account_creds
+    # ignore this test if the oauth options are not set
+    if @args.oauth_scope.nil?
+      p 'NOT RUN: service_account_creds; no service_account settings'
+      return
+    end
+    json_key = File.read(ENV[AUTH_ENV])
+    wanted_email = MultiJson.load(json_key)['client_email']
+    resp = perform_large_unary(fill_username: true,
+                               fill_oauth_scope: true)
+    assert("#{__callee__}: bad username") { wanted_email == resp.username }
+    assert("#{__callee__}: bad oauth scope") do
+      @args.oauth_scope.include?(resp.oauth_scope)
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def jwt_token_creds
+    json_key = File.read(ENV[AUTH_ENV])
+    wanted_email = MultiJson.load(json_key)['client_email']
+    resp = perform_large_unary(fill_username: true)
+    assert("#{__callee__}: bad username") { wanted_email == resp.username }
+    p "OK: #{__callee__}"
+  end
+
+  def compute_engine_creds
+    resp = perform_large_unary(fill_username: true,
+                               fill_oauth_scope: true)
+    assert("#{__callee__}: bad username") do
+      @args.default_service_account == resp.username
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def oauth2_auth_token
+    resp = perform_large_unary(fill_username: true,
+                               fill_oauth_scope: true)
+    json_key = File.read(ENV[AUTH_ENV])
+    wanted_email = MultiJson.load(json_key)['client_email']
+    assert("#{__callee__}: bad username") { wanted_email == resp.username }
+    assert("#{__callee__}: bad oauth scope") do
+      @args.oauth_scope.include?(resp.oauth_scope)
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def per_rpc_creds
+    auth_creds = Google::Auth.get_application_default(@args.oauth_scope)
+    kw = auth_creds.updater_proc.call({})
+    resp = perform_large_unary(fill_username: true,
+                               fill_oauth_scope: true,
+                               **kw)
+    json_key = File.read(ENV[AUTH_ENV])
+    wanted_email = MultiJson.load(json_key)['client_email']
+    assert("#{__callee__}: bad username") { wanted_email == resp.username }
+    assert("#{__callee__}: bad oauth scope") do
+      @args.oauth_scope.include?(resp.oauth_scope)
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def client_streaming
+    msg_sizes = [27_182, 8, 1828, 45_904]
+    wanted_aggregate_size = 74_922
+    reqs = msg_sizes.map do |x|
+      req = Payload.new(body: nulls(x))
+      StreamingInputCallRequest.new(payload: req)
+    end
+    resp = @stub.streaming_input_call(reqs)
+    assert("#{__callee__}: aggregate payload size is incorrect") do
+      wanted_aggregate_size == resp.aggregated_payload_size
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def server_streaming
+    msg_sizes = [31_415, 9, 2653, 58_979]
+    response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
+    req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
+                                         response_parameters: response_spec)
+    resps = @stub.streaming_output_call(req)
+    resps.each_with_index do |r, i|
+      assert("#{__callee__}: too many responses") { i < msg_sizes.length }
+      assert("#{__callee__}: payload body #{i} has the wrong length") do
+        msg_sizes[i] == r.payload.body.length
+      end
+      assert("#{__callee__}: payload type is wrong") do
+        :COMPRESSABLE == r.payload.type
+      end
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def ping_pong
+    msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
+    ppp = PingPongPlayer.new(msg_sizes)
+    resps = @stub.full_duplex_call(ppp.each_item)
+    resps.each { |r| ppp.queue.push(r) }
+    p "OK: #{__callee__}"
+  end
+
+  def timeout_on_sleeping_server
+    msg_sizes = [[27_182, 31_415]]
+    ppp = PingPongPlayer.new(msg_sizes)
+    resps = @stub.full_duplex_call(ppp.each_item, timeout: 0.001)
+    resps.each { |r| ppp.queue.push(r) }
+    fail 'Should have raised GRPC::BadStatus(DEADLINE_EXCEEDED)'
+  rescue GRPC::BadStatus => e
+    assert("#{__callee__}: status was wrong") do
+      e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def empty_stream
+    ppp = PingPongPlayer.new([])
+    resps = @stub.full_duplex_call(ppp.each_item)
+    count = 0
+    resps.each do |r|
+      ppp.queue.push(r)
+      count += 1
+    end
+    assert("#{__callee__}: too many responses expected 0") do
+      count == 0
+    end
+    p "OK: #{__callee__}"
+  end
+
+  def cancel_after_begin
+    msg_sizes = [27_182, 8, 1828, 45_904]
+    reqs = msg_sizes.map do |x|
+      req = Payload.new(body: nulls(x))
+      StreamingInputCallRequest.new(payload: req)
+    end
+    op = @stub.streaming_input_call(reqs, return_op: true)
+    op.cancel
+    op.execute
+    fail 'Should have raised GRPC:Cancelled'
+  rescue GRPC::Cancelled
+    assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
+    p "OK: #{__callee__}"
+  end
+
+  def cancel_after_first_response
+    msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
+    ppp = PingPongPlayer.new(msg_sizes)
+    op = @stub.full_duplex_call(ppp.each_item, return_op: true)
+    ppp.canceller_op = op  # causes ppp to cancel after the 1st message
+    op.execute.each { |r| ppp.queue.push(r) }
+    fail 'Should have raised GRPC:Cancelled'
+  rescue GRPC::Cancelled
+    assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
+    op.wait
+    p "OK: #{__callee__}"
+  end
+
+  def all
+    all_methods = NamedTests.instance_methods(false).map(&:to_s)
+    all_methods.each do |m|
+      next if m == 'all' || m.start_with?('assert')
+      p "TESTCASE: #{m}"
+      method(m).call
+    end
+  end
+
+  private
+
+  def perform_large_unary(fill_username: false, fill_oauth_scope: false, **kw)
+    req_size, wanted_response_size = 271_828, 314_159
+    payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
+    req = SimpleRequest.new(response_type: :COMPRESSABLE,
+                            response_size: wanted_response_size,
+                            payload: payload)
+    req.fill_username = fill_username
+    req.fill_oauth_scope = fill_oauth_scope
+    resp = @stub.unary_call(req, **kw)
+    assert('payload type is wrong') do
+      :COMPRESSABLE == resp.payload.type
+    end
+    assert('payload body has the wrong length') do
+      wanted_response_size == resp.payload.body.length
+    end
+    assert('payload body is invalid') do
+      nulls(wanted_response_size) == resp.payload.body
+    end
+    resp
+  end
+end
+
+# Args is used to hold the command line info.
+Args = Struct.new(:default_service_account, :host, :host_override,
+                  :oauth_scope, :port, :secure, :test_case,
+                  :use_test_ca)
+
+# validates the the command line options, returning them as a Hash.
+def parse_args
+  args = Args.new
+  args.host_override = 'foo.test.google.fr'
+  OptionParser.new do |opts|
+    opts.on('--oauth_scope scope',
+            'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
+    opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
+      args['host'] = v
+    end
+    opts.on('--default_service_account email_address',
+            'email address of the default service account') do |v|
+      args['default_service_account'] = v
+    end
+    opts.on('--server_host_override HOST_OVERRIDE',
+            'override host via a HTTP header') do |v|
+      args['host_override'] = v
+    end
+    opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
+    # instance_methods(false) gives only the methods defined in that class
+    test_cases = NamedTests.instance_methods(false).map(&:to_s)
+    test_case_list = test_cases.join(',')
+    opts.on('--test_case CODE', test_cases, {}, 'select a test_case',
+            "  (#{test_case_list})") { |v| args['test_case'] = v }
+    opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
+      args['secure'] = v
+    end
+    opts.on('-t', '--use_test_ca',
+            'if secure, use the test certificate?') do |v|
+      args['use_test_ca'] = v
+    end
+  end.parse!
+  _check_args(args)
+end
+
+def _check_args(args)
+  %w(host port test_case).each do |a|
+    if args[a].nil?
+      fail(OptionParser::MissingArgument, "please specify --#{a}")
+    end
+  end
+  args
+end
+
+def main
+  opts = parse_args
+  stub = create_stub(opts)
+  NamedTests.new(stub, opts).method(opts['test_case']).call
+end
+
+main
diff --git a/src/ruby/pb/test/proto/empty.rb b/src/ruby/pb/test/proto/empty.rb
new file mode 100644
index 0000000..559adcc
--- /dev/null
+++ b/src/ruby/pb/test/proto/empty.rb
@@ -0,0 +1,15 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: test/proto/empty.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_message "grpc.testing.Empty" do
+  end
+end
+
+module Grpc
+  module Testing
+    Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass
+  end
+end
diff --git a/src/ruby/bin/interop/test/cpp/interop/messages.rb b/src/ruby/pb/test/proto/messages.rb
similarity index 64%
rename from src/ruby/bin/interop/test/cpp/interop/messages.rb
rename to src/ruby/pb/test/proto/messages.rb
index 89c349b..9b7f977 100644
--- a/src/ruby/bin/interop/test/cpp/interop/messages.rb
+++ b/src/ruby/pb/test/proto/messages.rb
@@ -1,34 +1,5 @@
-# Copyright 2015, 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.
-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/messages.proto
+# source: test/proto/messages.proto
 
 require 'google/protobuf'
 
@@ -37,12 +8,18 @@
     optional :type, :enum, 1, "grpc.testing.PayloadType"
     optional :body, :string, 2
   end
+  add_message "grpc.testing.EchoStatus" do
+    optional :code, :int32, 1
+    optional :message, :string, 2
+  end
   add_message "grpc.testing.SimpleRequest" do
     optional :response_type, :enum, 1, "grpc.testing.PayloadType"
     optional :response_size, :int32, 2
     optional :payload, :message, 3, "grpc.testing.Payload"
     optional :fill_username, :bool, 4
     optional :fill_oauth_scope, :bool, 5
+    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+    optional :response_status, :message, 7, "grpc.testing.EchoStatus"
   end
   add_message "grpc.testing.SimpleResponse" do
     optional :payload, :message, 1, "grpc.testing.Payload"
@@ -63,20 +40,32 @@
     optional :response_type, :enum, 1, "grpc.testing.PayloadType"
     repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
     optional :payload, :message, 3, "grpc.testing.Payload"
+    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+    optional :response_status, :message, 7, "grpc.testing.EchoStatus"
   end
   add_message "grpc.testing.StreamingOutputCallResponse" do
     optional :payload, :message, 1, "grpc.testing.Payload"
   end
+  add_message "grpc.testing.ReconnectInfo" do
+    optional :passed, :bool, 1
+    repeated :backoff_ms, :int32, 2
+  end
   add_enum "grpc.testing.PayloadType" do
     value :COMPRESSABLE, 0
     value :UNCOMPRESSABLE, 1
     value :RANDOM, 2
   end
+  add_enum "grpc.testing.CompressionType" do
+    value :NONE, 0
+    value :GZIP, 1
+    value :DEFLATE, 2
+  end
 end
 
 module Grpc
   module Testing
     Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
+    EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
     SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
     SimpleResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleResponse").msgclass
     StreamingInputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallRequest").msgclass
@@ -84,6 +73,8 @@
     ResponseParameters = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ResponseParameters").msgclass
     StreamingOutputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallRequest").msgclass
     StreamingOutputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass
+    ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
     PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
+    CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
   end
 end
diff --git a/src/ruby/pb/test/proto/test.rb b/src/ruby/pb/test/proto/test.rb
new file mode 100644
index 0000000..100eb65
--- /dev/null
+++ b/src/ruby/pb/test/proto/test.rb
@@ -0,0 +1,14 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: test/proto/test.proto
+
+require 'google/protobuf'
+
+require 'test/proto/empty'
+require 'test/proto/messages'
+Google::Protobuf::DescriptorPool.generated_pool.build do
+end
+
+module Grpc
+  module Testing
+  end
+end
diff --git a/src/ruby/pb/test/proto/test_services.rb b/src/ruby/pb/test/proto/test_services.rb
new file mode 100644
index 0000000..9df9cc5
--- /dev/null
+++ b/src/ruby/pb/test/proto/test_services.rb
@@ -0,0 +1,64 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# Source: test/proto/test.proto for package 'grpc.testing'
+
+require 'grpc'
+require 'test/proto/test'
+
+module Grpc
+  module Testing
+    module TestService
+
+      # TODO: add proto service documentation here
+      class Service
+
+        include GRPC::GenericService
+
+        self.marshal_class_method = :encode
+        self.unmarshal_class_method = :decode
+        self.service_name = 'grpc.testing.TestService'
+
+        rpc :EmptyCall, Empty, Empty
+        rpc :UnaryCall, SimpleRequest, SimpleResponse
+        rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
+        rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse
+        rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+        rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+      end
+
+      Stub = Service.rpc_stub_class
+    end
+    module UnimplementedService
+
+      # TODO: add proto service documentation here
+      class Service
+
+        include GRPC::GenericService
+
+        self.marshal_class_method = :encode
+        self.unmarshal_class_method = :decode
+        self.service_name = 'grpc.testing.UnimplementedService'
+
+        rpc :UnimplementedCall, Empty, Empty
+      end
+
+      Stub = Service.rpc_stub_class
+    end
+    module ReconnectService
+
+      # TODO: add proto service documentation here
+      class Service
+
+        include GRPC::GenericService
+
+        self.marshal_class_method = :encode
+        self.unmarshal_class_method = :decode
+        self.service_name = 'grpc.testing.ReconnectService'
+
+        rpc :Start, Empty, Empty
+        rpc :Stop, Empty, ReconnectInfo
+      end
+
+      Stub = Service.rpc_stub_class
+    end
+  end
+end
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
new file mode 100755
index 0000000..e2e1ecb
--- /dev/null
+++ b/src/ruby/pb/test/server.rb
@@ -0,0 +1,196 @@
+#!/usr/bin/env ruby
+
+# Copyright 2015, 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.
+
+# interop_server is a Testing app that runs a gRPC interop testing server.
+#
+# It helps validate interoperation b/w gRPC in different environments
+#
+# Helps validate interoperation b/w different gRPC implementations.
+#
+# Usage: $ path/to/interop_server.rb --port
+
+this_dir = File.expand_path(File.dirname(__FILE__))
+lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
+pb_dir = File.dirname(File.dirname(this_dir))
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
+
+require 'forwardable'
+require 'optparse'
+
+require 'grpc'
+
+require 'test/proto/empty'
+require 'test/proto/messages'
+require 'test/proto/test_services'
+
+# loads the certificates by the test server.
+def load_test_certs
+  this_dir = File.expand_path(File.dirname(__FILE__))
+  data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata')
+  files = ['ca.pem', 'server1.key', 'server1.pem']
+  files.map { |f| File.open(File.join(data_dir, f)).read }
+end
+
+# creates a ServerCredentials from the test certificates.
+def test_server_creds
+  certs = load_test_certs
+  GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
+end
+
+# produces a string of null chars (\0) of length l.
+def nulls(l)
+  fail 'requires #{l} to be +ve' if l < 0
+  [].pack('x' * l).force_encoding('utf-8')
+end
+
+# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
+class EnumeratorQueue
+  extend Forwardable
+  def_delegators :@q, :push
+
+  def initialize(sentinel)
+    @q = Queue.new
+    @sentinel = sentinel
+  end
+
+  def each_item
+    return enum_for(:each_item) unless block_given?
+    loop do
+      r = @q.pop
+      break if r.equal?(@sentinel)
+      fail r if r.is_a? Exception
+      yield r
+    end
+  end
+end
+
+# A runnable implementation of the schema-specified testing service, with each
+# service method implemented as required by the interop testing spec.
+class TestTarget < Grpc::Testing::TestService::Service
+  include Grpc::Testing
+  include Grpc::Testing::PayloadType
+
+  def empty_call(_empty, _call)
+    Empty.new
+  end
+
+  def unary_call(simple_req, _call)
+    req_size = simple_req.response_size
+    SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
+                                            body: nulls(req_size)))
+  end
+
+  def streaming_input_call(call)
+    sizes = call.each_remote_read.map { |x| x.payload.body.length }
+    sum = sizes.inject { |s, x| s + x }
+    StreamingInputCallResponse.new(aggregated_payload_size: sum)
+  end
+
+  def streaming_output_call(req, _call)
+    cls = StreamingOutputCallResponse
+    req.response_parameters.map do |p|
+      cls.new(payload: Payload.new(type: req.response_type,
+                                   body: nulls(p.size)))
+    end
+  end
+
+  def full_duplex_call(reqs)
+    # reqs is a lazy Enumerator of the requests sent by the client.
+    q = EnumeratorQueue.new(self)
+    cls = StreamingOutputCallResponse
+    Thread.new do
+      begin
+        GRPC.logger.info('interop-server: started receiving')
+        reqs.each do |req|
+          resp_size = req.response_parameters[0].size
+          GRPC.logger.info("read a req, response size is #{resp_size}")
+          resp = cls.new(payload: Payload.new(type: req.response_type,
+                                              body: nulls(resp_size)))
+          q.push(resp)
+        end
+        GRPC.logger.info('interop-server: finished receiving')
+        q.push(self)
+      rescue StandardError => e
+        GRPC.logger.info('interop-server: failed')
+        GRPC.logger.warn(e)
+        q.push(e)  # share the exception with the enumerator
+      end
+    end
+    q.each_item
+  end
+
+  def half_duplex_call(reqs)
+    # TODO: update with unique behaviour of the half_duplex_call if that's
+    # ever required by any of the tests.
+    full_duplex_call(reqs)
+  end
+end
+
+# validates the the command line options, returning them as a Hash.
+def parse_options
+  options = {
+    'port' => nil,
+    'secure' => false
+  }
+  OptionParser.new do |opts|
+    opts.banner = 'Usage: --port port'
+    opts.on('--port PORT', 'server port') do |v|
+      options['port'] = v
+    end
+    opts.on('-s', '--use_tls', 'require a secure connection?') do |v|
+      options['secure'] = v
+    end
+  end.parse!
+
+  if options['port'].nil?
+    fail(OptionParser::MissingArgument, 'please specify --port')
+  end
+  options
+end
+
+def main
+  opts = parse_options
+  host = "0.0.0.0:#{opts['port']}"
+  s = GRPC::RpcServer.new
+  if opts['secure']
+    s.add_http2_port(host, test_server_creds)
+    GRPC.logger.info("... running securely on #{host}")
+  else
+    s.add_http2_port(host)
+    GRPC.logger.info("... running insecurely on #{host}")
+  end
+  s.handle(TestTarget)
+  s.run_till_terminated
+end
+
+main
diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb
index 36a442f..3c5d33f 100644
--- a/src/ruby/spec/call_spec.rb
+++ b/src/ruby/spec/call_spec.rb
@@ -137,7 +137,7 @@
   end
 
   def make_test_call
-    @ch.create_call(client_queue, 'dummy_method', nil, deadline)
+    @ch.create_call(client_queue, nil, nil, 'dummy_method', nil, deadline)
   end
 
   def deadline
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index 9081f0e..25cefcd 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -117,7 +117,7 @@
       deadline = Time.now + 5
 
       blk = proc do
-        ch.create_call(cq, 'dummy_method', nil, deadline)
+        ch.create_call(cq, nil, nil, 'dummy_method', nil, deadline)
       end
       expect(&blk).to_not raise_error
     end
@@ -128,7 +128,7 @@
 
       deadline = Time.now + 5
       blk = proc do
-        ch.create_call(cq, 'dummy_method', nil, deadline)
+        ch.create_call(cq, nil, nil, 'dummy_method', nil, deadline)
       end
       expect(&blk).to raise_error(RuntimeError)
     end
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 57c9a8d..2e673ff 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -61,7 +61,7 @@
   end
 
   def new_client_call
-    @ch.create_call(@client_queue, '/method', nil, deadline)
+    @ch.create_call(@client_queue, nil, nil, '/method', nil, deadline)
   end
 end
 
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 424b2db..26208b7 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -57,7 +57,7 @@
   describe 'restricted view methods' do
     before(:each) do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       @client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                     @pass_through, deadline,
                                     metadata_tag: md_tag)
@@ -87,7 +87,7 @@
   describe '#remote_send' do
     it 'allows a client to send a payload to the server' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       @client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                     @pass_through, deadline,
                                     metadata_tag: md_tag)
@@ -111,7 +111,7 @@
 
     it 'marshals the payload using the marshal func' do
       call = make_test_call
-      ActiveCall.client_invoke(call, @client_queue, deadline)
+      ActiveCall.client_invoke(call, @client_queue)
       marshal = proc { |x| 'marshalled:' + x }
       client_call = ActiveCall.new(call, @client_queue, marshal,
                                    @pass_through, deadline)
@@ -134,8 +134,7 @@
   describe '#client_invoke' do
     it 'sends keywords as metadata to the server when the are present' do
       call = make_test_call
-      ActiveCall.client_invoke(call, @client_queue, deadline,
-                               k1: 'v1', k2: 'v2')
+      ActiveCall.client_invoke(call, @client_queue, k1: 'v1', k2: 'v2')
       recvd_rpc =  @server.request_call(@server_queue, @server_tag, deadline)
       recvd_call = recvd_rpc.call
       expect(recvd_call).to_not be_nil
@@ -148,7 +147,7 @@
   describe '#remote_read' do
     it 'reads the response sent by a server' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -161,7 +160,7 @@
 
     it 'saves no metadata when the server adds no metadata' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -176,7 +175,7 @@
 
     it 'saves metadata add by the server' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -192,7 +191,7 @@
 
     it 'get a nil msg before a status when an OK status is sent' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -209,7 +208,7 @@
 
     it 'unmarshals the response using the unmarshal func' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       unmarshal = proc { |x| 'unmarshalled:' + x }
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    unmarshal, deadline,
@@ -234,7 +233,7 @@
 
     it 'the returns an enumerator that can read n responses' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -252,7 +251,7 @@
 
     it 'the returns an enumerator that stops after an OK Status' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -275,7 +274,7 @@
   describe '#writes_done' do
     it 'finishes ok if the server sends a status response' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -291,7 +290,7 @@
 
     it 'finishes ok if the server sends an early status response' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -307,7 +306,7 @@
 
     it 'finishes ok if writes_done is true' do
       call = make_test_call
-      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
                                    metadata_tag: md_tag)
@@ -338,7 +337,7 @@
   end
 
   def make_test_call
-    @ch.create_call(@client_queue, '/method', nil, deadline)
+    @ch.create_call(@client_queue, nil, nil, '/method', nil, deadline)
   end
 
   def deadline
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 68d4b11..edcc962 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -408,6 +408,26 @@
 
       it_behaves_like 'bidi streaming'
     end
+
+    describe 'without enough time to run' do
+      before(:each) do
+        @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
+        @replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
+        server_port = create_test_server
+        @host = "localhost:#{server_port}"
+      end
+
+      it 'should fail with DeadlineExceeded', bidi: true do
+        @server.start
+        stub = GRPC::ClientStub.new(@host, @cq)
+        blk = proc do
+          e = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
+                                 timeout: 0.001)
+          e.collect { |r| r }
+        end
+        expect(&blk).to raise_error GRPC::BadStatus, /Deadline Exceeded/
+      end
+    end
   end
 
   def run_server_streamer(expected_input, replys, status, **kw)
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 0326f6e..1295fd7 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -396,8 +396,9 @@
         @srv.wait_till_running
         req = EchoMsg.new
         stub = SlowStub.new(@host, **client_opts)
-        deadline = service.delay + 1.0 # wait for long enough
-        expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+        timeout = service.delay + 1.0 # wait for long enough
+        resp = stub.an_rpc(req, timeout: timeout, k1: 'v1', k2: 'v2')
+        expect(resp).to be_a(EchoMsg)
         wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
         check_md(wanted_md, service.received_md)
         @srv.stop
@@ -411,8 +412,8 @@
         @srv.wait_till_running
         req = EchoMsg.new
         stub = SlowStub.new(@host, **client_opts)
-        deadline = 0.1  # too short for SlowService to respond
-        blk = proc { stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2') }
+        timeout = 0.1  # too short for SlowService to respond
+        blk = proc { stub.an_rpc(req, timeout: timeout, k1: 'v1', k2: 'v2') }
         expect(&blk).to raise_error GRPC::BadStatus
         wanted_md = []
         expect(service.received_md).to eq(wanted_md)
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
new file mode 100644
index 0000000..6999a69
--- /dev/null
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -0,0 +1,233 @@
+# Copyright 2015, 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.
+
+require 'grpc'
+require 'grpc/health/v1alpha/health'
+require 'grpc/health/checker'
+require 'open3'
+
+def can_run_codegen_check
+  system('which grpc_ruby_plugin') && system('which protoc')
+end
+
+describe 'Health protobuf code generation' do
+  context 'the health service file used by grpc/health/checker' do
+    if !can_run_codegen_check
+      skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen'
+    else
+      it 'should already be loaded indirectly i.e, used by the other specs' do
+        expect(require('grpc/health/v1alpha/health_services')).to be(false)
+      end
+
+      it 'should have the same content as created by code generation' do
+        root_dir = File.dirname(
+          File.dirname(File.dirname(File.dirname(__FILE__))))
+        pb_dir = File.join(root_dir, 'pb')
+
+        # Get the current content
+        service_path = File.join(pb_dir, 'grpc', 'health', 'v1alpha',
+                                 'health_services.rb')
+        want = nil
+        File.open(service_path) { |f| want = f.read }
+
+        # Regenerate it
+        plugin, = Open3.capture2('which', 'grpc_ruby_plugin')
+        plugin = plugin.strip
+        got = nil
+        Dir.mktmpdir do |tmp_dir|
+          gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1alpha',
+                              'health_services.rb')
+          pid = spawn(
+            'protoc',
+            '-I.',
+            'grpc/health/v1alpha/health.proto',
+            "--grpc_out=#{tmp_dir}",
+            "--plugin=protoc-gen-grpc=#{plugin}",
+            chdir: pb_dir)
+          Process.wait(pid)
+          File.open(gen_out) { |f| got = f.read }
+        end
+        expect(got).to eq(want)
+      end
+    end
+  end
+end
+
+describe Grpc::Health::Checker do
+  StatusCodes = GRPC::Core::StatusCodes
+  ServingStatus = Grpc::Health::V1alpha::HealthCheckResponse::ServingStatus
+  HCResp = Grpc::Health::V1alpha::HealthCheckResponse
+  HCReq = Grpc::Health::V1alpha::HealthCheckRequest
+  success_tests =
+    [
+      {
+        desc: 'neither host or service are specified',
+        host: '',
+        service: ''
+      }, {
+        desc: 'only the host is specified',
+        host: 'test-fake-host',
+        service: ''
+      }, {
+        desc: 'the host and service are specified',
+        host: 'test-fake-host',
+        service: 'fake-service-1'
+      }, {
+        desc: 'only the service is specified',
+        host: '',
+        service: 'fake-service-2'
+      }
+    ]
+
+  context 'initialization' do
+    it 'can be constructed with no args' do
+      expect(subject).to_not be(nil)
+    end
+  end
+
+  context 'method `add_status` and `check`' do
+    success_tests.each do |t|
+      it "should succeed when #{t[:desc]}" do
+        subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING)
+        got = subject.check(HCReq.new(host: t[:host], service: t[:service]),
+                            nil)
+        want = HCResp.new(status: ServingStatus::NOT_SERVING)
+        expect(got).to eq(want)
+      end
+    end
+  end
+
+  context 'method `check`' do
+    success_tests.each do |t|
+      it "should fail with NOT_FOUND when #{t[:desc]}" do
+        blk = proc do
+          subject.check(HCReq.new(host: t[:host], service: t[:service]), nil)
+        end
+        expected_msg = /#{StatusCodes::NOT_FOUND}/
+        expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+      end
+    end
+  end
+
+  context 'method `clear_status`' do
+    success_tests.each do |t|
+      it "should fail after clearing status when #{t[:desc]}" do
+        subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING)
+        got = subject.check(HCReq.new(host: t[:host], service: t[:service]),
+                            nil)
+        want = HCResp.new(status: ServingStatus::NOT_SERVING)
+        expect(got).to eq(want)
+
+        subject.clear_status(t[:host], t[:service])
+        blk = proc do
+          subject.check(HCReq.new(host: t[:host], service: t[:service]),
+                        nil)
+        end
+        expected_msg = /#{StatusCodes::NOT_FOUND}/
+        expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+      end
+    end
+  end
+
+  context 'method `clear_all`' do
+    it 'should return NOT_FOUND after being invoked' do
+      success_tests.each do |t|
+        subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING)
+        got = subject.check(HCReq.new(host: t[:host], service: t[:service]),
+                            nil)
+        want = HCResp.new(status: ServingStatus::NOT_SERVING)
+        expect(got).to eq(want)
+      end
+
+      subject.clear_all
+
+      success_tests.each do |t|
+        blk = proc do
+          subject.check(HCReq.new(host: t[:host], service: t[:service]), nil)
+        end
+        expected_msg = /#{StatusCodes::NOT_FOUND}/
+        expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+      end
+    end
+  end
+
+  describe 'running on RpcServer' do
+    RpcServer = GRPC::RpcServer
+    StatusCodes = GRPC::Core::StatusCodes
+    CheckerStub = Grpc::Health::Checker.rpc_stub_class
+
+    before(:each) do
+      @server_queue = GRPC::Core::CompletionQueue.new
+      server_host = '0.0.0.0:0'
+      @server = GRPC::Core::Server.new(@server_queue, nil)
+      server_port = @server.add_http2_port(server_host)
+      @host = "localhost:#{server_port}"
+      @ch = GRPC::Core::Channel.new(@host, nil)
+      @client_opts = { channel_override: @ch }
+      server_opts = {
+        server_override: @server,
+        completion_queue_override: @server_queue,
+        poll_period: 1
+      }
+      @srv = RpcServer.new(**server_opts)
+    end
+
+    after(:each) do
+      @srv.stop
+    end
+
+    it 'should receive the correct status', server: true do
+      @srv.handle(subject)
+      subject.add_status('', '', ServingStatus::NOT_SERVING)
+      t = Thread.new { @srv.run }
+      @srv.wait_till_running
+
+      stub = CheckerStub.new(@host, **@client_opts)
+      got = stub.check(HCReq.new)
+      want = HCResp.new(status: ServingStatus::NOT_SERVING)
+      expect(got).to eq(want)
+      @srv.stop
+      t.join
+    end
+
+    it 'should fail on unknown services', server: true do
+      @srv.handle(subject)
+      t = Thread.new { @srv.run }
+      @srv.wait_till_running
+      blk = proc do
+        stub = CheckerStub.new(@host, **@client_opts)
+        stub.check(HCReq.new(host: 'unknown', service: 'unknown'))
+      end
+      expected_msg = /#{StatusCodes::NOT_FOUND}/
+      expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+      @srv.stop
+      t.join
+    end
+  end
+end
diff --git a/src/ruby/spec/spec_helper.rb b/src/ruby/spec/spec_helper.rb
index 270d2e9..c891c1b 100644
--- a/src/ruby/spec/spec_helper.rb
+++ b/src/ruby/spec/spec_helper.rb
@@ -47,11 +47,23 @@
 require 'logging'
 require 'rspec/logging_helper'
 
+# GRPC is the general RPC module
+#
+# Configure its logging for fine-grained log control during test runs
+module GRPC
+  extend Logging.globally
+end
+Logging.logger.root.appenders = Logging.appenders.stdout
+Logging.logger.root.level = :info
+Logging.logger['GRPC'].level = :info
+Logging.logger['GRPC::ActiveCall'].level = :info
+Logging.logger['GRPC::BidiCall'].level = :info
+
 # Configure RSpec to capture log messages for each test. The output from the
 # logs will be stored in the @log_output variable. It is a StringIO instance.
 RSpec.configure do |config|
   include RSpec::LoggingHelper
-  config.capture_log_messages
+  config.capture_log_messages  # comment this out to see logs during test runs
 end
 
 RSpec::Expectations.configuration.warn_about_potential_false_positives = false
diff --git a/templates/BUILD.template b/templates/BUILD.template
index 4e9d8c3..8b565a0 100644
--- a/templates/BUILD.template
+++ b/templates/BUILD.template
@@ -49,6 +49,8 @@
     deps.append("//external:protobuf_compiler")
   if target_dict['name'] == 'grpc++_unsecure' or target_dict['name'] == 'grpc++':
     deps.append("//external:protobuf_clib")
+  elif target_dict['name'] == 'grpc':
+    deps.append("//external:zlib")
   for d in target_dict.get('deps', []):
     if d.find('//') == 0 or d[0] == ':':
       deps.append(d)
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 6530ea5..1b898ef 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -436,6 +436,7 @@
 PROTOC_CHECK_VERSION_CMD = protoc --version | grep -q libprotoc.3
 DTRACE_CHECK_CMD = which dtrace > /dev/null
 SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
+ZOOKEEPER_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zookeeper.c $(LDFLAGS) -lzookeeper_mt
 
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
 HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
@@ -503,6 +504,8 @@
 CACHE_MK += HAS_SYSTEMTAP = true,
 endif
 
+HAS_ZOOKEEPER = $(shell $(ZOOKEEPER_CHECK_CMD) 2> /dev/null && echo true || echo false)
+
 # Note that for testing purposes, one can do:
 #   make HAS_EMBEDDED_OPENSSL_ALPN=false
 # to emulate the fact we do not have OpenSSL in the third_party folder.
@@ -621,6 +624,14 @@
 PC_LIB = -lgrpc
 GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
 
+# gprc_zookeeper .pc file
+PC_NAME = gRPC zookeeper
+PC_DESCRIPTION = gRPC's zookeeper plugin
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE =
+PC_LIBS_PRIVATE = -lzookeeper_mt
+GRPC_ZOOKEEPER_PC_FILE := $(PC_TEMPLATE)
+
 PROTOBUF_PKG_CONFIG = false
 
 PC_REQUIRES_GRPCXX =
@@ -813,6 +824,7 @@
 	$(PERFTOOLS_CHECK_CMD) || true
 	$(PROTOBUF_CHECK_CMD) || true
 	$(PROTOC_CHECK_VERSION_CMD) || true
+	$(ZOOKEEPER_CHECK_CMD) || true
 
 $(LIBDIR)/$(CONFIG)/zlib/libz.a:
 	$(E) "[MAKE]    Building zlib"
@@ -871,12 +883,13 @@
 
 static: static_c static_cxx
 
-static_c: pc_c pc_c_unsecure cache.mk \
+static_c: pc_c pc_c_unsecure cache.mk pc_gpr pc_c_zookeeper\
 % for lib in libs:
-% if lib.build == 'all' and lib.language == 'c':
+% if lib.build == 'all' and lib.language == 'c' and not lib.get('external_deps', None):
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
 % endif
 % endfor
+ static_zookeeper_libs
 
 
 static_cxx: pc_cxx pc_cxx_unsecure pc_gpr cache.mk \
@@ -889,13 +902,13 @@
 
 shared: shared_c shared_cxx
 
-shared_c: pc_c pc_c_unsecure pc_gpr  cache.mk\
+shared_c: pc_c pc_c_unsecure pc_gpr cache.mk pc_c_zookeeper\
 % for lib in libs:
-% if lib.build == 'all' and lib.language == 'c':
+% if lib.build == 'all' and lib.language == 'c' and not lib.get('external_deps', None):
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
 % endif
 % endfor
-
+ shared_zookeeper_libs
 
 shared_cxx: pc_cxx pc_cxx_unsecure cache.mk\
 % for lib in libs:
@@ -912,6 +925,29 @@
 % endif
 % endfor
 
+ifeq ($(HAS_ZOOKEEPER),true)
+static_zookeeper_libs:\
+% for lib in libs:
+% if lib.build == 'all' and lib.language == 'c' and 'zookeeper' in lib.get('external_deps', []):
+ $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
+% endif
+% endfor
+
+shared_zookeeper_libs:\
+% for lib in libs:
+% if lib.build == 'all' and lib.language == 'c' and 'zookeeper' in lib.get('external_deps', []):
+ $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
+% endif
+% endfor
+
+else
+
+static_zookeeper_libs:
+
+shared_zookeeper_libs:
+
+endif
+
 grpc_csharp_ext: shared_csharp
 
 plugins: $(PROTOC_PLUGINS)
@@ -920,7 +956,7 @@
 
 privatelibs_c: \
 % for lib in libs:
-% if lib.build == 'private' and lib.language == 'c':
+% if lib.build == 'private' and lib.language == 'c' and not lib.get('external_deps', None):
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
 % endif
 % endfor
@@ -931,43 +967,75 @@
 
 pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
 
+ifeq ($(HAS_ZOOKEEPER),true)
+pc_c_zookeeper: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_zookeeper.pc
+else
+pc_c_zookeeper:
+endif
+
 pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
 
 pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 privatelibs_cxx: \
 % for lib in libs:
-% if lib.build == 'private' and lib.language == 'c++':
+% if lib.build == 'private' and lib.language == 'c++' and not lib.get('external_deps', None):
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
 % endif
 % endfor
 
 
-buildtests: buildtests_c buildtests_cxx
+ifeq ($(HAS_ZOOKEEPER),true)
+privatelibs_zookeeper: \
+% for lib in libs:
+% if lib.build == 'private' and lib.language == 'c++' and zookeeper in lib.get('external_deps', []):
+ $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
+% endif
+% endfor
+
+else
+privatelibs_zookeeper:
+endif
+
+
+buildtests: buildtests_c buildtests_cxx buildtests_zookeeper
 
 buildtests_c: privatelibs_c\
 % for tgt in targets:
-% if tgt.build == 'test' and not tgt.language == 'c++':
+% if tgt.build == 'test' and not tgt.language == 'c++' and not tgt.get('external_deps', None):
  $(BINDIR)/$(CONFIG)/${tgt.name}\
 % endif
 % endfor
 
 
-buildtests_cxx: privatelibs_cxx\
+buildtests_cxx: buildtests_zookeeper privatelibs_cxx\
 % for tgt in targets:
-% if tgt.build == 'test' and tgt.language == 'c++':
+% if tgt.build == 'test' and tgt.language == 'c++' and not tgt.get('external_deps', None):
  $(BINDIR)/$(CONFIG)/${tgt.name}\
 % endif
 % endfor
 
 
-test: test_c test_cxx
+ifeq ($(HAS_ZOOKEEPER),true)
+buildtests_zookeeper: privatelibs_zookeeper\
+% for tgt in targets:
+% if tgt.build == 'test' and tgt.language == 'c++' and 'zookeeper' in tgt.get('external_deps', []):
+ $(BINDIR)/$(CONFIG)/${tgt.name}\
+% endif
+% endfor
 
-flaky_test: flaky_test_c flaky_test_cxx
+else
+buildtests_zookeeper:
+endif
+
+
+test: test_c test_cxx test_zookeeper
+
+flaky_test: flaky_test_c flaky_test_cxx flaky_test_zookeeper
 
 test_c: buildtests_c
 % for tgt in targets:
-% if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++' and not tgt.get('flaky', False):
+% if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++' and not tgt.get('flaky', False) and not tgt.get('external_deps', None):
 	$(E) "[RUN]     Testing ${tgt.name}"
 	$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
 % endif
@@ -976,16 +1044,16 @@
 
 flaky_test_c: buildtests_c
 % for tgt in targets:
-% if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++' and tgt.get('flaky', False):
+% if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++' and tgt.get('flaky', False) and not tgt.get('external_deps', None):
 	$(E) "[RUN]     Testing ${tgt.name}"
 	$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
 % endif
 % endfor
 
 
-test_cxx: buildtests_cxx
+test_cxx: test_zookeeper buildtests_cxx
 % for tgt in targets:
-% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and not tgt.get('flaky', False):
+% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and not tgt.get('flaky', False) and not tgt.get('external_deps', None):
 	$(E) "[RUN]     Testing ${tgt.name}"
 	$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
 % endif
@@ -994,13 +1062,37 @@
 
 flaky_test_cxx: buildtests_cxx
 % for tgt in targets:
-% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and tgt.get('flaky', False):
+% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and tgt.get('flaky', False) and not tgt.get('external_deps', None):
 	$(E) "[RUN]     Testing ${tgt.name}"
 	$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
 % endif
 % endfor
 
 
+ifeq ($(HAS_ZOOKEEPER),true)
+test_zookeeper: buildtests_zookeeper
+% for tgt in targets:
+% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and not tgt.get('flaky', False) and 'zookeeper' in tgt.get('external_deps', []):
+	$(E) "[RUN]     Testing ${tgt.name}"
+	$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
+% endif
+% endfor
+
+
+flaky_test_zookeeper: buildtests_zookeeper
+% for tgt in targets:
+% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and tgt.get('flaky', False) and 'zookeeper' in tgt.get('external_deps', []):
+	$(E) "[RUN]     Testing ${tgt.name}"
+	$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
+% endif
+% endfor
+
+else
+test_zookeeper:
+flaky_test_zookeeper:
+endif
+
+
 test_python: static_c
 	$(E) "[RUN]     Testing python code"
 	$(Q) tools/run_tests/run_tests.py -lpython -c$(CONFIG)
@@ -1051,11 +1143,25 @@
 % for lib in libs:
 % if lib.language == "c":
 % if lib.build == "all":
+% if not lib.get('external_deps', None):
 	$(E) "[STRIP]   Stripping lib${lib.name}.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a
 % endif
 % endif
+% endif
 % endfor
+ifeq ($(HAS_ZOOKEEPER),true)
+% for lib in libs:
+% if lib.language == "c":
+% if lib.build == "all":
+% if 'zookeeper' in lib.get('external_deps', []):
+	$(E) "[STRIP]   Stripping lib${lib.name}.a"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a
+% endif
+% endif
+% endif
+% endfor
+endif
 endif
 
 strip-static_cxx: static_cxx
@@ -1075,11 +1181,25 @@
 % for lib in libs:
 % if lib.language == "c":
 % if lib.build == "all":
+% if not lib.get('external_deps', None):
 	$(E) "[STRIP]   Stripping lib${lib.name}.so"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)
 % endif
 % endif
+% endif
 % endfor
+ifeq ($(HAS_ZOOKEEPER),true)
+% for lib in libs:
+% if lib.language == "c":
+% if lib.build == "all":
+% if 'zookeeper' in lib.get('external_deps', []):
+	$(E) "[STRIP]   Stripping lib${lib.name}.so"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)
+% endif
+% endif
+% endif
+% endfor
+endif
 endif
 
 strip-shared_cxx: shared_cxx
@@ -1125,6 +1245,11 @@
 	$(Q) mkdir -p $(@D)
 	$(Q) echo "$(GRPC_UNSECURE_PC_FILE)" | tr , '\n' >$@
 
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc_zookeeper.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo -e "$(GRPC_ZOOKEEPER_PC_FILE)" >$@
+
 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc:
 	$(E) "[MAKE]    Generating $@"
 	$(Q) mkdir -p $(@D)
@@ -1213,12 +1338,27 @@
 % for lib in libs:
 % if lib.language == "c":
 % if lib.build == "all":
+% if not lib.get('external_deps', None):
 	$(E) "[INSTALL] Installing lib${lib.name}.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(prefix)/lib/lib${lib.name}.a
 % endif
 % endif
+% endif
 % endfor
+ifeq ($(HAS_ZOOKEEPER),true)
+% for lib in libs:
+% if lib.language == "c":
+% if lib.build == "all":
+% if 'zookeeper' in lib.get('external_deps', []):
+	$(E) "[INSTALL] Installing lib${lib.name}.a"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(prefix)/lib/lib${lib.name}.a
+% endif
+% endif
+% endif
+% endfor
+endif
 
 install-static_cxx: static_cxx strip-static_cxx install-pkg-config_cxx
 % for lib in libs:
@@ -1235,6 +1375,7 @@
 % for lib in libs:
 % if lib.language == lang_filter:
 % if lib.build == "all":
+% if not lib.get('external_deps', None):
 ifeq ($(SYSTEM),MINGW32)
 	$(E) "[INSTALL] Installing ${lib.name}.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
@@ -1251,7 +1392,32 @@
 endif
 % endif
 % endif
+% endif
 % endfor
+ifeq ($(HAS_ZOOKEEPER),true)
+% for lib in libs:
+% if lib.language == lang_filter:
+% if lib.build == "all":
+% if 'zookeeper' in lib.get('external_deps', []):
+ifeq ($(SYSTEM),MINGW32)
+	$(E) "[INSTALL] Installing ${lib.name}.$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT) $(prefix)/lib/${lib.name}.$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
+else
+	$(E) "[INSTALL] Installing lib${lib.name}.$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
+	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
+endif
+endif
+% endif
+% endif
+% endif
+% endfor
+endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
 	$(Q) ldconfig || true
@@ -1281,12 +1447,15 @@
 % endfor
 endif
 
-install-pkg-config_c: pc_gpr pc_c pc_c_unsecure
+install-pkg-config_c: pc_gpr pc_c pc_c_unsecure pc_c_zookeeper
 	$(E) "[INSTALL] Installing C pkg-config files"
 	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc $(prefix)/lib/pkgconfig/gpr.pc
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(prefix)/lib/pkgconfig/grpc.pc
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(prefix)/lib/pkgconfig/grpc_unsecure.pc
+ifeq ($(HAS_ZOOKEEPER),true)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_zookeeper.pc $(prefix)/lib/pkgconfig/grpc_zookeeper.pc
+endif
 
 install-pkg-config_cxx: pc_cxx pc_cxx_unsecure
 	$(E) "[INSTALL] Installing C++ pkg-config files"
@@ -1480,6 +1649,9 @@
     for src in lib.src:
       sources_that_don_t_need_openssl.add(src)
 
+  if 'zookeeper' in lib.get('external_deps', []):
+    libs = libs + ' -lzookeeper_mt'
+
   if lib.get('secure', 'check') == 'yes' or lib.get('secure', 'check') == 'check':
     lib_deps = lib_deps + ' $(OPENSSL_DEP)'
     mingw_lib_deps = mingw_lib_deps + ' $(OPENSSL_DEP)'
@@ -1619,6 +1791,9 @@
 % for dep in tgt.deps:
  $(LIBDIR)/$(CONFIG)/lib${dep}.a\
 % endfor
+% if 'zookeeper' in tgt.get('external_deps', []):
+ -lzookeeper_mt\
+% endif
 % if tgt.language == "c++":
 % if tgt.build == 'protoc':
  $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC)\
diff --git a/templates/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.template b/templates/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.template
new file mode 100644
index 0000000..98c5f50
--- /dev/null
+++ b/templates/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="../vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc_test_util_unsecure', libs)}
\ No newline at end of file
diff --git a/include/grpc/support/cancellable_platform.h b/test/build/zookeeper.c
similarity index 68%
copy from include/grpc/support/cancellable_platform.h
copy to test/build/zookeeper.c
index e8e4b84..7cd3d0d 100644
--- a/include/grpc/support/cancellable_platform.h
+++ b/test/build/zookeeper.c
@@ -31,26 +31,13 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_CANCELLABLE_PLATFORM_H
-#define GRPC_SUPPORT_CANCELLABLE_PLATFORM_H
+/* This is just a compilation test, to see if we have Zookeeper C client
+   library installed. */
 
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
+#include <stdlib.h>
+#include <zookeeper/zookeeper.h>
 
-struct gpr_cancellable_list_ {
-  /* a doubly-linked list on cancellable's waiters queue */
-  struct gpr_cancellable_list_ *next;
-  struct gpr_cancellable_list_ *prev;
-  /* The following two fields are arguments to gpr_cv_cancellable_wait() */
-  gpr_mu *mu;
-  gpr_cv *cv;
-};
-
-/* Internal definition of gpr_cancellable. */
-typedef struct {
-  gpr_mu mu; /* protects waiters and modifications to cancelled */
-  gpr_atm cancelled;
-  struct gpr_cancellable_list_ waiters;
-} gpr_cancellable;
-
-#endif  /* GRPC_SUPPORT_CANCELLABLE_PLATFORM_H */
+int main() {
+  zookeeper_init(NULL, NULL, 0, 0, 0, 0);
+  return 0;
+}
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index b050227..f739977 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -102,11 +102,11 @@
 
   /* Create server, completion events */
   a.server = grpc_server_create_from_filters(NULL, 0, NULL);
-  a.cq = grpc_completion_queue_create();
+  a.cq = grpc_completion_queue_create(NULL);
   gpr_event_init(&a.done_thd);
   gpr_event_init(&a.done_write);
   a.validator = validator;
-  grpc_server_register_completion_queue(a.server, a.cq);
+  grpc_server_register_completion_queue(a.server, a.cq, NULL);
   grpc_server_start(a.server);
   transport = grpc_create_chttp2_transport(NULL, sfd.server, mdctx, 0);
   server_setup_transport(&a, transport, mdctx);
@@ -151,7 +151,8 @@
   }
   grpc_server_shutdown_and_notify(a.server, a.cq, NULL);
   GPR_ASSERT(grpc_completion_queue_pluck(a.cq, NULL,
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(a.server);
   grpc_completion_queue_destroy(a.cq);
diff --git a/test/core/bad_client/tests/connection_prefix.c b/test/core/bad_client/tests/connection_prefix.c
index 0bd86ec..de62e92 100644
--- a/test/core/bad_client/tests/connection_prefix.c
+++ b/test/core/bad_client/tests/connection_prefix.c
@@ -37,8 +37,8 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq) {
   while (grpc_server_has_open_connections(server)) {
     GPR_ASSERT(
-        grpc_completion_queue_next(cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20))
-            .type == GRPC_QUEUE_TIMEOUT);
+        grpc_completion_queue_next(cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
+                                   NULL).type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/initial_settings_frame.c b/test/core/bad_client/tests/initial_settings_frame.c
index 2075602..28e9a39 100644
--- a/test/core/bad_client/tests/initial_settings_frame.c
+++ b/test/core/bad_client/tests/initial_settings_frame.c
@@ -39,8 +39,8 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq) {
   while (grpc_server_has_open_connections(server)) {
     GPR_ASSERT(
-        grpc_completion_queue_next(cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20))
-            .type == GRPC_QUEUE_TIMEOUT);
+        grpc_completion_queue_next(cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
+                                   NULL).type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index c28932c..a9ba78d 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -226,7 +226,7 @@
   gpr_strvec_init(&have_tags);
 
   while (v->expect.next != &v->expect) {
-    ev = grpc_completion_queue_next(v->cq, deadline);
+    ev = grpc_completion_queue_next(v->cq, deadline, NULL);
     if (ev.type == GRPC_QUEUE_TIMEOUT) {
       fail_no_event_received(v);
       break;
@@ -265,7 +265,7 @@
 
   GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
 
-  ev = grpc_completion_queue_next(v->cq, deadline);
+  ev = grpc_completion_queue_next(v->cq, deadline, NULL);
   if (ev.type != GRPC_QUEUE_TIMEOUT) {
     char *s = grpc_event_string(&ev);
     gpr_log(GPR_ERROR, "unexpected event (expected nothing): %s", s);
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 48a88be..7b7dbc7 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -53,7 +53,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, ms_from_now(5000));
+    ev = grpc_completion_queue_next(cq, ms_from_now(5000), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -75,6 +75,7 @@
   grpc_metadata_array trailing_metadata_recv;
   grpc_metadata_array request_metadata_recv;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
@@ -93,9 +94,9 @@
   grpc_call_details_init(&call_details);
 
   /* Create server. */
-  cq = grpc_completion_queue_create();
-  server = grpc_server_create(NULL);
-  grpc_server_register_completion_queue(server, cq);
+  cq = grpc_completion_queue_create(NULL);
+  server = grpc_server_create(NULL, NULL);
+  grpc_server_register_completion_queue(server, cq, NULL);
   GPR_ASSERT((got_port = grpc_server_add_insecure_http2_port(
                   server, server_hostport)) > 0);
   if (port == 0) {
@@ -113,7 +114,7 @@
   } else {
     gpr_join_host_port(&client_hostport, client_host, port);
   }
-  client = grpc_insecure_channel_create(client_hostport, NULL);
+  client = grpc_insecure_channel_create(client_hostport, NULL, NULL);
 
   gpr_log(GPR_INFO, "Testing with server=%s client=%s (expecting %s)",
           server_hostport, client_hostport, expect_ok ? "success" : "failure");
@@ -132,20 +133,23 @@
 
   /* Send a trivial request. */
   c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -153,14 +157,16 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   if (expect_ok) {
     /* Check for a successful request. */
-    GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                   server, &s, &call_details,
-                                   &request_metadata_recv, cq, cq, tag(101)));
+    error = grpc_server_request_call(server, &s, &call_details,
+                                     &request_metadata_recv, cq, cq, tag(101));
+    GPR_ASSERT(GRPC_CALL_OK == error);
     cq_expect_completion(cqv, tag(101), 1);
     cq_verify(cqv);
 
@@ -179,8 +185,8 @@
     op->data.recv_close_on_server.cancelled = &was_cancelled;
     op->flags = 0;
     op++;
-    GPR_ASSERT(GRPC_CALL_OK ==
-               grpc_call_start_batch(s, ops, op - ops, tag(102)));
+    error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
 
     cq_expect_completion(cqv, tag(102), 1);
     cq_expect_completion(cqv, tag(1), 1);
@@ -215,7 +221,8 @@
   /* Destroy server. */
   grpc_server_shutdown_and_notify(server, cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(server);
   grpc_completion_queue_shutdown(cq);
diff --git a/test/core/end2end/fixtures/chttp2_fake_security.c b/test/core/end2end/fixtures/chttp2_fake_security.c
index 78b692a..27531ec 100644
--- a/test/core/end2end/fixtures/chttp2_fake_security.c
+++ b/test/core/end2end/fixtures/chttp2_fake_security.c
@@ -60,7 +60,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -89,8 +89,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
                                                server_creds));
   grpc_server_credentials_release(server_creds);
diff --git a/test/core/end2end/fixtures/chttp2_fullstack.c b/test/core/end2end/fixtures/chttp2_fullstack.c
index 53a6f0d..0170dcf 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack.c
@@ -64,7 +64,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -72,7 +72,7 @@
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
   GPR_ASSERT(f->client);
 }
 
@@ -82,8 +82,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
 }
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_compression.c b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
index a75075d..6e7a1fa 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_compression.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
@@ -69,7 +69,7 @@
 
   memset(&f, 0, sizeof(f));
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -83,7 +83,7 @@
   ffd->client_args_compression = grpc_channel_args_set_compression_algorithm(
       client_args, GRPC_COMPRESS_GZIP);
   f->client = grpc_insecure_channel_create(ffd->localaddr,
-                                           ffd->client_args_compression);
+                                           ffd->client_args_compression, NULL);
 }
 
 void chttp2_init_server_fullstack_compression(grpc_end2end_test_fixture *f,
@@ -97,8 +97,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(ffd->server_args_compression);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(ffd->server_args_compression, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
 }
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
index 20afdb8..59d39bb 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
@@ -70,7 +70,7 @@
                unique++);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -78,7 +78,7 @@
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
@@ -87,8 +87,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
 }
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
index 8491ea6..05b9ea0 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
@@ -70,7 +70,7 @@
                unique++);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -78,7 +78,7 @@
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
@@ -87,8 +87,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
 }
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
index 2a4835a..48feefc 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
@@ -64,7 +64,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -72,7 +72,7 @@
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
@@ -81,8 +81,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
 }
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_with_proxy.c b/test/core/end2end/fixtures/chttp2_fullstack_with_proxy.c
index 248cc7d..44083e2 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_with_proxy.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_with_proxy.c
@@ -56,13 +56,13 @@
 } fullstack_fixture_data;
 
 static grpc_server *create_proxy_server(const char *port) {
-  grpc_server *s = grpc_server_create(NULL);
+  grpc_server *s = grpc_server_create(NULL, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(s, port));
   return s;
 }
 
 static grpc_channel *create_proxy_client(const char *target) {
-  return grpc_insecure_channel_create(target, NULL);
+  return grpc_insecure_channel_create(target, NULL, NULL);
 }
 
 static const grpc_end2end_proxy_def proxy_def = {create_proxy_server,
@@ -77,7 +77,7 @@
   ffd->proxy = grpc_end2end_proxy_create(&proxy_def);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -86,7 +86,7 @@
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
   f->client = grpc_insecure_channel_create(
-      grpc_end2end_proxy_get_client_target(ffd->proxy), client_args);
+      grpc_end2end_proxy_get_client_target(ffd->proxy), client_args, NULL);
   GPR_ASSERT(f->client);
 }
 
@@ -96,8 +96,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(
       f->server, grpc_end2end_proxy_get_server_port(ffd->proxy)));
   grpc_server_start(f->server);
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
index 9850aac..491a293 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
@@ -63,7 +63,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -92,8 +92,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
                                                server_creds));
   grpc_server_credentials_release(server_creds);
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c
index 3df2acd..f2736cc 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c
@@ -63,7 +63,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -92,8 +92,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
                                                server_creds));
   grpc_server_credentials_release(server_creds);
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c
index 4d77039..cc0b9db 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c
@@ -54,7 +54,7 @@
 } fullstack_secure_fixture_data;
 
 static grpc_server *create_proxy_server(const char *port) {
-  grpc_server *s = grpc_server_create(NULL);
+  grpc_server *s = grpc_server_create(NULL, NULL);
   grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
                                                   test_server1_cert};
   grpc_server_credentials *ssl_creds =
@@ -91,7 +91,7 @@
   ffd->proxy = grpc_end2end_proxy_create(&proxy_def);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -121,8 +121,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_secure_http2_port(
       f->server, grpc_end2end_proxy_get_server_port(ffd->proxy), server_creds));
   grpc_server_credentials_release(server_creds);
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
index 284d5f0..3c35bae 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
@@ -105,7 +105,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   return f;
 }
@@ -126,8 +126,8 @@
   if (f->server) {
     grpc_server_destroy(f->server);
   }
-  f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
                                                server_creds));
   grpc_server_credentials_release(server_creds);
diff --git a/test/core/end2end/fixtures/chttp2_socket_pair.c b/test/core/end2end/fixtures/chttp2_socket_pair.c
index 807fc8e..16a04fb 100644
--- a/test/core/end2end/fixtures/chttp2_socket_pair.c
+++ b/test/core/end2end/fixtures/chttp2_socket_pair.c
@@ -95,7 +95,7 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
 
@@ -123,7 +123,7 @@
   grpc_transport *transport;
   GPR_ASSERT(!f->server);
   f->server = grpc_server_create_from_filters(NULL, 0, server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
   transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
   server_setup_transport(f, transport, mdctx);
diff --git a/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c b/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c
index 21d4404..94fc36f 100644
--- a/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c
+++ b/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c
@@ -95,7 +95,7 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", 1);
 
@@ -123,7 +123,7 @@
   grpc_transport *transport;
   GPR_ASSERT(!f->server);
   f->server = grpc_server_create_from_filters(NULL, 0, server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
   transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
   server_setup_transport(f, transport, mdctx);
diff --git a/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c b/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c
index 9d798ad..588c4b2 100644
--- a/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c
+++ b/test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c
@@ -96,7 +96,7 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create(NULL);
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
 
@@ -124,7 +124,7 @@
   grpc_transport *transport;
   GPR_ASSERT(!f->server);
   f->server = grpc_server_create_from_filters(NULL, 0, server_args);
-  grpc_server_register_completion_queue(f->server, f->cq);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
   transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
   server_setup_transport(f, transport, mdctx);
diff --git a/test/core/end2end/fixtures/proxy.c b/test/core/end2end/fixtures/proxy.c
index e4f6263..798d4e9 100644
--- a/test/core/end2end/fixtures/proxy.c
+++ b/test/core/end2end/fixtures/proxy.c
@@ -100,11 +100,11 @@
 
   gpr_join_host_port(&proxy->proxy_port, "localhost", proxy_port);
   gpr_join_host_port(&proxy->server_port, "localhost", server_port);
-  proxy->cq = grpc_completion_queue_create();
+  proxy->cq = grpc_completion_queue_create(NULL);
   proxy->server = def->create_server(proxy->proxy_port);
   proxy->client = def->create_client(proxy->server_port);
 
-  grpc_server_register_completion_queue(proxy->server, proxy->cq);
+  grpc_server_register_completion_queue(proxy->server, proxy->cq, NULL);
   grpc_server_start(proxy->server);
 
   gpr_thd_options_set_joinable(&opt);
@@ -178,7 +178,8 @@
     op.data.send_initial_metadata.metadata = pc->p2s_initial_metadata.metadata;
     refpc(pc, "on_c2p_sent_initial_metadata");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
-                                new_closure(on_c2p_sent_initial_metadata, pc));
+                                new_closure(on_c2p_sent_initial_metadata, pc),
+                                NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
   }
 
@@ -204,7 +205,7 @@
     op.data.recv_message = &pc->c2p_msg;
     refpc(pc, "on_c2p_recv_msg");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
-                                new_closure(on_c2p_recv_msg, pc));
+                                new_closure(on_c2p_recv_msg, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
   }
 
@@ -228,14 +229,14 @@
       op.data.send_message = pc->c2p_msg;
       refpc(pc, "on_p2s_sent_message");
       err = grpc_call_start_batch(pc->p2s, &op, 1,
-                                  new_closure(on_p2s_sent_message, pc));
+                                  new_closure(on_p2s_sent_message, pc), NULL);
       GPR_ASSERT(err == GRPC_CALL_OK);
     } else {
       op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
       op.flags = 0;
       refpc(pc, "on_p2s_sent_close");
       err = grpc_call_start_batch(pc->p2s, &op, 1,
-                                  new_closure(on_p2s_sent_close, pc));
+                                  new_closure(on_p2s_sent_close, pc), NULL);
       GPR_ASSERT(err == GRPC_CALL_OK);
     }
   }
@@ -257,7 +258,7 @@
     op.data.recv_message = &pc->p2s_msg;
     refpc(pc, "on_p2s_recv_msg");
     err = grpc_call_start_batch(pc->p2s, &op, 1,
-                                new_closure(on_p2s_recv_msg, pc));
+                                new_closure(on_p2s_recv_msg, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
   }
 
@@ -275,7 +276,7 @@
     op.data.send_message = pc->p2s_msg;
     refpc(pc, "on_c2p_sent_message");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
-                                new_closure(on_c2p_sent_message, pc));
+                                new_closure(on_c2p_sent_message, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
   }
   unrefpc(pc, "on_p2s_recv_msg");
@@ -303,7 +304,7 @@
     op.data.send_status_from_server.status_details = pc->p2s_status_details;
     refpc(pc, "on_c2p_sent_status");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
-                                new_closure(on_c2p_sent_status, pc));
+                                new_closure(on_c2p_sent_status, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
   }
 
@@ -330,7 +331,7 @@
     pc->p2s = grpc_channel_create_call(
         proxy->client, pc->c2p, GRPC_PROPAGATE_DEFAULTS, proxy->cq,
         proxy->new_call_details.method, proxy->new_call_details.host,
-        proxy->new_call_details.deadline);
+        proxy->new_call_details.deadline, NULL);
     gpr_ref_init(&pc->refs, 1);
 
     op.flags = 0;
@@ -339,7 +340,8 @@
     op.data.recv_initial_metadata = &pc->p2s_initial_metadata;
     refpc(pc, "on_p2s_recv_initial_metadata");
     err = grpc_call_start_batch(pc->p2s, &op, 1,
-                                new_closure(on_p2s_recv_initial_metadata, pc));
+                                new_closure(on_p2s_recv_initial_metadata, pc),
+                                NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
 
     op.op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -347,21 +349,22 @@
     op.data.send_initial_metadata.metadata = pc->c2p_initial_metadata.metadata;
     refpc(pc, "on_p2s_sent_initial_metadata");
     err = grpc_call_start_batch(pc->p2s, &op, 1,
-                                new_closure(on_p2s_sent_initial_metadata, pc));
+                                new_closure(on_p2s_sent_initial_metadata, pc),
+                                NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
 
     op.op = GRPC_OP_RECV_MESSAGE;
     op.data.recv_message = &pc->c2p_msg;
     refpc(pc, "on_c2p_recv_msg");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
-                                new_closure(on_c2p_recv_msg, pc));
+                                new_closure(on_c2p_recv_msg, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
 
     op.op = GRPC_OP_RECV_MESSAGE;
     op.data.recv_message = &pc->p2s_msg;
     refpc(pc, "on_p2s_recv_msg");
     err = grpc_call_start_batch(pc->p2s, &op, 1,
-                                new_closure(on_p2s_recv_msg, pc));
+                                new_closure(on_p2s_recv_msg, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
 
     op.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
@@ -372,15 +375,15 @@
     op.data.recv_status_on_client.status_details_capacity =
         &pc->p2s_status_details_capacity;
     refpc(pc, "on_p2s_status");
-    err =
-        grpc_call_start_batch(pc->p2s, &op, 1, new_closure(on_p2s_status, pc));
+    err = grpc_call_start_batch(pc->p2s, &op, 1,
+                                new_closure(on_p2s_status, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
 
     op.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
     op.data.recv_close_on_server.cancelled = &pc->c2p_server_cancelled;
     refpc(pc, "on_c2p_closed");
-    err =
-        grpc_call_start_batch(pc->c2p, &op, 1, new_closure(on_c2p_closed, pc));
+    err = grpc_call_start_batch(pc->c2p, &op, 1,
+                                new_closure(on_c2p_closed, pc), NULL);
     GPR_ASSERT(err == GRPC_CALL_OK);
 
     request_call(proxy);
@@ -405,7 +408,7 @@
   closure *cl;
   for (;;) {
     grpc_event ev = grpc_completion_queue_next(
-        proxy->cq, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+        proxy->cq, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL);
     switch (ev.type) {
       case GRPC_QUEUE_TIMEOUT:
         gpr_log(GPR_ERROR, "Should never reach here");
diff --git a/test/core/end2end/multiple_server_queues_test.c b/test/core/end2end/multiple_server_queues_test.c
index 7772d14..2befcd0 100644
--- a/test/core/end2end/multiple_server_queues_test.c
+++ b/test/core/end2end/multiple_server_queues_test.c
@@ -41,20 +41,20 @@
 
   grpc_test_init(argc, argv);
   grpc_init();
-  cq1 = grpc_completion_queue_create();
-  cq2 = grpc_completion_queue_create();
-  server = grpc_server_create(NULL);
-  grpc_server_register_completion_queue(server, cq1);
+  cq1 = grpc_completion_queue_create(NULL);
+  cq2 = grpc_completion_queue_create(NULL);
+  server = grpc_server_create(NULL, NULL);
+  grpc_server_register_completion_queue(server, cq1, NULL);
   grpc_server_add_insecure_http2_port(server, "[::]:0");
-  grpc_server_register_completion_queue(server, cq2);
+  grpc_server_register_completion_queue(server, cq2, NULL);
   grpc_server_start(server);
   grpc_server_shutdown_and_notify(server, cq2, NULL);
   grpc_completion_queue_next(
-      cq2, gpr_inf_future(GPR_CLOCK_REALTIME)); /* cue queue hang */
+      cq2, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); /* cue queue hang */
   grpc_completion_queue_shutdown(cq1);
   grpc_completion_queue_shutdown(cq2);
-  grpc_completion_queue_next(cq1, gpr_inf_future(GPR_CLOCK_REALTIME));
-  grpc_completion_queue_next(cq2, gpr_inf_future(GPR_CLOCK_REALTIME));
+  grpc_completion_queue_next(cq1, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  grpc_completion_queue_next(cq2, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   grpc_server_destroy(server);
   grpc_completion_queue_destroy(cq1);
   grpc_completion_queue_destroy(cq2);
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 6a5e123..6ae8728 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -57,18 +57,19 @@
 
   grpc_metadata_array_init(&trailing_metadata_recv);
 
-  cq = grpc_completion_queue_create();
+  cq = grpc_completion_queue_create(NULL);
   cqv = cq_verifier_create(cq);
 
   /* create a call, channel to a non existant server */
-  chan = grpc_insecure_channel_create("nonexistant:54321", NULL);
+  chan = grpc_insecure_channel_create("nonexistant:54321", NULL, NULL);
   call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
-                                  "/Foo", "nonexistant", deadline);
+                                  "/Foo", "nonexistant", deadline, NULL);
 
   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_STATUS_ON_CLIENT;
   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
@@ -76,9 +77,10 @@
   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++;
   GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, ops, op - ops, tag(1)));
+             grpc_call_start_batch(call, ops, op - ops, tag(1), NULL));
   /* verify that all tags get completed */
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
@@ -86,8 +88,8 @@
   GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
 
   grpc_completion_queue_shutdown(cq);
-  while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME))
-             .type != GRPC_QUEUE_SHUTDOWN)
+  while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                    NULL).type != GRPC_QUEUE_SHUTDOWN)
     ;
   grpc_completion_queue_destroy(cq);
   grpc_call_destroy(call);
diff --git a/test/core/end2end/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c
index 198ba46..61bbbe4 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -110,11 +111,12 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "slartibartfast.local", deadline);
+                               "/foo", "slartibartfast.local", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -126,13 +128,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -140,13 +145,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
 
-  GPR_ASSERT(status == GRPC_STATUS_UNAUTHENTICATED);
+  GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index 2e166b8..3715166 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -69,7 +69,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -77,7 +77,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -114,6 +115,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   grpc_byte_buffer *request_payload_recv = NULL;
@@ -127,7 +129,7 @@
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -142,28 +144,34 @@
   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++;
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   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_MESSAGE;
   op->data.recv_message = &response_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(2)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq, tag(2));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(2), 1);
   cq_verify(cqv);
 
@@ -171,22 +179,27 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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_SEND_MESSAGE;
   op->data.send_message = response_payload;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(3)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(3), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
+  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
   cq_expect_completion(cqv, tag(3), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c b/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
index 171c187..ffb267c 100644
--- a/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
+++ b/test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
@@ -69,7 +69,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -77,7 +77,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -114,6 +115,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   grpc_byte_buffer *request_payload_recv = NULL;
@@ -127,7 +129,7 @@
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -142,31 +144,38 @@
   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++;
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(2)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq, tag(2));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(2), 1);
   cq_verify(cqv);
 
@@ -174,22 +183,27 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   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++;
   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_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(3)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(3), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
+  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
   cq_expect_completion(cqv, tag(3), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index 186cd44..7e984da 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -114,6 +115,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   grpc_byte_buffer *response_payload_recv = NULL;
@@ -122,7 +124,7 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -137,29 +139,36 @@
   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++;
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, test_ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, test_ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
+  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index b511908..06e6602 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -112,6 +113,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   grpc_byte_buffer *response_payload_recv = NULL;
@@ -120,10 +122,10 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c, NULL));
 
   grpc_metadata_array_init(&initial_metadata_recv);
   grpc_metadata_array_init(&trailing_metadata_recv);
@@ -137,27 +139,34 @@
   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++;
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, test_ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, test_ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index 7645410..f57a44c 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -69,7 +69,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -77,7 +77,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -108,10 +109,10 @@
   cq_verifier *v_client = cq_verifier_create(f.cq);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
-  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
+  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
   grpc_call_destroy(c);
 
diff --git a/test/core/end2end/tests/cancel_test_helpers.h b/test/core/end2end/tests/cancel_test_helpers.h
index 8345c07..6ea822f 100644
--- a/test/core/end2end/tests/cancel_test_helpers.h
+++ b/test/core/end2end/tests/cancel_test_helpers.h
@@ -36,12 +36,13 @@
 
 typedef struct {
   const char *name;
-  grpc_call_error (*initiate_cancel)(grpc_call *call);
+  grpc_call_error (*initiate_cancel)(grpc_call *call, void *reserved);
   grpc_status_code expect_status;
   const char *expect_details;
 } cancellation_mode;
 
-static grpc_call_error wait_for_deadline(grpc_call *call) {
+static grpc_call_error wait_for_deadline(grpc_call *call, void *reserved) {
+  (void) reserved;
   return GRPC_CALL_OK;
 }
 
diff --git a/test/core/end2end/tests/census_simple_request.c b/test/core/end2end/tests/census_simple_request.c
index 2142dde..8f615de 100644
--- a/test/core/end2end/tests/census_simple_request.c
+++ b/test/core/end2end/tests/census_simple_request.c
@@ -67,7 +67,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -82,7 +83,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, n_seconds_time(5));
+    ev = grpc_completion_queue_next(cq, n_seconds_time(5), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -107,12 +108,14 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -124,13 +127,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -138,12 +144,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -151,18 +160,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index 920449f..5cbf26b 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -111,13 +112,14 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
   char *peer;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", NULL, deadline);
+                               "/foo", NULL, deadline, NULL);
   GPR_ASSERT(c);
 
   peer = grpc_call_get_peer(c);
@@ -149,11 +151,13 @@
   op->data.recv_status_on_client.status_details_capacity = &details_capacity;
   op->flags = 0;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(error == GRPC_CALL_OK);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(error == GRPC_CALL_OK);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -181,7 +185,8 @@
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(error == GRPC_CALL_OK);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c
index 94bed33..0b98424 100644
--- a/test/core/end2end/tests/disappearing_server.c
+++ b/test/core/end2end/tests/disappearing_server.c
@@ -56,7 +56,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -93,12 +93,14 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -110,13 +112,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -124,13 +129,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, &s,
-                                                      &call_details,
-                                                      &request_metadata_recv,
-                                                      f->cq, f->cq, tag(101)));
+  error = grpc_server_request_call(f->server, &s, &call_details,
+                                   &request_metadata_recv, f->cq, f->cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -142,18 +149,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c b/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
index 36cbe80..a568312 100644
--- a/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
+++ b/test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -101,12 +101,13 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -119,13 +120,16 @@
   op->data.send_initial_metadata.count = 0;
   op->data.send_initial_metadata.metadata = NULL;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -133,12 +137,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -146,8 +153,10 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* shutdown and destroy the server */
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(1000));
diff --git a/test/core/end2end/tests/early_server_shutdown_finishes_tags.c b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
index fc03cb0..9b678a1 100644
--- a/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
+++ b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index 138c6b0..feb2f18 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -103,13 +104,15 @@
   grpc_call *c;
   gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_call_error error;
   grpc_op *op = NULL;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, op, 0, tag(1)));
+  error = grpc_call_start_batch(c, op, 0, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
 
diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c
index 23efa03..9ec9430 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.c
+++ b/test/core/end2end/tests/graceful_server_shutdown.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -108,12 +108,13 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -126,13 +127,16 @@
   op->data.send_initial_metadata.count = 0;
   op->data.send_initial_metadata.metadata = NULL;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -140,12 +144,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -157,18 +164,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(0xdead), 1);
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index e32645e..5fe369e 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -66,7 +66,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, n_seconds_time(5));
+    ev = grpc_completion_queue_next(cq, n_seconds_time(5), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -74,7 +74,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -124,12 +125,13 @@
   grpc_byte_buffer *response_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -141,21 +143,26 @@
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_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;
@@ -163,12 +170,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -176,12 +186,15 @@
   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_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -190,18 +203,22 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index 049c028..203d98d 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -109,12 +110,14 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -126,13 +129,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -140,12 +146,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -153,18 +162,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
@@ -207,6 +220,7 @@
   grpc_metadata_array initial_metadata_recv2;
   grpc_metadata_array trailing_metadata_recv2;
   grpc_status_code status1;
+  grpc_call_error error;
   char *details1 = NULL;
   size_t details_capacity1 = 0;
   grpc_status_code status2;
@@ -245,10 +259,12 @@
      the first completes */
   deadline = n_seconds_time(1000);
   c1 = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                                "/alpha", "foo.test.google.fr:1234", deadline);
+                                "/alpha", "foo.test.google.fr:1234", deadline,
+                                NULL);
   GPR_ASSERT(c1);
   c2 = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                                "/beta", "foo.test.google.fr:1234", deadline);
+                                "/beta", "foo.test.google.fr:1234", deadline,
+                                NULL);
   GPR_ASSERT(c2);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -259,12 +275,14 @@
   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_SEND_CLOSE_FROM_CLIENT;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(c1, ops, op - ops, tag(301)));
+  error = grpc_call_start_batch(c1, ops, op - ops, tag(301), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   op = ops;
   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
@@ -273,24 +291,28 @@
   op->data.recv_status_on_client.status_details = &details1;
   op->data.recv_status_on_client.status_details_capacity = &details_capacity1;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
   op->data.recv_initial_metadata = &initial_metadata_recv1;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(c1, ops, op - ops, tag(302)));
+  error = grpc_call_start_batch(c1, ops, op - ops, tag(302), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   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_SEND_CLOSE_FROM_CLIENT;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(c2, ops, op - ops, tag(401)));
+  error = grpc_call_start_batch(c2, ops, op - ops, tag(401), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   op = ops;
   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
@@ -299,19 +321,22 @@
   op->data.recv_status_on_client.status_details = &details2;
   op->data.recv_status_on_client.status_details_capacity = &details_capacity2;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
   op->data.recv_initial_metadata = &initial_metadata_recv1;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(c2, ops, op - ops, tag(402)));
+  error = grpc_call_start_batch(c2, ops, op - ops, tag(402), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   got_client_start = 0;
   got_server_start = 0;
   live_call = -1;
   while (!got_client_start || !got_server_start) {
-    ev = grpc_completion_queue_next(f.cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3));
+    ev = grpc_completion_queue_next(f.cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3),
+                                    NULL);
     GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
     GPR_ASSERT(ev.success);
     if (ev.tag == tag(101)) {
@@ -334,19 +359,22 @@
   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++;
   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_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(s1, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s1, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(live_call + 2), 1);
@@ -365,19 +393,22 @@
   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++;
   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_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(s2, ops, op - ops, tag(202)));
+  error = grpc_call_start_batch(s2, ops, op - ops, tag(202), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(live_call + 2), 1);
   cq_expect_completion(cqv, tag(202), 1);
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index feea49c..dd30e68 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -114,6 +115,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
@@ -130,7 +132,7 @@
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
                                "/foo", "foo.test.google.fr:1234",
-                               gpr_inf_future(GPR_CLOCK_REALTIME));
+                               gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -142,17 +144,21 @@
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -160,12 +166,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -173,8 +182,10 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
index 8ead664..565d4ea 100644
--- a/test/core/end2end/tests/no_op.c
+++ b/test/core/end2end/tests/no_op.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index 0ae611b..e19f115 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -113,6 +114,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
@@ -125,7 +127,8 @@
   gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -137,10 +140,12 @@
   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;
@@ -148,12 +153,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(100)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(100));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(100), 1);
   cq_verify(cqv);
 
@@ -161,12 +169,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(101)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(101), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   for (i = 0; i < messages; i++) {
     request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
@@ -176,20 +187,24 @@
     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++;
-    GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(2)));
+    error = grpc_call_start_batch(c, ops, op - ops, tag(2), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
 
     op = ops;
     op->op = GRPC_OP_RECV_MESSAGE;
     op->data.recv_message = &request_payload_recv;
     op->flags = 0;
+    op->reserved = NULL;
     op++;
-    GPR_ASSERT(GRPC_CALL_OK ==
-               grpc_call_start_batch(s, ops, op - ops, tag(102)));
+    error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
     cq_expect_completion(cqv, tag(102), 1);
     cq_verify(cqv);
 
@@ -197,9 +212,10 @@
     op->op = GRPC_OP_SEND_MESSAGE;
     op->data.send_message = response_payload;
     op->flags = 0;
+    op->reserved = NULL;
     op++;
-    GPR_ASSERT(GRPC_CALL_OK ==
-               grpc_call_start_batch(s, ops, op - ops, tag(103)));
+    error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
     cq_expect_completion(cqv, tag(103), 1);
     cq_expect_completion(cqv, tag(2), 1);
     cq_verify(cqv);
@@ -216,8 +232,10 @@
   op = ops;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(3)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(3), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   op = ops;
   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
@@ -225,8 +243,10 @@
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(104)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(104), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(1), 1);
   cq_expect_completion(cqv, tag(3), 1);
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index ffc4cd4..1ef595e 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -111,12 +112,13 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_registered_call(
-      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, rc, deadline);
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, rc, deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -128,13 +130,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -142,12 +147,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -155,18 +163,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
@@ -194,7 +206,8 @@
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_simple_request", NULL, NULL);
   void *rc =
-      grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234");
+      grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234",
+                                 NULL);
 
   simple_request_body(f, rc);
   end_test(&f);
@@ -206,7 +219,8 @@
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
   void *rc =
-      grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234");
+      grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234",
+                                 NULL);
 
   for (i = 0; i < 10; i++) {
     simple_request_body(f, rc);
diff --git a/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
index 600642e..de6f460 100644
--- a/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -113,20 +114,24 @@
       {"key1-bin",
        "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc",
        13,
-       {{NULL, NULL, NULL}}},
+       0,
+       {{NULL, NULL, NULL, NULL}}},
       {"key2-bin",
        "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d",
        14,
-       {{NULL, NULL, NULL}}}};
+       0,
+       {{NULL, NULL, NULL, NULL}}}};
   grpc_metadata meta_s[2] = {
       {"key3-bin",
        "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee",
        15,
-       {{NULL, NULL, NULL}}},
+       0,
+       {{NULL, NULL, NULL, NULL}}},
       {"key4-bin",
        "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
        16,
-       {{NULL, NULL, NULL}}}};
+       0,
+       {{NULL, NULL, NULL, NULL}}}};
   grpc_end2end_test_fixture f = begin_test(
       config, "test_request_response_with_metadata_and_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -139,12 +144,13 @@
   grpc_byte_buffer *response_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -157,21 +163,26 @@
   op->data.send_initial_metadata.count = 2;
   op->data.send_initial_metadata.metadata = meta_c;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_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;
@@ -179,12 +190,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -193,12 +207,15 @@
   op->data.send_initial_metadata.count = 2;
   op->data.send_initial_metadata.metadata = meta_s;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -207,18 +224,22 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/request_response_with_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
index 7e8cce1..b6196ab 100644
--- a/test/core/end2end/tests/request_response_with_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -109,10 +110,10 @@
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   gpr_timespec deadline = five_seconds_time();
-  grpc_metadata meta_c[2] = {{"key1", "val1", 4, {{NULL, NULL, NULL}}},
-                             {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
-  grpc_metadata meta_s[2] = {{"KeY3", "val3", 4, {{NULL, NULL, NULL}}},
-                             {"KeY4", "val4", 4, {{NULL, NULL, NULL}}}};
+  grpc_metadata meta_c[2] = {{"key1", "val1", 4, 0, {{NULL, NULL, NULL, NULL}}},
+                             {"key2", "val2", 4, 0, {{NULL, NULL, NULL, NULL}}}};
+  grpc_metadata meta_s[2] = {{"KeY3", "val3", 4, 0, {{NULL, NULL, NULL, NULL}}},
+                             {"KeY4", "val4", 4, 0, {{NULL, NULL, NULL, NULL}}}};
   grpc_end2end_test_fixture f = begin_test(
       config, "test_request_response_with_metadata_and_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -125,12 +126,13 @@
   grpc_byte_buffer *response_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -143,21 +145,26 @@
   op->data.send_initial_metadata.count = 2;
   op->data.send_initial_metadata.metadata = meta_c;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_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;
@@ -165,12 +172,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -179,12 +189,15 @@
   op->data.send_initial_metadata.count = 2;
   op->data.send_initial_metadata.metadata = meta_s;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -193,18 +206,22 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/request_response_with_payload.c b/test/core/end2end/tests/request_response_with_payload.c
index 5532389..0a45a48 100644
--- a/test/core/end2end/tests/request_response_with_payload.c
+++ b/test/core/end2end/tests/request_response_with_payload.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -117,12 +118,13 @@
   grpc_byte_buffer *response_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -134,21 +136,26 @@
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_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;
@@ -156,12 +163,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -169,12 +179,15 @@
   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_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -183,18 +196,22 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c
index 342dfa0..8e0bc4e 100644
--- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c
+++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c
@@ -86,7 +86,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -94,7 +94,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -139,7 +140,7 @@
       begin_test(config, "test_call_creds_failure", 0);
   gpr_timespec deadline = five_seconds_time();
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   /* Try with credentials unfit to be set on a call (channel creds). */
@@ -176,6 +177,7 @@
   grpc_byte_buffer *response_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
@@ -187,7 +189,7 @@
   cqv = cq_verifier_create(f.cq);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
   creds = grpc_iam_credentials_create(iam_token, iam_selector);
   GPR_ASSERT(creds != NULL);
@@ -217,21 +219,26 @@
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_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;
@@ -239,12 +246,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
   s_auth_context = grpc_call_auth_context(s);
@@ -264,12 +274,15 @@
   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_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -278,18 +291,22 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
@@ -389,6 +406,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   grpc_byte_buffer *response_payload_recv = NULL;
@@ -401,7 +419,7 @@
   cqv = cq_verifier_create(f.cq);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   creds = grpc_iam_credentials_create(iam_token, iam_selector);
@@ -441,7 +459,8 @@
   op->data.recv_message = &response_payload_recv;
   op->flags = 0;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(error == GRPC_CALL_OK);
 
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
diff --git a/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
index 26be4ef..83744a8 100644
--- a/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -109,12 +110,12 @@
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   gpr_timespec deadline = five_seconds_time();
-  grpc_metadata meta_c[2] = {{"key1", "val1", 4, {{NULL, NULL, NULL}}},
-                             {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
-  grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}},
-                             {"key4", "val4", 4, {{NULL, NULL, NULL}}}};
-  grpc_metadata meta_t[2] = {{"key5", "val5", 4, {{NULL, NULL, NULL}}},
-                             {"key6", "val6", 4, {{NULL, NULL, NULL}}}};
+  grpc_metadata meta_c[2] = {{"key1", "val1", 4, 0, {{NULL, NULL, NULL, NULL}}},
+                             {"key2", "val2", 4, 0, {{NULL, NULL, NULL, NULL}}}};
+  grpc_metadata meta_s[2] = {{"key3", "val3", 4, 0, {{NULL, NULL, NULL, NULL}}},
+                             {"key4", "val4", 4, 0, {{NULL, NULL, NULL, NULL}}}};
+  grpc_metadata meta_t[2] = {{"key5", "val5", 4, 0, {{NULL, NULL, NULL, NULL}}},
+                             {"key6", "val6", 4, 0, {{NULL, NULL, NULL, NULL}}}};
   grpc_end2end_test_fixture f = begin_test(
       config, "test_request_response_with_metadata_and_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -127,12 +128,13 @@
   grpc_byte_buffer *response_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -145,21 +147,26 @@
   op->data.send_initial_metadata.count = 2;
   op->data.send_initial_metadata.metadata = meta_c;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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_MESSAGE;
   op->data.recv_message = &response_payload_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;
@@ -167,12 +174,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -181,12 +191,15 @@
   op->data.send_initial_metadata.count = 2;
   op->data.send_initial_metadata.metadata = meta_s;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -195,10 +208,12 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 2;
@@ -206,8 +221,10 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/request_with_compressed_payload.c b/test/core/end2end/tests/request_with_compressed_payload.c
index 5f7d83c..6a067d8 100644
--- a/test/core/end2end/tests/request_with_compressed_payload.c
+++ b/test/core/end2end/tests/request_with_compressed_payload.c
@@ -72,7 +72,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -80,7 +80,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -123,6 +124,7 @@
   grpc_byte_buffer *request_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
@@ -142,7 +144,7 @@
   cqv = cq_verifier_create(f.cq);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -159,17 +161,21 @@
     op->data.send_initial_metadata.count = 0;
   }
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = send_flags_bitmask;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -177,13 +183,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.cq,
-                                      f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq,
+                                   f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -191,12 +199,15 @@
   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_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -205,14 +216,17 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
@@ -286,12 +300,12 @@
          sizeof(gzip_compression_override.internal_data));
 
   none_compression_override.key = GRPC_COMPRESS_REQUEST_ALGORITHM_KEY;
-  none_compression_override.value = "none";
+  none_compression_override.value = "identity";
   none_compression_override.value_length = 4;
   memset(&none_compression_override.internal_data, 0,
          sizeof(none_compression_override.internal_data));
 
-  /* Channel default NONE, call override to GZIP */
+  /* Channel default NONE (aka IDENTITY), call override to GZIP */
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload_md_override_1", 0,
       GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP, &gzip_compression_override);
@@ -301,7 +315,7 @@
       config, "test_invoke_request_with_compressed_payload_md_override_2", 0,
       GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_GZIP, &gzip_compression_override);
 
-  /* Channel default DEFLATE, call override to NONE */
+  /* Channel default DEFLATE, call override to NONE (aka IDENTITY) */
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload_md_override_3", 0,
       GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_NONE, &none_compression_override);
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index 37c4825..3255f14 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -69,7 +69,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -77,7 +77,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -117,12 +118,13 @@
   grpc_byte_buffer *request_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   grpc_call_error expectation;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -134,17 +136,21 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op->flags = flags_for_op[op->op];
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = flags_for_op[op->op];
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   op->flags = flags_for_op[op->op];
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
   op->data.recv_initial_metadata = &initial_metadata_recv;
   op->flags = flags_for_op[op->op];
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
@@ -152,9 +158,11 @@
   op->data.recv_status_on_client.status_details = &details;
   op->data.recv_status_on_client.status_details_capacity = &details_capacity;
   op->flags = flags_for_op[op->op];
+  op->reserved = NULL;
   op++;
   expectation = call_start_batch_expected_result;
-  GPR_ASSERT(expectation == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(expectation == error);
 
   if (expectation == GRPC_CALL_OK) {
     cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/request_with_large_metadata.c b/test/core/end2end/tests/request_with_large_metadata.c
index 9ea8273..5b43caf 100644
--- a/test/core/end2end/tests/request_with_large_metadata.c
+++ b/test/core/end2end/tests/request_with_large_metadata.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -117,13 +118,14 @@
   grpc_byte_buffer *request_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
   const int large_size = 64 * 1024;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   meta.key = "key";
@@ -142,17 +144,21 @@
   op->data.send_initial_metadata.count = 1;
   op->data.send_initial_metadata.metadata = &meta;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -160,12 +166,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -173,12 +182,15 @@
   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_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -187,14 +199,17 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index 6b5f173..c0013fb 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -68,7 +68,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -76,7 +76,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -116,12 +117,13 @@
   grpc_byte_buffer *request_payload_recv = NULL;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -133,17 +135,21 @@
   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_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -151,8 +157,10 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
                                  f.server, &s, &call_details,
@@ -164,12 +172,15 @@
   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_MESSAGE;
   op->data.recv_message = &request_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_verify(cqv);
@@ -178,14 +189,17 @@
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(103), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index 661c099..ab2f575 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -111,12 +112,14 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -128,10 +131,12 @@
   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;
@@ -139,12 +144,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -152,18 +160,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index 82d2bf9..277aa25 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -56,7 +56,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -64,7 +64,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -101,6 +102,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
@@ -108,7 +110,7 @@
   config.init_client(f, client_args);
 
   c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
-                               "/foo", "foo.test.google.fr", deadline);
+                               "/foo", "foo.test.google.fr", deadline, NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -120,13 +122,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -134,15 +139,17 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   config.init_server(f, server_args);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, &s,
-                                                      &call_details,
-                                                      &request_metadata_recv,
-                                                      f->cq, f->cq, tag(101)));
+  error = grpc_server_request_call(f->server, &s, &call_details,
+                                   &request_metadata_recv, f->cq, f->cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -150,18 +157,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index d60a63e..d3d2f27 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -111,13 +112,15 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
   char *peer;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   peer = grpc_call_get_peer(c);
@@ -134,13 +137,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -148,12 +154,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -170,18 +179,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/simple_request_with_high_initial_sequence_number.c b/test/core/end2end/tests/simple_request_with_high_initial_sequence_number.c
index 2244e22..4fc206c 100644
--- a/test/core/end2end/tests/simple_request_with_high_initial_sequence_number.c
+++ b/test/core/end2end/tests/simple_request_with_high_initial_sequence_number.c
@@ -70,7 +70,7 @@
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time());
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -78,7 +78,8 @@
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
   GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                         NULL)
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
@@ -111,12 +112,14 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline);
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -128,13 +131,16 @@
   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_SEND_CLOSE_FROM_CLIENT;
   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;
@@ -142,12 +148,15 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
-                                 f.server, &s, &call_details,
-                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  error = grpc_server_request_call(f.server, &s, &call_details,
+                                   &request_metadata_recv, f.cq, f.cq,
+                                   tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
   cq_expect_completion(cqv, tag(101), 1);
   cq_verify(cqv);
 
@@ -155,18 +164,22 @@
   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_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   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++;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+  error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   cq_expect_completion(cqv, tag(102), 1);
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index 17b737c..54c9274 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -91,24 +91,25 @@
 static void step_ping_pong_request(void) {
   call = grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
                                   "/Reflector/reflectUnary", "localhost",
-                                  gpr_inf_future(GPR_CLOCK_REALTIME));
+                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, ops, op - ops, (void *)1));
-  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
+             grpc_call_start_batch(call, ops, op - ops, (void *)1, NULL));
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   grpc_call_destroy(call);
   grpc_byte_buffer_destroy(response_payload_recv);
   call = NULL;
 }
 
 static void init_ping_pong_stream(void) {
+  grpc_call_error error;
   call = grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
                                   "/Reflector/reflectStream", "localhost",
-                                  gpr_inf_future(GPR_CLOCK_REALTIME));
+                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   stream_init_op.op = GRPC_OP_SEND_INITIAL_METADATA;
   stream_init_op.data.send_initial_metadata.count = 0;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, &stream_init_op, 1, (void *)1));
-  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
+  error = grpc_call_start_batch(call, &stream_init_op, 1, (void *)1, NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
 
   grpc_metadata_array_init(&initial_metadata_recv);
 
@@ -119,9 +120,10 @@
 }
 
 static void step_ping_pong_stream(void) {
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, stream_step_ops, 2, (void *)1));
-  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
+  grpc_call_error error;
+  error = grpc_call_start_batch(call, stream_step_ops, 2, (void *)1, NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   grpc_byte_buffer_destroy(response_payload_recv);
 }
 
@@ -152,6 +154,7 @@
   int secure = 0;
   char *target = "localhost:443";
   gpr_cmdline *cl;
+  grpc_event event;
   char *scenario_name = "ping-pong-request";
   scenario sc = {NULL, NULL, NULL};
 
@@ -183,8 +186,8 @@
     return 1;
   }
 
-  channel = grpc_insecure_channel_create(target, NULL);
-  cq = grpc_completion_queue_create();
+  channel = grpc_insecure_channel_create(target, NULL, NULL);
+  cq = grpc_completion_queue_create(NULL);
   the_buffer = grpc_raw_byte_buffer_create(&slice, payload_size);
   histogram = gpr_histogram_create(0.01, 60e9);
 
@@ -210,9 +213,10 @@
 
   grpc_channel_destroy(channel);
   grpc_completion_queue_shutdown(cq);
-  while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME))
-             .type != GRPC_QUEUE_SHUTDOWN)
-    ;
+  do {
+    event = grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                       NULL);
+  } while (event.type != GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cq);
   grpc_byte_buffer_destroy(the_buffer);
   gpr_slice_unref(slice);
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index f445c68..2873e4a 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -97,6 +97,7 @@
 
 static void handle_unary_method(void) {
   grpc_op *op;
+  grpc_call_error error;
 
   grpc_metadata_array_init(&initial_metadata_send);
 
@@ -122,41 +123,47 @@
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op++;
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, unary_ops, op - unary_ops,
-                                   tag(FLING_SERVER_BATCH_OPS_FOR_UNARY)));
+  error = grpc_call_start_batch(call, unary_ops, op - unary_ops,
+                                tag(FLING_SERVER_BATCH_OPS_FOR_UNARY), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 }
 
 static void send_initial_metadata(void) {
+  grpc_call_error error;
+  void *tagarg = tag(FLING_SERVER_SEND_INIT_METADATA_FOR_STREAMING);
   grpc_metadata_array_init(&initial_metadata_send);
   metadata_send_op.op = GRPC_OP_SEND_INITIAL_METADATA;
   metadata_send_op.data.send_initial_metadata.count = 0;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(
-                 call, &metadata_send_op, 1,
-                 tag(FLING_SERVER_SEND_INIT_METADATA_FOR_STREAMING)));
+  error = grpc_call_start_batch(call, &metadata_send_op, 1, tagarg, NULL);
+
+  GPR_ASSERT(GRPC_CALL_OK == error);
 }
 
 static void start_read_op(int t) {
+  grpc_call_error error;
   /* Starting read at server */
   read_op.op = GRPC_OP_RECV_MESSAGE;
   read_op.data.recv_message = &payload_buffer;
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, &read_op, 1, tag(t)));
+  error = grpc_call_start_batch(call, &read_op, 1, tag(t), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 }
 
 static void start_write_op(void) {
+  grpc_call_error error;
+  void *tagarg = tag(FLING_SERVER_WRITE_FOR_STREAMING);
   /* Starting write at server */
   write_op.op = GRPC_OP_SEND_MESSAGE;
   if (payload_buffer == NULL) {
     gpr_log(GPR_INFO, "NULL payload buffer !!!");
   }
   write_op.data.send_message = payload_buffer;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, &write_op, 1,
-                                   tag(FLING_SERVER_WRITE_FOR_STREAMING)));
+  error = grpc_call_start_batch(call, &write_op, 1, tagarg, NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 }
 
 static void start_send_status(void) {
+  grpc_call_error error;
+  void *tagarg = tag(FLING_SERVER_SEND_STATUS_FOR_STREAMING);
   status_op[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
   status_op[0].data.send_status_from_server.status = GRPC_STATUS_OK;
   status_op[0].data.send_status_from_server.trailing_metadata_count = 0;
@@ -164,9 +171,8 @@
   status_op[1].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   status_op[1].data.recv_close_on_server.cancelled = &was_cancelled;
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(
-                                 call, status_op, 2,
-                                 tag(FLING_SERVER_SEND_STATUS_FOR_STREAMING)));
+  error = grpc_call_start_batch(call, status_op, 2, tagarg, NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 }
 
 /* We have some sort of deadlock, so let's not exit gracefully for now.
@@ -205,20 +211,20 @@
   }
   gpr_log(GPR_INFO, "creating server on: %s", addr);
 
-  cq = grpc_completion_queue_create();
+  cq = grpc_completion_queue_create(NULL);
   if (secure) {
     grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
                                                     test_server1_cert};
     grpc_server_credentials *ssl_creds =
         grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0);
-    server = grpc_server_create(NULL);
+    server = grpc_server_create(NULL, NULL);
     GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, ssl_creds));
     grpc_server_credentials_release(ssl_creds);
   } else {
-    server = grpc_server_create(NULL);
+    server = grpc_server_create(NULL, NULL);
     GPR_ASSERT(grpc_server_add_insecure_http2_port(server, addr));
   }
-  grpc_server_register_completion_queue(server, cq);
+  grpc_server_register_completion_queue(server, cq, NULL);
   grpc_server_start(server);
 
   gpr_free(addr_buf);
@@ -235,14 +241,14 @@
       gpr_log(GPR_INFO, "Shutting down due to SIGINT");
       grpc_server_shutdown_and_notify(server, cq, tag(1000));
       GPR_ASSERT(grpc_completion_queue_pluck(
-                     cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                     cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
                      .type == GRPC_OP_COMPLETE);
       grpc_completion_queue_shutdown(cq);
       shutdown_started = 1;
     }
     ev = grpc_completion_queue_next(
         cq, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                         gpr_time_from_micros(1000000, GPR_TIMESPAN)));
+                         gpr_time_from_micros(1000000, GPR_TIMESPAN)), NULL);
     s = ev.tag;
     switch (ev.type) {
       case GRPC_OP_COMPLETE:
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
new file mode 100644
index 0000000..74b7895
--- /dev/null
+++ b/test/core/iomgr/udp_server_test.c
@@ -0,0 +1,178 @@
+/*
+ *
+ * Copyright 2015, 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 "src/core/iomgr/udp_server.h"
+#include "src/core/iomgr/iomgr.h"
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include "test/core/util/test_config.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", #x)
+
+static grpc_pollset g_pollset;
+static int g_number_of_reads = 0;
+static int g_number_of_bytes_read = 0;
+
+static void on_connect(void *arg, grpc_endpoint *udp) {
+}
+
+static void on_read(int fd, grpc_udp_server_cb new_transport_cb, void *cb_arg) {
+  char read_buffer[512];
+  int byte_count;
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  byte_count = recv(fd, read_buffer, sizeof(read_buffer), 0);
+
+  g_number_of_reads++;
+  g_number_of_bytes_read += byte_count;
+
+  grpc_pollset_kick(&g_pollset, NULL);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+}
+
+static void test_no_op(void) {
+  grpc_udp_server *s = grpc_udp_server_create();
+  grpc_udp_server_destroy(s, NULL, NULL);
+}
+
+static void test_no_op_with_start(void) {
+  grpc_udp_server *s = grpc_udp_server_create();
+  LOG_TEST("test_no_op_with_start");
+  grpc_udp_server_start(s, NULL, 0, on_connect, NULL);
+  grpc_udp_server_destroy(s, NULL, NULL);
+}
+
+static void test_no_op_with_port(void) {
+  struct sockaddr_in addr;
+  grpc_udp_server *s = grpc_udp_server_create();
+  LOG_TEST("test_no_op_with_port");
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  GPR_ASSERT(grpc_udp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr),
+                                      on_read));
+
+  grpc_udp_server_destroy(s, NULL, NULL);
+}
+
+static void test_no_op_with_port_and_start(void) {
+  struct sockaddr_in addr;
+  grpc_udp_server *s = grpc_udp_server_create();
+  LOG_TEST("test_no_op_with_port_and_start");
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  GPR_ASSERT(grpc_udp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr),
+                                      on_read));
+
+  grpc_udp_server_start(s, NULL, 0, on_connect, NULL);
+
+  grpc_udp_server_destroy(s, NULL, NULL);
+}
+
+static void test_receive(int number_of_clients) {
+  struct sockaddr_storage addr;
+  socklen_t addr_len = sizeof(addr);
+  int clifd, svrfd;
+  grpc_udp_server *s = grpc_udp_server_create();
+  int i;
+  int number_of_reads_before;
+  gpr_timespec deadline;
+  grpc_pollset *pollsets[1];
+  LOG_TEST("test_receive");
+  gpr_log(GPR_INFO, "clients=%d", number_of_clients);
+
+  g_number_of_bytes_read = 0;
+
+  memset(&addr, 0, sizeof(addr));
+  addr.ss_family = AF_INET;
+  GPR_ASSERT(grpc_udp_server_add_port(s, (struct sockaddr *)&addr, addr_len, on_read));
+
+  svrfd = grpc_udp_server_get_fd(s, 0);
+  GPR_ASSERT(svrfd >= 0);
+  GPR_ASSERT(getsockname(svrfd, (struct sockaddr *)&addr, &addr_len) == 0);
+  GPR_ASSERT(addr_len <= sizeof(addr));
+
+  pollsets[0] = &g_pollset;
+  grpc_udp_server_start(s, pollsets, 1, on_connect, NULL);
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+
+  for (i = 0; i < number_of_clients; i++) {
+    deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(4000);
+
+    number_of_reads_before = g_number_of_reads;
+    /* Create a socket, send a packet to the UDP server. */
+    clifd = socket(addr.ss_family, SOCK_DGRAM, 0);
+    GPR_ASSERT(clifd >= 0);
+    GPR_ASSERT(connect(clifd, (struct sockaddr *)&addr, addr_len) == 0);
+    GPR_ASSERT(5 == write(clifd, "hello", 5));
+    while (g_number_of_reads == number_of_reads_before &&
+           gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
+      grpc_pollset_worker worker;
+      grpc_pollset_work(&g_pollset, &worker, deadline);
+    }
+    GPR_ASSERT(g_number_of_reads == number_of_reads_before + 1);
+    close(clifd);
+  }
+  GPR_ASSERT(g_number_of_bytes_read == 5 * number_of_clients);
+
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+
+  grpc_udp_server_destroy(s, NULL, NULL);
+}
+
+static void destroy_pollset(void *p) { grpc_pollset_destroy(p); }
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_iomgr_init();
+  grpc_pollset_init(&g_pollset);
+
+  test_no_op();
+  test_no_op_with_start();
+  test_no_op_with_port();
+  test_no_op_with_port_and_start();
+  test_receive(1);
+  test_receive(10);
+
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
+  grpc_iomgr_shutdown();
+  return 0;
+}
diff --git a/test/core/support/cancellable_test.c b/test/core/support/cancellable_test.c
deleted file mode 100644
index 9b321d3..0000000
--- a/test/core/support/cancellable_test.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *
- * Copyright 2015, 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.
- *
- */
-
-/* Test of gpr_cancellable. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
-#include "test/core/util/test_config.h"
-
-struct test {
-  gpr_mu mu;
-  gpr_cv cv;
-  gpr_event ev;
-  gpr_event done;
-  gpr_cancellable cancel;
-  int n;
-};
-
-/* A thread body.   Wait until t->cancel is cancelledm then
-   decrement t->n.  If t->n becomes 0, set t->done.  */
-static void thd_body(void *v) {
-  struct test *t = v;
-  gpr_mu_lock(&t->mu);
-  while (!gpr_cv_cancellable_wait(
-      &t->cv, &t->mu, gpr_inf_future(GPR_CLOCK_REALTIME), &t->cancel)) {
-  }
-  t->n--;
-  if (t->n == 0) {
-    gpr_event_set(&t->done, (void *)1);
-  }
-  gpr_mu_unlock(&t->mu);
-}
-
-static void test(void) {
-  int i;
-  gpr_thd_id thd;
-  struct test t;
-  int n = 1;
-  gpr_timespec interval;
-
-  gpr_mu_init(&t.mu);
-  gpr_cv_init(&t.cv);
-  gpr_event_init(&t.ev);
-  gpr_event_init(&t.done);
-  gpr_cancellable_init(&t.cancel);
-
-  /* A gpr_cancellable starts not cancelled. */
-  GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
-
-  /* Test timeout on event wait for uncancelled gpr_cancellable */
-  interval = gpr_now(GPR_CLOCK_REALTIME);
-  gpr_event_cancellable_wait(
-      &t.ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                          gpr_time_from_micros(1000000, GPR_TIMESPAN)),
-      &t.cancel);
-  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
-  GPR_ASSERT(
-      gpr_time_cmp(interval, gpr_time_from_micros(500000, GPR_TIMESPAN)) >= 0);
-  GPR_ASSERT(
-      gpr_time_cmp(gpr_time_from_micros(2000000, GPR_TIMESPAN), interval) >= 0);
-
-  /* Test timeout on cv wait for uncancelled gpr_cancellable */
-  gpr_mu_lock(&t.mu);
-  interval = gpr_now(GPR_CLOCK_REALTIME);
-  while (!gpr_cv_cancellable_wait(
-      &t.cv, &t.mu, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                                 gpr_time_from_micros(1000000, GPR_TIMESPAN)),
-      &t.cancel)) {
-  }
-  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
-  GPR_ASSERT(
-      gpr_time_cmp(interval, gpr_time_from_micros(500000, GPR_TIMESPAN)) >= 0);
-  GPR_ASSERT(
-      gpr_time_cmp(gpr_time_from_micros(2000000, GPR_TIMESPAN), interval) >= 0);
-  gpr_mu_unlock(&t.mu);
-
-  /* Create some threads.  They all wait until cancelled; the last to finish
-     sets t.done.  */
-  t.n = n;
-  for (i = 0; i != n; i++) {
-    GPR_ASSERT(gpr_thd_new(&thd, &thd_body, &t, NULL));
-  }
-  /* Check that t.cancel still is not cancelled. */
-  GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
-
-  /* Wait a second, and check that no threads have finished waiting. */
-  gpr_mu_lock(&t.mu);
-  gpr_cv_wait(&t.cv, &t.mu,
-              gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                           gpr_time_from_micros(1000000, GPR_TIMESPAN)));
-  GPR_ASSERT(t.n == n);
-  gpr_mu_unlock(&t.mu);
-
-  /* Check that t.cancel still is not cancelled, but when
-     cancelled it retports that it is cacncelled. */
-  GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
-  gpr_cancellable_cancel(&t.cancel);
-  GPR_ASSERT(gpr_cancellable_is_cancelled(&t.cancel));
-
-  /* Wait for threads to finish. */
-  gpr_event_wait(&t.done, gpr_inf_future(GPR_CLOCK_REALTIME));
-  GPR_ASSERT(t.n == 0);
-
-  /* Test timeout on cv wait for cancelled gpr_cancellable */
-  gpr_mu_lock(&t.mu);
-  interval = gpr_now(GPR_CLOCK_REALTIME);
-  while (!gpr_cv_cancellable_wait(
-      &t.cv, &t.mu, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                                 gpr_time_from_micros(1000000, GPR_TIMESPAN)),
-      &t.cancel)) {
-  }
-  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
-  GPR_ASSERT(
-      gpr_time_cmp(gpr_time_from_micros(100000, GPR_TIMESPAN), interval) >= 0);
-  gpr_mu_unlock(&t.mu);
-
-  /* Test timeout on event wait for cancelled gpr_cancellable */
-  interval = gpr_now(GPR_CLOCK_REALTIME);
-  gpr_event_cancellable_wait(
-      &t.ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                          gpr_time_from_micros(1000000, GPR_TIMESPAN)),
-      &t.cancel);
-  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
-  GPR_ASSERT(
-      gpr_time_cmp(gpr_time_from_micros(100000, GPR_TIMESPAN), interval) >= 0);
-
-  gpr_mu_destroy(&t.mu);
-  gpr_cv_destroy(&t.cv);
-  gpr_cancellable_destroy(&t.cancel);
-}
-
-/* ------------------------------------------------- */
-
-int main(int argc, char *argv[]) {
-  grpc_test_init(argc, argv);
-  test();
-  return 0;
-}
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index 0e59ea4..0741ab9 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -52,7 +52,7 @@
 static void shutdown_and_destroy(grpc_completion_queue *cc) {
   grpc_event ev;
   grpc_completion_queue_shutdown(cc);
-  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME));
+  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
   GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
@@ -60,17 +60,18 @@
 /* ensure we can create and destroy a completion channel */
 static void test_no_op(void) {
   LOG_TEST("test_no_op");
-  shutdown_and_destroy(grpc_completion_queue_create());
+  shutdown_and_destroy(grpc_completion_queue_create(NULL));
 }
 
 static void test_wait_empty(void) {
   grpc_completion_queue *cc;
+  grpc_event event;
 
   LOG_TEST("test_wait_empty");
 
-  cc = grpc_completion_queue_create();
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_now(GPR_CLOCK_REALTIME)).type ==
-             GRPC_QUEUE_TIMEOUT);
+  cc = grpc_completion_queue_create(NULL);
+  event = grpc_completion_queue_next(cc, gpr_now(GPR_CLOCK_REALTIME), NULL);
+  GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT);
   shutdown_and_destroy(cc);
 }
 
@@ -84,12 +85,12 @@
 
   LOG_TEST("test_cq_end_op");
 
-  cc = grpc_completion_queue_create();
+  cc = grpc_completion_queue_create(NULL);
 
   grpc_cq_begin_op(cc);
   grpc_cq_end_op(cc, tag, 1, do_nothing_end_completion, NULL, &completion);
 
-  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME));
+  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
   GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
   GPR_ASSERT(ev.tag == tag);
   GPR_ASSERT(ev.success);
@@ -99,23 +100,27 @@
 
 static void test_shutdown_then_next_polling(void) {
   grpc_completion_queue *cc;
+  grpc_event event;
   LOG_TEST("test_shutdown_then_next_polling");
 
-  cc = grpc_completion_queue_create();
+  cc = grpc_completion_queue_create(NULL);
   grpc_completion_queue_shutdown(cc);
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME))
-                 .type == GRPC_QUEUE_SHUTDOWN);
+  event = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME),
+                                     NULL);
+  GPR_ASSERT(event.type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
 
 static void test_shutdown_then_next_with_timeout(void) {
   grpc_completion_queue *cc;
+  grpc_event event;
   LOG_TEST("test_shutdown_then_next_with_timeout");
 
-  cc = grpc_completion_queue_create();
+  cc = grpc_completion_queue_create(NULL);
   grpc_completion_queue_shutdown(cc);
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_inf_future(GPR_CLOCK_REALTIME))
-                 .type == GRPC_QUEUE_SHUTDOWN);
+  event = grpc_completion_queue_next(cc, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                     NULL);
+  GPR_ASSERT(event.type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
 
@@ -135,7 +140,7 @@
     }
   }
 
-  cc = grpc_completion_queue_create();
+  cc = grpc_completion_queue_create(NULL);
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
     grpc_cq_begin_op(cc);
@@ -145,7 +150,7 @@
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
     ev = grpc_completion_queue_pluck(cc, tags[i],
-                                     gpr_inf_past(GPR_CLOCK_REALTIME));
+                                     gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
     GPR_ASSERT(ev.tag == tags[i]);
   }
 
@@ -157,7 +162,7 @@
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
     ev = grpc_completion_queue_pluck(cc, tags[GPR_ARRAY_SIZE(tags) - i - 1],
-                                     gpr_inf_past(GPR_CLOCK_REALTIME));
+                                     gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
     GPR_ASSERT(ev.tag == tags[GPR_ARRAY_SIZE(tags) - i - 1]);
   }
 
@@ -229,7 +234,7 @@
 
   gpr_log(GPR_INFO, "consumer %d phase 2", opt->id);
   for (;;) {
-    ev = grpc_completion_queue_next(opt->cc, ten_seconds_time());
+    ev = grpc_completion_queue_next(opt->cc, ten_seconds_time(), NULL);
     switch (ev.type) {
       case GRPC_OP_COMPLETE:
         GPR_ASSERT(ev.success);
@@ -251,7 +256,7 @@
       gpr_malloc((producers + consumers) * sizeof(test_thread_options));
   gpr_event phase1 = GPR_EVENT_INIT;
   gpr_event phase2 = GPR_EVENT_INIT;
-  grpc_completion_queue *cc = grpc_completion_queue_create();
+  grpc_completion_queue *cc = grpc_completion_queue_create(NULL);
   int i;
   int total_consumed = 0;
   static int optid = 101;
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
index 5e6c9ae..216eeca 100644
--- a/test/core/surface/lame_client_test.c
+++ b/test/core/surface/lame_client_test.c
@@ -49,6 +49,7 @@
   grpc_op *op;
   grpc_metadata_array trailing_metadata_recv;
   grpc_status_code status;
+  grpc_call_error error;
   char *details = NULL;
   size_t details_capacity = 0;
 
@@ -59,10 +60,11 @@
 
   chan = grpc_lame_client_channel_create("lampoon:national");
   GPR_ASSERT(chan);
-  cq = grpc_completion_queue_create();
+  cq = grpc_completion_queue_create(NULL);
   call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
                                   "/Foo", "anywhere",
-                                  GRPC_TIMEOUT_SECONDS_TO_DEADLINE(100));
+                                  GRPC_TIMEOUT_SECONDS_TO_DEADLINE(100),
+                                  NULL);
   GPR_ASSERT(call);
   cqv = cq_verifier_create(cq);
 
@@ -70,6 +72,7 @@
   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_STATUS_ON_CLIENT;
   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
@@ -77,9 +80,10 @@
   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++;
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call, ops, op - ops, tag(1)));
+  error = grpc_call_start_batch(call, ops, op - ops, tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* the call should immediately fail */
   cq_expect_completion(cqv, tag(1), 1);
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 9b53bdc..f00d19e 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -666,6 +666,28 @@
   EXPECT_TRUE(recv_status.ok());
 }
 
+TEST_F(AsyncEnd2endTest, UnimplementedRpc) {
+  std::shared_ptr<ChannelInterface> channel = CreateChannel(
+      server_address_.str(), InsecureCredentials(), ChannelArguments());
+  std::unique_ptr<grpc::cpp::test::util::UnimplementedService::Stub> stub;
+  stub =
+      std::move(grpc::cpp::test::util::UnimplementedService::NewStub(channel));
+  EchoRequest send_request;
+  EchoResponse recv_response;
+  Status recv_status;
+
+  ClientContext cli_ctx;
+  send_request.set_message("Hello");
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+      stub->AsyncUnimplemented(&cli_ctx, send_request, cq_.get()));
+
+  response_reader->Finish(&recv_response, &recv_status, tag(4));
+  Verifier().Expect(4, false).Verify(cq_.get());
+
+  EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
+  EXPECT_EQ("", recv_status.error_message());
+}
+
 }  // namespace
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 3766981..3827cdf 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -290,13 +290,17 @@
     if (proxy_server_) proxy_server_->Shutdown();
   }
 
-  void ResetStub(bool use_proxy) {
+  void ResetChannel() {
     SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
     ChannelArguments args;
     args.SetSslTargetNameOverride("foo.test.google.fr");
     args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
     channel_ = CreateChannel(server_address_.str(), SslCredentials(ssl_opts),
                              args);
+  }
+
+  void ResetStub(bool use_proxy) {
+    ResetChannel();
     if (use_proxy) {
       proxy_service_.reset(new Proxy(channel_));
       int port = grpc_pick_unused_port_or_die();
@@ -930,6 +934,23 @@
   EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false));
 }
 
+// Talking to a non-existing service.
+TEST_F(End2endTest, NonExistingService) {
+  ResetChannel();
+  std::unique_ptr<grpc::cpp::test::util::UnimplementedService::Stub> stub;
+  stub =
+      std::move(grpc::cpp::test::util::UnimplementedService::NewStub(channel_));
+
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+
+  ClientContext context;
+  Status s = stub->Unimplemented(&context, request, &response);
+  EXPECT_EQ(StatusCode::UNIMPLEMENTED, s.error_code());
+  EXPECT_EQ("", s.error_message());
+}
+
 INSTANTIATE_TEST_CASE_P(End2end, End2endTest, ::testing::Values(false, true));
 
 }  // namespace testing
diff --git a/test/cpp/end2end/zookeeper_test.cc b/test/cpp/end2end/zookeeper_test.cc
new file mode 100644
index 0000000..a48c497
--- /dev/null
+++ b/test/cpp/end2end/zookeeper_test.cc
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2015, 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 "test/core/util/test_config.h"
+#include "test/core/util/port.h"
+#include "test/cpp/util/echo.grpc.pb.h"
+#include "src/core/support/env.h"
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc++/server_credentials.h>
+#include <grpc++/status.h>
+#include <gtest/gtest.h>
+#include <grpc/grpc.h>
+#include <grpc/grpc_zookeeper.h>
+#include <zookeeper/zookeeper.h>
+
+using grpc::cpp::test::util::EchoRequest;
+using grpc::cpp::test::util::EchoResponse;
+
+namespace grpc {
+namespace testing {
+
+class ZookeeperTestServiceImpl
+    : public ::grpc::cpp::test::util::TestService::Service {
+ public:
+  Status Echo(ServerContext* context, const EchoRequest* request,
+              EchoResponse* response) GRPC_OVERRIDE {
+    response->set_message(request->message());
+    return Status::OK;
+  }
+};
+
+class ZookeeperTest : public ::testing::Test {
+ protected:
+  ZookeeperTest() {}
+
+  void SetUp() GRPC_OVERRIDE {
+    SetUpZookeeper();
+
+    // Sets up two servers
+    int port1 = grpc_pick_unused_port_or_die();
+    server1_ = SetUpServer(port1);
+
+    int port2 = grpc_pick_unused_port_or_die();
+    server2_ = SetUpServer(port2);
+
+    // Registers service /test in zookeeper
+    RegisterService("/test", "test");
+
+    // Registers service instance /test/1 in zookeeper
+    string value =
+        "{\"host\":\"localhost\",\"port\":\"" + to_string(port1) + "\"}";
+    RegisterService("/test/1", value);
+
+    // Registers service instance /test/2 in zookeeper
+    value =
+        "{\"host\":\"localhost\",\"port\":\"" + to_string(port2) + "\"}";
+    RegisterService("/test/2", value);
+  }
+
+  // Requires zookeeper server running
+  void SetUpZookeeper() {
+    // Finds zookeeper server address in environment
+    // Default is localhost:2181
+    zookeeper_address_ = "localhost:2181";
+    char* addr = gpr_getenv("GRPC_ZOOKEEPER_SERVER_TEST");
+    if (addr != NULL) {
+      string addr_str(addr);
+      zookeeper_address_ = addr_str;
+      gpr_free(addr);
+    }
+    gpr_log(GPR_DEBUG, zookeeper_address_.c_str());
+
+    // Connects to zookeeper server
+    zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
+    zookeeper_handle_ =
+        zookeeper_init(zookeeper_address_.c_str(), NULL, 15000, 0, 0, 0);
+    GPR_ASSERT(zookeeper_handle_ != NULL);
+
+    // Registers zookeeper name resolver in grpc
+    grpc_zookeeper_register();
+  }
+
+  std::unique_ptr<Server> SetUpServer(const int port) {
+    string server_address = "localhost:" + to_string(port);
+
+    ServerBuilder builder;
+    builder.AddListeningPort(server_address, InsecureServerCredentials());
+    builder.RegisterService(&service_);
+    std::unique_ptr<Server> server = builder.BuildAndStart();
+    return server;
+  }
+
+  void RegisterService(const string& name, const string& value) {
+    char* path = (char*)gpr_malloc(name.size());
+
+    int status = zoo_exists(zookeeper_handle_, name.c_str(), 0, NULL);
+    if (status == ZNONODE) {
+      status =
+          zoo_create(zookeeper_handle_, name.c_str(), value.c_str(),
+                     value.size(), &ZOO_OPEN_ACL_UNSAFE, 0, path, name.size());
+    } else {
+      status = zoo_set(zookeeper_handle_, name.c_str(), value.c_str(),
+                       value.size(), -1);
+    }
+    gpr_free(path);
+    GPR_ASSERT(status == 0);
+  }
+
+  void DeleteService(const string& name) {
+    int status = zoo_delete(zookeeper_handle_, name.c_str(), -1);
+    GPR_ASSERT(status == 0);
+  }
+
+  void ChangeZookeeperState() {
+    server1_->Shutdown();
+    DeleteService("/test/1");
+  }
+
+  void TearDown() GRPC_OVERRIDE {
+    server1_->Shutdown();
+    server2_->Shutdown();
+    zookeeper_close(zookeeper_handle_);
+  }
+
+  void ResetStub() {
+    string target = "zookeeper://" + zookeeper_address_ + "/test";
+    channel_ = CreateChannel(target, InsecureCredentials(), ChannelArguments());
+    stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_));
+  }
+
+  string to_string(const int number) {
+    std::stringstream strs;
+    strs << number;
+    return strs.str();
+  }
+
+  std::shared_ptr<ChannelInterface> channel_;
+  std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
+  std::unique_ptr<Server> server1_;
+  std::unique_ptr<Server> server2_;
+  ZookeeperTestServiceImpl service_;
+  zhandle_t* zookeeper_handle_;
+  string zookeeper_address_;
+};
+
+// Tests zookeeper state change between two RPCs
+// TODO(ctiller): leaked objects in this test
+TEST_F(ZookeeperTest, ZookeeperStateChangeTwoRpc) {
+  ResetStub();
+
+  // First RPC
+  EchoRequest request1;
+  EchoResponse response1;
+  ClientContext context1;
+  context1.set_authority("test");
+  request1.set_message("Hello");
+  Status s1 = stub_->Echo(&context1, request1, &response1);
+  EXPECT_EQ(response1.message(), request1.message());
+  EXPECT_TRUE(s1.ok());
+
+  // Zookeeper state changes
+  gpr_log(GPR_DEBUG, "Zookeeper state change"); 
+  ChangeZookeeperState();
+  // Waits for re-resolving addresses
+  // TODO(ctiller): RPC will probably fail if not waiting
+  sleep(1);
+
+  // Second RPC
+  EchoRequest request2;
+  EchoResponse response2;
+  ClientContext context2;
+  context2.set_authority("test");
+  request2.set_message("World");
+  Status s2 = stub_->Echo(&context2, request2, &response2);
+  EXPECT_EQ(response2.message(), request2.message());
+  EXPECT_TRUE(s2.ok());
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index dfb90fa..066877e 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -316,7 +316,6 @@
   unsigned int i = 0;
   StreamingOutputCallResponse response;
   while (stream->Read(&response)) {
-    GPR_ASSERT(response.payload().has_body());
     GPR_ASSERT(response.payload().body() ==
                grpc::string(response_stream_sizes[i], '\0'));
     ++i;
@@ -346,7 +345,6 @@
     payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
     GPR_ASSERT(stream->Write(request));
     GPR_ASSERT(stream->Read(&response));
-    GPR_ASSERT(response.payload().has_body());
     GPR_ASSERT(response.payload().body() ==
                grpc::string(response_stream_sizes[i], '\0'));
   }
@@ -393,7 +391,6 @@
   StreamingOutputCallResponse response;
   GPR_ASSERT(stream->Write(request));
   GPR_ASSERT(stream->Read(&response));
-  GPR_ASSERT(response.payload().has_body());
   GPR_ASSERT(response.payload().body() == grpc::string(31415, '\0'));
   gpr_log(GPR_INFO, "Trying to cancel...");
   context.TryCancel();
diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc
index 05a10de..4e809ed 100644
--- a/test/cpp/interop/server.cc
+++ b/test/cpp/interop/server.cc
@@ -99,7 +99,7 @@
 
   Status UnaryCall(ServerContext* context, const SimpleRequest* request,
                    SimpleResponse* response) {
-    if (request->has_response_size() && request->response_size() > 0) {
+    if (request->response_size() > 0) {
       if (!SetPayload(request->response_type(), request->response_size(),
                       response->mutable_payload())) {
         return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
@@ -140,7 +140,7 @@
     StreamingInputCallRequest request;
     int aggregated_payload_size = 0;
     while (reader->Read(&request)) {
-      if (request.has_payload() && request.payload().has_body()) {
+      if (request.has_payload()) {
         aggregated_payload_size += request.payload().body().size();
       }
     }
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 28cd32a..1c4f463 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -41,6 +41,7 @@
 
 #include <condition_variable>
 #include <mutex>
+#include <grpc++/config.h>
 
 namespace grpc {
 
@@ -67,10 +68,12 @@
 class Client {
  public:
   explicit Client(const ClientConfig& config)
-      : timer_(new Timer), interarrival_timer_() {
+      : channels_(config.client_channels()),
+        timer_(new Timer),
+        interarrival_timer_() {
     for (int i = 0; i < config.client_channels(); i++) {
-      channels_.push_back(ClientChannelInfo(
-          config.server_targets(i % config.server_targets_size()), config));
+      channels_[i].init(config.server_targets(i % config.server_targets_size()),
+                        config);
     }
     request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
     request_.set_response_size(config.payload_size());
@@ -79,7 +82,8 @@
 
   ClientStats Mark() {
     Histogram latencies;
-    std::vector<Histogram> to_merge(threads_.size());
+    // avoid std::vector for old compilers that expect a copy constructor
+    Histogram* to_merge = new Histogram[threads_.size()];
     for (size_t i = 0; i < threads_.size(); i++) {
       threads_[i]->BeginSwap(&to_merge[i]);
     }
@@ -89,6 +93,7 @@
       threads_[i]->EndSwap();
       latencies.Merge(&to_merge[i]);
     }
+    delete[] to_merge;
 
     auto timer_result = timer->Mark();
 
@@ -106,9 +111,20 @@
 
   class ClientChannelInfo {
    public:
-    ClientChannelInfo(const grpc::string& target, const ClientConfig& config)
-        : channel_(CreateTestChannel(target, config.enable_ssl())),
-          stub_(TestService::NewStub(channel_)) {}
+    ClientChannelInfo() {}
+    ClientChannelInfo(const ClientChannelInfo& i) {
+      // The copy constructor is to satisfy old compilers
+      // that need it for using std::vector . It is only ever
+      // used for empty entries
+      GPR_ASSERT(!i.channel_ && !i.stub_);
+    }
+    void init(const grpc::string& target, const ClientConfig& config) {
+      // We have to use a 2-phase init like this with a default
+      // constructor followed by an initializer function to make
+      // old compilers happy with using this in std::vector
+      channel_ = CreateTestChannel(target, config.enable_ssl());
+      stub_ = TestService::NewStub(channel_);
+    }
     ChannelInterface* get_channel() { return channel_.get(); }
     TestService::Stub* get_stub() { return stub_.get(); }
 
@@ -189,27 +205,9 @@
     Thread(Client* client, size_t idx)
         : done_(false),
           new_(nullptr),
-          impl_([this, idx, client]() {
-            for (;;) {
-              // run the loop body
-              bool thread_still_ok = client->ThreadFunc(&histogram_, idx);
-              // lock, see if we're done
-              std::lock_guard<std::mutex> g(mu_);
-              if (!thread_still_ok) {
-                gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
-                done_ = true;
-              }
-              if (done_) {
-                return;
-              }
-              // check if we're marking, swap out the histogram if so
-              if (new_) {
-                new_->Swap(&histogram_);
-                new_ = nullptr;
-                cv_.notify_one();
-              }
-            }
-          }) {}
+          client_(client),
+          idx_(idx),
+          impl_(&Thread::ThreadFunc, this) {}
 
     ~Thread() {
       {
@@ -226,13 +224,37 @@
 
     void EndSwap() {
       std::unique_lock<std::mutex> g(mu_);
-      cv_.wait(g, [this]() { return new_ == nullptr; });
+      while (new_ != nullptr) {
+        cv_.wait(g);
+      };
     }
 
    private:
     Thread(const Thread&);
     Thread& operator=(const Thread&);
 
+    void ThreadFunc() {
+      for (;;) {
+        // run the loop body
+        const bool thread_still_ok = client_->ThreadFunc(&histogram_, idx_);
+        // lock, see if we're done
+        std::lock_guard<std::mutex> g(mu_);
+        if (!thread_still_ok) {
+          gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
+          done_ = true;
+        }
+        if (done_) {
+          return;
+        }
+        // check if we're marking, swap out the histogram if so
+        if (new_) {
+          new_->Swap(&histogram_);
+          new_ = nullptr;
+          cv_.notify_one();
+        }
+      }
+    }
+
     TestService::Stub* stub_;
     ClientConfig config_;
     std::mutex mu_;
@@ -240,6 +262,8 @@
     bool done_;
     Histogram* new_;
     Histogram histogram_;
+    Client* client_;
+    size_t idx_;
     std::thread impl_;
   };
 
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index e1e44f9..a337610 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -156,7 +156,7 @@
       std::function<ClientRpcContext*(int, TestService::Stub*,
                                       const SimpleRequest&)> setup_ctx)
       : Client(config),
-        channel_lock_(config.client_channels()),
+        channel_lock_(new std::mutex[config.client_channels()]),
         contexts_(config.client_channels()),
         max_outstanding_per_channel_(config.outstanding_rpcs_per_channel()),
         channel_count_(config.client_channels()),
@@ -208,6 +208,7 @@
         delete ctx;
       }
     }
+    delete[] channel_lock_;
   }
 
   bool ThreadFunc(Histogram* histogram,
@@ -316,23 +317,28 @@
   }
 
  private:
-  class boolean { // exists only to avoid data-race on vector<bool>
+  class boolean {  // exists only to avoid data-race on vector<bool>
    public:
-    boolean(): val_(false) {}
-    boolean(bool b): val_(b) {}
-    operator bool() const {return val_;}
-    boolean& operator=(bool b) {val_=b; return *this;}
+    boolean() : val_(false) {}
+    boolean(bool b) : val_(b) {}
+    operator bool() const { return val_; }
+    boolean& operator=(bool b) {
+      val_ = b;
+      return *this;
+    }
+
    private:
     bool val_;
   };
   std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
 
   std::vector<deadline_list> rpc_deadlines_;  // per thread deadlines
-  std::vector<int> next_channel_;      // per thread round-robin channel ctr
-  std::vector<boolean> issue_allowed_; // may this thread attempt to issue
-  std::vector<grpc_time> next_issue_;  // when should it issue?
+  std::vector<int> next_channel_;       // per thread round-robin channel ctr
+  std::vector<boolean> issue_allowed_;  // may this thread attempt to issue
+  std::vector<grpc_time> next_issue_;   // when should it issue?
 
-  std::vector<std::mutex> channel_lock_;
+  std::mutex*
+      channel_lock_;  // a vector, but avoid std::vector for old compilers
   std::vector<context_list> contexts_;  // per-channel list of idle contexts
   int max_outstanding_per_channel_;
   int channel_count_;
@@ -348,15 +354,17 @@
   ~AsyncUnaryClient() GRPC_OVERRIDE { EndThreads(); }
 
  private:
+  static void CheckDone(grpc::Status s, SimpleResponse* response) {}
+  static std::unique_ptr<grpc::ClientAsyncResponseReader<SimpleResponse>>
+  StartReq(TestService::Stub* stub, grpc::ClientContext* ctx,
+           const SimpleRequest& request, CompletionQueue* cq) {
+    return stub->AsyncUnaryCall(ctx, request, cq);
+  };
   static ClientRpcContext* SetupCtx(int channel_id, TestService::Stub* stub,
                                     const SimpleRequest& req) {
-    auto check_done = [](grpc::Status s, SimpleResponse* response) {};
-    auto start_req = [](TestService::Stub* stub, grpc::ClientContext* ctx,
-                        const SimpleRequest& request, CompletionQueue* cq) {
-      return stub->AsyncUnaryCall(ctx, request, cq);
-    };
     return new ClientRpcContextUnaryImpl<SimpleRequest, SimpleResponse>(
-        channel_id, stub, req, start_req, check_done);
+        channel_id, stub, req, AsyncUnaryClient::StartReq,
+        AsyncUnaryClient::CheckDone);
   }
 };
 
@@ -442,16 +450,19 @@
   ~AsyncStreamingClient() GRPC_OVERRIDE { EndThreads(); }
 
  private:
+  static void CheckDone(grpc::Status s, SimpleResponse* response) {}
+  static std::unique_ptr<
+      grpc::ClientAsyncReaderWriter<SimpleRequest, SimpleResponse>>
+  StartReq(TestService::Stub* stub, grpc::ClientContext* ctx,
+           CompletionQueue* cq, void* tag) {
+    auto stream = stub->AsyncStreamingCall(ctx, cq, tag);
+    return stream;
+  };
   static ClientRpcContext* SetupCtx(int channel_id, TestService::Stub* stub,
                                     const SimpleRequest& req) {
-    auto check_done = [](grpc::Status s, SimpleResponse* response) {};
-    auto start_req = [](TestService::Stub* stub, grpc::ClientContext* ctx,
-                        CompletionQueue* cq, void* tag) {
-      auto stream = stub->AsyncStreamingCall(ctx, cq, tag);
-      return stream;
-    };
     return new ClientRpcContextStreamingImpl<SimpleRequest, SimpleResponse>(
-        channel_id, stub, req, start_req, check_done);
+        channel_id, stub, req, AsyncStreamingClient::StartReq,
+        AsyncStreamingClient::CheckDone);
   }
 };
 
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 718698b..db5416a 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -45,8 +45,9 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/histogram.h>
-#include <grpc/support/log.h>
 #include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
 #include <gflags/gflags.h>
 #include <grpc++/client_context.h>
 #include <grpc++/server.h>
@@ -79,7 +80,9 @@
   void WaitToIssue(int thread_idx) {
     grpc_time next_time;
     if (NextIssueTime(thread_idx, &next_time)) {
-      std::this_thread::sleep_until(next_time);
+      gpr_timespec next_timespec;
+      TimepointHR2Timespec(next_time, &next_timespec);
+      gpr_sleep_until(next_timespec);
     }
   }
 
@@ -110,9 +113,10 @@
 class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient {
  public:
   SynchronousStreamingClient(const ClientConfig& config)
-      : SynchronousClient(config),
-        context_(num_threads_),
-        stream_(num_threads_) {
+      : SynchronousClient(config) {
+    context_ = new grpc::ClientContext[num_threads_];
+    stream_ = new std::unique_ptr<
+        grpc::ClientReaderWriter<SimpleRequest, SimpleResponse>>[num_threads_];
     for (size_t thread_idx = 0; thread_idx < num_threads_; thread_idx++) {
       auto* stub = channels_[thread_idx % channels_.size()].get_stub();
       stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
@@ -121,12 +125,15 @@
   }
   ~SynchronousStreamingClient() {
     EndThreads();
-    for (auto stream = stream_.begin(); stream != stream_.end(); stream++) {
+    for (auto stream = &stream_[0]; stream != &stream_[num_threads_];
+         stream++) {
       if (*stream) {
         (*stream)->WritesDone();
         EXPECT_TRUE((*stream)->Finish().ok());
       }
     }
+    delete[] stream_;
+    delete[] context_;
   }
 
   bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
@@ -141,9 +148,11 @@
   }
 
  private:
-  std::vector<grpc::ClientContext> context_;
-  std::vector<std::unique_ptr<
-      grpc::ClientReaderWriter<SimpleRequest, SimpleResponse>>> stream_;
+  // These are both conceptually std::vector but cannot be for old compilers
+  // that expect contained classes to support copy constructors
+  grpc::ClientContext* context_;
+  std::unique_ptr<grpc::ClientReaderWriter<SimpleRequest, SimpleResponse>>*
+      stream_;
 };
 
 std::unique_ptr<Client> CreateSynchronousUnaryClient(
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index a036029..78e3720 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -77,16 +77,34 @@
   }
 }
 
+// Namespace for classes and functions used only in RunScenario
+// Using this rather than local definitions to workaround gcc-4.4 limitations
+// regarding using templates without linkage
+namespace runsc {
+
+// ClientContext allocator
+static ClientContext* AllocContext(list<ClientContext>* contexts) {
+  contexts->emplace_back();
+  return &contexts->back();
+}
+
+struct ServerData {
+  unique_ptr<Worker::Stub> stub;
+  unique_ptr<ClientReaderWriter<ServerArgs, ServerStatus>> stream;
+};
+
+struct ClientData {
+  unique_ptr<Worker::Stub> stub;
+  unique_ptr<ClientReaderWriter<ClientArgs, ClientStatus>> stream;
+};
+}  // namespace runsc
+
 std::unique_ptr<ScenarioResult> RunScenario(
     const ClientConfig& initial_client_config, size_t num_clients,
     const ServerConfig& server_config, size_t num_servers, int warmup_seconds,
     int benchmark_seconds, int spawn_local_worker_count) {
-  // ClientContext allocator (all are destroyed at scope exit)
+  // ClientContext allocations (all are destroyed at scope exit)
   list<ClientContext> contexts;
-  auto alloc_context = [&contexts]() {
-    contexts.emplace_back();
-    return &contexts.back();
-  };
 
   // To be added to the result, containing the final configuration used for
   // client and config (incluiding host, etc.)
@@ -131,23 +149,22 @@
   workers.resize(num_clients + num_servers);
 
   // Start servers
-  struct ServerData {
-    unique_ptr<Worker::Stub> stub;
-    unique_ptr<ClientReaderWriter<ServerArgs, ServerStatus>> stream;
-  };
-  vector<ServerData> servers;
+  using runsc::ServerData;
+  // servers is array rather than std::vector to avoid gcc-4.4 issues
+  // where class contained in std::vector must have a copy constructor
+  auto* servers = new ServerData[num_servers];
   for (size_t i = 0; i < num_servers; i++) {
-    ServerData sd;
-    sd.stub = std::move(Worker::NewStub(
+    servers[i].stub = std::move(Worker::NewStub(
         CreateChannel(workers[i], InsecureCredentials(), ChannelArguments())));
     ServerArgs args;
     result_server_config = server_config;
     result_server_config.set_host(workers[i]);
     *args.mutable_setup() = server_config;
-    sd.stream = std::move(sd.stub->RunServer(alloc_context()));
-    GPR_ASSERT(sd.stream->Write(args));
+    servers[i].stream =
+        std::move(servers[i].stub->RunServer(runsc::AllocContext(&contexts)));
+    GPR_ASSERT(servers[i].stream->Write(args));
     ServerStatus init_status;
-    GPR_ASSERT(sd.stream->Read(&init_status));
+    GPR_ASSERT(servers[i].stream->Read(&init_status));
     char* host;
     char* driver_port;
     char* cli_target;
@@ -157,30 +174,25 @@
     gpr_free(host);
     gpr_free(driver_port);
     gpr_free(cli_target);
-
-    servers.push_back(std::move(sd));
   }
 
   // Start clients
-  struct ClientData {
-    unique_ptr<Worker::Stub> stub;
-    unique_ptr<ClientReaderWriter<ClientArgs, ClientStatus>> stream;
-  };
-  vector<ClientData> clients;
+  using runsc::ClientData;
+  // clients is array rather than std::vector to avoid gcc-4.4 issues
+  // where class contained in std::vector must have a copy constructor
+  auto* clients = new ClientData[num_clients];
   for (size_t i = 0; i < num_clients; i++) {
-    ClientData cd;
-    cd.stub = std::move(Worker::NewStub(CreateChannel(
+    clients[i].stub = std::move(Worker::NewStub(CreateChannel(
         workers[i + num_servers], InsecureCredentials(), ChannelArguments())));
     ClientArgs args;
     result_client_config = client_config;
     result_client_config.set_host(workers[i + num_servers]);
     *args.mutable_setup() = client_config;
-    cd.stream = std::move(cd.stub->RunTest(alloc_context()));
-    GPR_ASSERT(cd.stream->Write(args));
+    clients[i].stream =
+        std::move(clients[i].stub->RunTest(runsc::AllocContext(&contexts)));
+    GPR_ASSERT(clients[i].stream->Write(args));
     ClientStatus init_status;
-    GPR_ASSERT(cd.stream->Read(&init_status));
-
-    clients.push_back(std::move(cd));
+    GPR_ASSERT(clients[i].stream->Read(&init_status));
   }
 
   // Let everything warmup
@@ -195,23 +207,25 @@
   server_mark.mutable_mark();
   ClientArgs client_mark;
   client_mark.mutable_mark();
-  for (auto server = servers.begin(); server != servers.end(); server++) {
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Write(server_mark));
   }
-  for (auto client = clients.begin(); client != clients.end(); client++) {
+  for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Write(client_mark));
   }
   ServerStatus server_status;
   ClientStatus client_status;
-  for (auto server = servers.begin(); server != servers.end(); server++) {
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Read(&server_status));
   }
-  for (auto client = clients.begin(); client != clients.end(); client++) {
+  for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Read(&client_status));
   }
 
   // Wait some time
   gpr_log(GPR_INFO, "Running");
+  // Use gpr_sleep_until rather than this_thread::sleep_until to support
+  // compilers that don't work with this_thread
   gpr_sleep_until(gpr_time_add(
       start, gpr_time_from_seconds(benchmark_seconds, GPR_TIMESPAN)));
 
@@ -220,34 +234,36 @@
   result->client_config = result_client_config;
   result->server_config = result_server_config;
   gpr_log(GPR_INFO, "Finishing");
-  for (auto server = servers.begin(); server != servers.end(); server++) {
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Write(server_mark));
   }
-  for (auto client = clients.begin(); client != clients.end(); client++) {
+  for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Write(client_mark));
   }
-  for (auto server = servers.begin(); server != servers.end(); server++) {
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Read(&server_status));
     const auto& stats = server_status.stats();
-    result->server_resources.push_back(ResourceUsage{
-        stats.time_elapsed(), stats.time_user(), stats.time_system()});
+    result->server_resources.emplace_back(
+        stats.time_elapsed(), stats.time_user(), stats.time_system());
   }
-  for (auto client = clients.begin(); client != clients.end(); client++) {
+  for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Read(&client_status));
     const auto& stats = client_status.stats();
     result->latencies.MergeProto(stats.latencies());
-    result->client_resources.push_back(ResourceUsage{
-        stats.time_elapsed(), stats.time_user(), stats.time_system()});
+    result->client_resources.emplace_back(
+        stats.time_elapsed(), stats.time_user(), stats.time_system());
   }
 
-  for (auto client = clients.begin(); client != clients.end(); client++) {
+  for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->WritesDone());
     GPR_ASSERT(client->stream->Finish().ok());
   }
-  for (auto server = servers.begin(); server != servers.end(); server++) {
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->WritesDone());
     GPR_ASSERT(server->stream->Finish().ok());
   }
+  delete[] clients;
+  delete[] servers;
   return result;
 }
 }  // namespace testing
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index 5e9d4b3..9a29df8 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -41,10 +41,18 @@
 
 namespace grpc {
 namespace testing {
-struct ResourceUsage {
-  double wall_time;
-  double user_time;
-  double system_time;
+class ResourceUsage {
+ public:
+  ResourceUsage(double w, double u, double s)
+      : wall_time_(w), user_time_(u), system_time_(s) {}
+  double wall_time() const { return wall_time_; }
+  double user_time() const { return user_time_; }
+  double system_time() const { return system_time_; }
+
+ private:
+  double wall_time_;
+  double user_time_;
+  double system_time_;
 };
 
 struct ScenarioResult {
diff --git a/test/cpp/qps/interarrival.h b/test/cpp/qps/interarrival.h
index f90a17a..04d14f6 100644
--- a/test/cpp/qps/interarrival.h
+++ b/test/cpp/qps/interarrival.h
@@ -36,7 +36,8 @@
 
 #include <chrono>
 #include <cmath>
-#include <random>
+#include <cstdlib>
+#include <vector>
 
 #include <grpc++/config.h>
 
@@ -141,17 +142,16 @@
 // in an efficient re-entrant way. The random table is built at construction
 // time, and each call must include the thread id of the invoker
 
-typedef std::default_random_engine qps_random_engine;
-
 class InterarrivalTimer {
  public:
   InterarrivalTimer() {}
   void init(const RandomDist& r, int threads, int entries = 1000000) {
-    qps_random_engine gen;
-    std::uniform_real_distribution<double> uniform(0.0, 1.0);
     for (int i = 0; i < entries; i++) {
-      random_table_.push_back(std::chrono::nanoseconds(
-          static_cast<int64_t>(1e9 * r(uniform(gen)))));
+      // rand is the only choice that is portable across POSIX and Windows
+      // and that supports new and old compilers
+      const double uniform_0_1 = rand() / RAND_MAX;
+      random_table_.push_back(
+          std::chrono::nanoseconds(static_cast<int64_t>(1e9 * r(uniform_0_1))));
     }
     // Now set up the thread positions
     for (int i = 0; i < threads; i++) {
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index d534846..b1463be 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -33,6 +33,7 @@
 
 #include <memory>
 #include <set>
+#include <signal.h>
 
 #include <gflags/gflags.h>
 #include <grpc/support/log.h>
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index ff01ec1..e03e8e1 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -34,11 +34,16 @@
 #include "test/cpp/qps/report.h"
 
 #include <grpc/support/log.h>
+#include "test/cpp/qps/driver.h"
 #include "test/cpp/qps/stats.h"
 
 namespace grpc {
 namespace testing {
 
+static double WallTime(ResourceUsage u) { return u.wall_time(); }
+static double UserTime(ResourceUsage u) { return u.user_time(); }
+static double SystemTime(ResourceUsage u) { return u.system_time(); }
+
 void CompositeReporter::add(std::unique_ptr<Reporter> reporter) {
   reporters_.emplace_back(std::move(reporter));
 }
@@ -68,16 +73,14 @@
 }
 
 void GprLogReporter::ReportQPS(const ScenarioResult& result) {
-  gpr_log(GPR_INFO, "QPS: %.1f",
-          result.latencies.Count() /
-              average(result.client_resources,
-                      [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(
+      GPR_INFO, "QPS: %.1f",
+      result.latencies.Count() / average(result.client_resources, WallTime));
 }
 
 void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) {
-  auto qps = result.latencies.Count() /
-             average(result.client_resources,
-                     [](ResourceUsage u) { return u.wall_time; });
+  auto qps =
+      result.latencies.Count() / average(result.client_resources, WallTime);
 
   gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps,
           qps / result.server_config.threads());
@@ -95,40 +98,30 @@
 
 void GprLogReporter::ReportTimes(const ScenarioResult& result) {
   gpr_log(GPR_INFO, "Server system time: %.2f%%",
-          100.0 * sum(result.server_resources,
-                      [](ResourceUsage u) { return u.system_time; }) /
-              sum(result.server_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
+          100.0 * sum(result.server_resources, SystemTime) /
+              sum(result.server_resources, WallTime));
   gpr_log(GPR_INFO, "Server user time:   %.2f%%",
-          100.0 * sum(result.server_resources,
-                      [](ResourceUsage u) { return u.user_time; }) /
-              sum(result.server_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
+          100.0 * sum(result.server_resources, UserTime) /
+              sum(result.server_resources, WallTime));
   gpr_log(GPR_INFO, "Client system time: %.2f%%",
-          100.0 * sum(result.client_resources,
-                      [](ResourceUsage u) { return u.system_time; }) /
-              sum(result.client_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
+          100.0 * sum(result.client_resources, SystemTime) /
+              sum(result.client_resources, WallTime));
   gpr_log(GPR_INFO, "Client user time:   %.2f%%",
-          100.0 * sum(result.client_resources,
-                      [](ResourceUsage u) { return u.user_time; }) /
-              sum(result.client_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
+          100.0 * sum(result.client_resources, UserTime) /
+              sum(result.client_resources, WallTime));
 }
 
 void PerfDbReporter::ReportQPS(const ScenarioResult& result) {
-  auto qps = result.latencies.Count() /
-             average(result.client_resources,
-                     [](ResourceUsage u) { return u.wall_time; });
+  auto qps =
+      result.latencies.Count() / average(result.client_resources, WallTime);
 
   perf_db_client_.setQps(qps);
   perf_db_client_.setConfigs(result.client_config, result.server_config);
 }
 
 void PerfDbReporter::ReportQPSPerCore(const ScenarioResult& result) {
-  auto qps = result.latencies.Count() /
-             average(result.client_resources,
-                     [](ResourceUsage u) { return u.wall_time; });
+  auto qps =
+      result.latencies.Count() / average(result.client_resources, WallTime);
 
   auto qpsPerCore = qps / result.server_config.threads();
 
@@ -139,33 +132,29 @@
 
 void PerfDbReporter::ReportLatency(const ScenarioResult& result) {
   perf_db_client_.setLatencies(result.latencies.Percentile(50) / 1000,
-                             result.latencies.Percentile(90) / 1000,
-                             result.latencies.Percentile(95) / 1000,
-                             result.latencies.Percentile(99) / 1000,
-                             result.latencies.Percentile(99.9) / 1000);
+                               result.latencies.Percentile(90) / 1000,
+                               result.latencies.Percentile(95) / 1000,
+                               result.latencies.Percentile(99) / 1000,
+                               result.latencies.Percentile(99.9) / 1000);
   perf_db_client_.setConfigs(result.client_config, result.server_config);
 }
 
 void PerfDbReporter::ReportTimes(const ScenarioResult& result) {
-  double server_system_time =
-      100.0 * sum(result.server_resources,
-                  [](ResourceUsage u) { return u.system_time; }) /
-      sum(result.server_resources, [](ResourceUsage u) { return u.wall_time; });
-  double server_user_time =
-      100.0 * sum(result.server_resources,
-                  [](ResourceUsage u) { return u.user_time; }) /
-      sum(result.server_resources, [](ResourceUsage u) { return u.wall_time; });
-  double client_system_time =
-      100.0 * sum(result.client_resources,
-                  [](ResourceUsage u) { return u.system_time; }) /
-      sum(result.client_resources, [](ResourceUsage u) { return u.wall_time; });
-  double client_user_time =
-      100.0 * sum(result.client_resources,
-                  [](ResourceUsage u) { return u.user_time; }) /
-      sum(result.client_resources, [](ResourceUsage u) { return u.wall_time; });
+  const double server_system_time = 100.0 *
+                                    sum(result.server_resources, SystemTime) /
+                                    sum(result.server_resources, WallTime);
+  const double server_user_time = 100.0 *
+                                  sum(result.server_resources, UserTime) /
+                                  sum(result.server_resources, WallTime);
+  const double client_system_time = 100.0 *
+                                    sum(result.client_resources, SystemTime) /
+                                    sum(result.client_resources, WallTime);
+  const double client_user_time = 100.0 *
+                                  sum(result.client_resources, UserTime) /
+                                  sum(result.client_resources, WallTime);
 
-  perf_db_client_.setTimes(server_system_time, server_user_time, client_system_time,
-                         client_user_time);
+  perf_db_client_.setTimes(server_system_time, server_user_time,
+                           client_system_time, client_user_time);
   perf_db_client_.setConfigs(result.client_config, result.server_config);
 }
 
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 33b6fa5..b4fc49c 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -99,25 +99,7 @@
       shutdown_state_.emplace_back(new PerThreadShutdownState());
     }
     for (int i = 0; i < config.threads(); i++) {
-      threads_.push_back(std::thread([=]() {
-        // Wait until work is available or we are shutting down
-        bool ok;
-        void *got_tag;
-        while (srv_cqs_[i]->Next(&got_tag, &ok)) {
-          ServerRpcContext *ctx = detag(got_tag);
-          // The tag is a pointer to an RPC context to invoke
-          bool still_going = ctx->RunNextState(ok);
-          if (!shutdown_state_[i]->shutdown()) {
-            // this RPC context is done, so refresh it
-            if (!still_going) {
-              ctx->Reset();
-            }
-          } else {
-            return;
-          }
-        }
-        return;
-      }));
+      threads_.emplace_back(&AsyncQpsServerTest::ThreadFunc, this, i);
     }
   }
   ~AsyncQpsServerTest() {
@@ -142,6 +124,26 @@
   }
 
  private:
+  void ThreadFunc(int rank) {
+    // Wait until work is available or we are shutting down
+    bool ok;
+    void *got_tag;
+    while (srv_cqs_[rank]->Next(&got_tag, &ok)) {
+      ServerRpcContext *ctx = detag(got_tag);
+      // The tag is a pointer to an RPC context to invoke
+      const bool still_going = ctx->RunNextState(ok);
+      if (!shutdown_state_[rank]->shutdown()) {
+        // this RPC context is done, so refresh it
+        if (!still_going) {
+          ctx->Reset();
+        }
+      } else {
+        return;
+      }
+    }
+    return;
+  }
+
   class ServerRpcContext {
    public:
     ServerRpcContext() {}
diff --git a/test/cpp/util/echo.proto b/test/cpp/util/echo.proto
index 58ec680..8ea2f59 100644
--- a/test/cpp/util/echo.proto
+++ b/test/cpp/util/echo.proto
@@ -28,7 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-syntax = "proto2";
+syntax = "proto3";
 
 import "test/cpp/util/messages.proto";
 
@@ -41,3 +41,7 @@
   rpc BidiStream(stream EchoRequest) returns (stream EchoResponse);
   rpc Unimplemented(EchoRequest) returns (EchoResponse);
 }
+
+service UnimplementedService {
+  rpc Unimplemented(EchoRequest) returns (EchoResponse);
+}
diff --git a/test/cpp/util/echo_duplicate.proto b/test/cpp/util/echo_duplicate.proto
index e54c016..9c1d678 100644
--- a/test/cpp/util/echo_duplicate.proto
+++ b/test/cpp/util/echo_duplicate.proto
@@ -30,7 +30,7 @@
 
 // This is a partial copy of echo.proto with a different package name.
 
-syntax = "proto2";
+syntax = "proto3";
 
 import "test/cpp/util/messages.proto";
 
diff --git a/test/cpp/util/messages.proto b/test/cpp/util/messages.proto
index 24e199b..359d1db 100644
--- a/test/cpp/util/messages.proto
+++ b/test/cpp/util/messages.proto
@@ -28,32 +28,32 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-syntax = "proto2";
+syntax = "proto3";
 
 package grpc.cpp.test.util;
 
 message RequestParams {
-  optional bool echo_deadline = 1;
-  optional int32 client_cancel_after_us = 2;
-  optional int32 server_cancel_after_us = 3;
-  optional bool echo_metadata = 4;
-  optional bool check_auth_context = 5;
-  optional int32 response_message_length = 6;
-  optional bool echo_peer = 7;
+  bool echo_deadline = 1;
+  int32 client_cancel_after_us = 2;
+  int32 server_cancel_after_us = 3;
+  bool echo_metadata = 4;
+  bool check_auth_context = 5;
+  int32 response_message_length = 6;
+  bool echo_peer = 7;
 }
 
 message EchoRequest {
-  optional string message = 1;
-  optional RequestParams param = 2;
+  string message = 1;
+  RequestParams param = 2;
 }
 
 message ResponseParams {
-  optional int64 request_deadline = 1;
-  optional string host = 2;
-  optional string peer = 3;
+  int64 request_deadline = 1;
+  string host = 2;
+  string peer = 3;
 }
 
 message EchoResponse {
-  optional string message = 1;
-  optional ResponseParams param = 2;
+  string message = 1;
+  ResponseParams param = 2;
 }
diff --git a/test/proto/empty.proto b/test/proto/empty.proto
index 4295a0a..6d0eb93 100644
--- a/test/proto/empty.proto
+++ b/test/proto/empty.proto
@@ -28,7 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-syntax = "proto2";
+syntax = "proto3";
 
 package grpc.testing;
 
diff --git a/test/proto/messages.proto b/test/proto/messages.proto
index 89e5544..193b6c4 100644
--- a/test/proto/messages.proto
+++ b/test/proto/messages.proto
@@ -30,7 +30,7 @@
 
 // Message definitions to be used by integration test service definitions.
 
-syntax = "proto2";
+syntax = "proto3";
 
 package grpc.testing;
 
@@ -57,59 +57,59 @@
 // A block of data, to simply increase gRPC message size.
 message Payload {
   // The type of data in body.
-  optional PayloadType type = 1;
+  PayloadType type = 1;
   // Primary contents of payload.
-  optional bytes body = 2;
+  bytes body = 2;
 }
 
 // A protobuf representation for grpc status. This is used by test
 // clients to specify a status that the server should attempt to return.
-message EchoStatus { 
-  optional int32 code = 1;
-  optional string message = 2;
+message EchoStatus {
+  int32 code = 1;
+  string message = 2;
 }
 
 // Unary request.
 message SimpleRequest {
   // Desired payload type in the response from the server.
   // If response_type is RANDOM, server randomly chooses one from other formats.
-  optional PayloadType response_type = 1;
+  PayloadType response_type = 1;
 
   // Desired payload size in the response from the server.
   // If response_type is COMPRESSABLE, this denotes the size before compression.
-  optional int32 response_size = 2;
+  int32 response_size = 2;
 
   // Optional input payload sent along with the request.
-  optional Payload payload = 3;
+  Payload payload = 3;
 
   // Whether SimpleResponse should include username.
-  optional bool fill_username = 4;
+  bool fill_username = 4;
 
   // Whether SimpleResponse should include OAuth scope.
-  optional bool fill_oauth_scope = 5;
+  bool fill_oauth_scope = 5;
 
   // Compression algorithm to be used by the server for the response (stream)
-  optional CompressionType response_compression = 6;
+  CompressionType response_compression = 6;
 
   // Whether server should return a given status
-  optional EchoStatus response_status = 7;
+  EchoStatus response_status = 7;
 }
 
 // Unary response, as configured by the request.
 message SimpleResponse {
   // Payload to increase message size.
-  optional Payload payload = 1;
+  Payload payload = 1;
   // The user the request came from, for verifying authentication was
   // successful when the client expected it.
-  optional string username = 2;
+  string username = 2;
   // OAuth scope.
-  optional string oauth_scope = 3;
+  string oauth_scope = 3;
 }
 
 // Client-streaming request.
 message StreamingInputCallRequest {
   // Optional input payload sent along with the request.
-  optional Payload payload = 1;
+  Payload payload = 1;
 
   // Not expecting any payload from the response.
 }
@@ -117,18 +117,18 @@
 // Client-streaming response.
 message StreamingInputCallResponse {
   // Aggregated size of payloads received from the client.
-  optional int32 aggregated_payload_size = 1;
+  int32 aggregated_payload_size = 1;
 }
 
 // Configuration for a particular response.
 message ResponseParameters {
   // Desired payload sizes in responses from the server.
   // If response_type is COMPRESSABLE, this denotes the size before compression.
-  optional int32 size = 1;
+  int32 size = 1;
 
   // Desired interval between consecutive responses in the response stream in
   // microseconds.
-  optional int32 interval_us = 2;
+  int32 interval_us = 2;
 }
 
 // Server-streaming request.
@@ -137,31 +137,31 @@
   // If response_type is RANDOM, the payload from each response in the stream
   // might be of different types. This is to simulate a mixed type of payload
   // stream.
-  optional PayloadType response_type = 1;
+  PayloadType response_type = 1;
 
   // Configuration for each expected response message.
   repeated ResponseParameters response_parameters = 2;
 
   // Optional input payload sent along with the request.
-  optional Payload payload = 3;
+  Payload payload = 3;
 
   // Compression algorithm to be used by the server for the response (stream)
-  optional CompressionType response_compression = 6;
+  CompressionType response_compression = 6;
 
   // Whether server should return a given status
-  optional EchoStatus response_status = 7;
+  EchoStatus response_status = 7;
 }
 
 // Server-streaming response, as configured by the request and parameters.
 message StreamingOutputCallResponse {
   // Payload to increase response size.
-  optional Payload payload = 1;
+  Payload payload = 1;
 }
 
 // For reconnect interop test only.
 // Server tells client whether its reconnects are following the spec and the
 // reconnect backoffs it saw.
 message ReconnectInfo {
-  optional bool passed = 1;
+  bool passed = 1;
   repeated int32 backoff_ms = 2;
 }
diff --git a/test/proto/test.proto b/test/proto/test.proto
index 368522d..92aff23 100644
--- a/test/proto/test.proto
+++ b/test/proto/test.proto
@@ -31,7 +31,7 @@
 // An integration test service that covers all the method signature permutations
 // of unary/streaming requests/responses.
 
-syntax = "proto2";
+syntax = "proto3";
 
 import "test/proto/empty.proto";
 import "test/proto/messages.proto";
diff --git a/tools/dockerfile/grpc_go/Dockerfile b/tools/dockerfile/grpc_go/Dockerfile
index 06bb3e2..7f3bd87 100644
--- a/tools/dockerfile/grpc_go/Dockerfile
+++ b/tools/dockerfile/grpc_go/Dockerfile
@@ -32,6 +32,8 @@
 
 # Get the source from GitHub
 RUN go get google.golang.org/grpc
+RUN go get golang.org/x/oauth2
+RUN go get google.golang.org/cloud
 
 # Add a service_account directory containing the auth creds file
 ADD service_account service_account
diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/tools/dockerfile/grpc_go/build.sh
old mode 100644
new mode 100755
similarity index 82%
copy from src/ruby/bin/interop/test/cpp/interop/test.rb
copy to tools/dockerfile/grpc_go/build.sh
index 5948b50..254942f
--- a/src/ruby/bin/interop/test/cpp/interop/test.rb
+++ b/tools/dockerfile/grpc_go/build.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -27,17 +28,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/cpp/interop/test.proto
-
-require 'google/protobuf'
-
-require 'test/cpp/interop/empty'
-require 'test/cpp/interop/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
+cp -R /var/local/git-clone/grpc-go/. /go/
+go get golang.org/x/oauth2
+go get google.golang.org/cloud
+cd src/google.golang.org/grpc/interop/client && go install
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index d219ca7..4c83e22 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -772,7 +772,6 @@
 include/grpc/support/atm_gcc_atomic.h \
 include/grpc/support/atm_gcc_sync.h \
 include/grpc/support/atm_win32.h \
-include/grpc/support/cancellable_platform.h \
 include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
 include/grpc/support/histogram.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 1f66fe1..325a293 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -837,6 +837,7 @@
 src/core/iomgr/tcp_server.h \
 src/core/iomgr/tcp_windows.h \
 src/core/iomgr/time_averaged_stats.h \
+src/core/iomgr/udp_server.h \
 src/core/iomgr/wakeup_fd_pipe.h \
 src/core/iomgr/wakeup_fd_posix.h \
 src/core/json/json.h \
@@ -961,6 +962,7 @@
 src/core/iomgr/tcp_server_windows.c \
 src/core/iomgr/tcp_windows.c \
 src/core/iomgr/time_averaged_stats.c \
+src/core/iomgr/udp_server.c \
 src/core/iomgr/wakeup_fd_eventfd.c \
 src/core/iomgr/wakeup_fd_nospecial.c \
 src/core/iomgr/wakeup_fd_pipe.c \
@@ -1024,7 +1026,6 @@
 include/grpc/support/atm_gcc_atomic.h \
 include/grpc/support/atm_gcc_sync.h \
 include/grpc/support/atm_win32.h \
-include/grpc/support/cancellable_platform.h \
 include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
 include/grpc/support/histogram.h \
@@ -1055,7 +1056,6 @@
 src/core/support/string_win32.h \
 src/core/support/thd_internal.h \
 src/core/support/alloc.c \
-src/core/support/cancellable.c \
 src/core/support/cmdline.c \
 src/core/support/cpu_iphone.c \
 src/core/support/cpu_linux.c \
diff --git a/tools/jenkins/grpc_jenkins_slave/Dockerfile b/tools/jenkins/grpc_jenkins_slave/Dockerfile
index 9058b04..2f6f0f5 100644
--- a/tools/jenkins/grpc_jenkins_slave/Dockerfile
+++ b/tools/jenkins/grpc_jenkins_slave/Dockerfile
@@ -146,6 +146,14 @@
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
+##################
+# Zookeeper dependencies
+
+# Install dependencies
+
+RUN apt-get install -y libzookeeper-mt-dev
+
+
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile b/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
index 2beaf9a..d6457d3 100644
--- a/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
+++ b/tools/jenkins/grpc_jenkins_slave_32bits/Dockerfile
@@ -146,6 +146,14 @@
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
+##################
+# Zookeeper dependencies
+
+# Install dependencies
+
+RUN apt-get install -y libzookeeper-mt-dev
+
+
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 93cf82d..1ef7bb1 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -79,6 +79,7 @@
     -e "config=$config" \
     -e "language=$language" \
     -e "arch=$arch" \
+    -e "GRPC_ZOOKEEPER_SERVER_TEST=grpc-jenkins-master:2181" \
     -e CCACHE_DIR=/tmp/ccache \
     -i \
     -v "$git_root:/var/local/jenkins/grpc" \
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index 203c8b7..2efc2c7 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -34,8 +34,10 @@
 cd $(dirname $0)/../..
 
 ROOT=`pwd`
+PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
 GRPCIO=$ROOT/src/python/grpcio
 GRPCIO_TEST=$ROOT/src/python/grpcio_test
+GRPCIO_HEALTH_CHECKING=$ROOT/src/python/grpcio_health_checking
 
 make_virtualenv() {
   virtualenv_name="python"$1"_virtual_environment"
@@ -54,6 +56,9 @@
     cd $GRPCIO_TEST
     pip install -r requirements.txt
     pip install $GRPCIO_TEST
+
+    # Install grpcio_health_checking
+    pip install $GRPCIO_HEALTH_CHECKING
   else
     source $virtualenv_name/bin/activate
     # Uninstall and re-install the packages we care about. Don't use
@@ -62,12 +67,14 @@
     # dependency upgrades.
     (yes | pip uninstall grpcio) || true
     (yes | pip uninstall grpcio_test) || true
+    (yes | pip uninstall grpcio_health_checking) || true
     (CFLAGS="-I$ROOT/include -std=c89" LDFLAGS=-L$ROOT/libs/$CONFIG GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install $GRPCIO) || (
       # Fall back to rebuilding the entire environment
       rm -rf $virtualenv_name
       make_virtualenv $1
     )
     pip install $GRPCIO_TEST
+    pip install $GRPCIO_HEALTH_CHECKING
   fi
 }
 
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index b7e0089..538deac 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -131,7 +131,7 @@
   """Specifies what to run for a job."""
 
   def __init__(self, cmdline, shortname=None, environ=None, hash_targets=None,
-               cwd=None, shell=False, timeout_seconds=900):
+               cwd=None, shell=False, timeout_seconds=5*60):
     """
     Arguments:
       cmdline: a list of arguments to pass as the command line
@@ -194,6 +194,10 @@
       self._tempfile.seek(0)
       stdout = self._tempfile.read()
       filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))
+      # TODO: looks like jenkins master is slow because parsing the junit results XMLs is not
+      # implemented efficiently. This is an experiment to workaround the issue by making sure
+      # results.xml file is small enough.
+      filtered_stdout = filtered_stdout[-128:]
       if self._xml_test is not None:
         self._xml_test.set('time', str(elapsed))
         ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout
diff --git a/tools/run_tests/run_interops.py b/tools/run_tests/run_interops.py
index 4e6b5ce..e1d40d3 100755
--- a/tools/run_tests/run_interops.py
+++ b/tools/run_tests/run_interops.py
@@ -15,7 +15,10 @@
 jobs = []
 jobNumber = 0
 for test in _TESTS:
-  test_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_test.sh', '%s' % args.language, '%s' % test], shortname=test)
+  test_job = jobset.JobSpec(
+        cmdline=['tools/run_tests/run_interops_test.sh', '%s' % args.language, '%s' % test], 
+        shortname=test,
+        timeout_seconds=15*60)
   jobs.append(test_job)
   jobNumber+=1
 
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 47d2b61..1a6752c 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -470,7 +470,8 @@
                            '-j', '%d' % (multiprocessing.cpu_count() + 1),
                            'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
                                args.slowdown,
-                           'CONFIG=%s' % cfg] + targets)
+                           'CONFIG=%s' % cfg] + targets,
+                          timeout_seconds=30*60)
 
 build_steps = [make_jobspec(cfg,
                             list(set(itertools.chain.from_iterable(
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index d2c3ec3..627e6ac 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -230,18 +230,6 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "gpr_cancellable_test", 
-    "src": [
-      "test/core/support/cancellable_test.c"
-    ]
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util"
-    ], 
-    "headers": [], 
-    "language": "c", 
     "name": "gpr_cmdline_test", 
     "src": [
       "test/core/support/cmdline_test.c"
@@ -980,6 +968,20 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "udp_server_test", 
+    "src": [
+      "test/core/iomgr/udp_server_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "uri_parser_test", 
     "src": [
       "test/core/client_config/uri_parser_test.c"
@@ -1671,6 +1673,23 @@
   }, 
   {
     "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "grpc_zookeeper"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "zookeeper_test", 
+    "src": [
+      "test/cpp/end2end/zookeeper_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
       "end2end_certs", 
       "end2end_fixture_chttp2_fake_security", 
       "end2end_test_bad_hostname", 
@@ -12087,7 +12106,6 @@
       "include/grpc/support/atm_gcc_atomic.h", 
       "include/grpc/support/atm_gcc_sync.h", 
       "include/grpc/support/atm_win32.h", 
-      "include/grpc/support/cancellable_platform.h", 
       "include/grpc/support/cmdline.h", 
       "include/grpc/support/cpu.h", 
       "include/grpc/support/histogram.h", 
@@ -12126,7 +12144,6 @@
       "include/grpc/support/atm_gcc_atomic.h", 
       "include/grpc/support/atm_gcc_sync.h", 
       "include/grpc/support/atm_win32.h", 
-      "include/grpc/support/cancellable_platform.h", 
       "include/grpc/support/cmdline.h", 
       "include/grpc/support/cpu.h", 
       "include/grpc/support/histogram.h", 
@@ -12150,7 +12167,6 @@
       "include/grpc/support/tls_pthread.h", 
       "include/grpc/support/useful.h", 
       "src/core/support/alloc.c", 
-      "src/core/support/cancellable.c", 
       "src/core/support/cmdline.c", 
       "src/core/support/cpu_iphone.c", 
       "src/core/support/cpu_linux.c", 
@@ -12281,6 +12297,7 @@
       "src/core/iomgr/tcp_server.h", 
       "src/core/iomgr/tcp_windows.h", 
       "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_pipe.h", 
       "src/core/iomgr/wakeup_fd_posix.h", 
       "src/core/json/json.h", 
@@ -12469,6 +12486,8 @@
       "src/core/iomgr/tcp_windows.h", 
       "src/core/iomgr/time_averaged_stats.c", 
       "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/udp_server.c", 
+      "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_eventfd.c", 
       "src/core/iomgr/wakeup_fd_nospecial.c", 
       "src/core/iomgr/wakeup_fd_pipe.c", 
@@ -12752,6 +12771,7 @@
       "src/core/iomgr/tcp_server.h", 
       "src/core/iomgr/tcp_windows.h", 
       "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_pipe.h", 
       "src/core/iomgr/wakeup_fd_posix.h", 
       "src/core/json/json.h", 
@@ -12925,6 +12945,8 @@
       "src/core/iomgr/tcp_windows.h", 
       "src/core/iomgr/time_averaged_stats.c", 
       "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/udp_server.c", 
+      "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_eventfd.c", 
       "src/core/iomgr/wakeup_fd_nospecial.c", 
       "src/core/iomgr/wakeup_fd_pipe.c", 
@@ -13028,6 +13050,23 @@
   {
     "deps": [
       "gpr", 
+      "grpc"
+    ], 
+    "headers": [
+      "include/grpc/grpc_zookeeper.h", 
+      "src/core/client_config/resolvers/zookeeper_resolver.h"
+    ], 
+    "language": "c", 
+    "name": "grpc_zookeeper", 
+    "src": [
+      "include/grpc/grpc_zookeeper.h", 
+      "src/core/client_config/resolvers/zookeeper_resolver.c", 
+      "src/core/client_config/resolvers/zookeeper_resolver.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "gpr_test_util", 
       "grpc", 
       "grpc_test_util"
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 471dae0..6b3183d 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -221,23 +221,6 @@
     ], 
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_cancellable_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ]
-  }, 
-  {
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "flaky": false, 
-    "language": "c", 
     "name": "gpr_cmdline_test", 
     "platforms": [
       "linux", 
@@ -1056,6 +1039,17 @@
   }, 
   {
     "ci_platforms": [
+      "posix"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "udp_server_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "ci_platforms": [
       "linux", 
       "mac", 
       "posix", 
@@ -1481,6 +1475,23 @@
   {
     "ci_platforms": [
       "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "zookeeper_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "ci_platforms": [
+      "linux", 
       "posix", 
       "windows"
     ], 
diff --git a/vsprojects/Grpc.mak b/vsprojects/Grpc.mak
index 15f45a5..96b3a79 100644
--- a/vsprojects/Grpc.mak
+++ b/vsprojects/Grpc.mak
@@ -77,13 +77,13 @@
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
-build_libs: build_gpr build_gpr_test_util build_grpc build_grpc_test_util build_grpc_test_util_unsecure build_grpc_unsecure Debug\reconnect_server.lib build_grpc++ Debug\grpc++_test_config.lib Debug\grpc++_test_util.lib build_grpc++_unsecure Debug\interop_client_helper.lib Debug\interop_client_main.lib Debug\interop_server_helper.lib Debug\interop_server_main.lib Debug\qps.lib Debug\end2end_fixture_chttp2_fake_security.lib Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_fixture_chttp2_fullstack_with_proxy.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack_with_proxy.lib Debug\end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.lib Debug\end2end_fixture_chttp2_socket_pair.lib Debug\end2end_fixture_chttp2_socket_pair_one_byte_at_a_time.lib Debug\end2end_fixture_chttp2_socket_pair_with_grpc_trace.lib Debug\end2end_test_bad_hostname.lib Debug\end2end_test_cancel_after_accept.lib Debug\end2end_test_cancel_after_accept_and_writes_closed.lib Debug\end2end_test_cancel_after_invoke.lib Debug\end2end_test_cancel_before_invoke.lib Debug\end2end_test_cancel_in_a_vacuum.lib Debug\end2end_test_census_simple_request.lib Debug\end2end_test_channel_connectivity.lib Debug\end2end_test_default_host.lib Debug\end2end_test_disappearing_server.lib Debug\end2end_test_early_server_shutdown_finishes_inflight_calls.lib Debug\end2end_test_early_server_shutdown_finishes_tags.lib Debug\end2end_test_empty_batch.lib Debug\end2end_test_graceful_server_shutdown.lib Debug\end2end_test_invoke_large_request.lib Debug\end2end_test_max_concurrent_streams.lib Debug\end2end_test_max_message_length.lib Debug\end2end_test_no_op.lib Debug\end2end_test_ping_pong_streaming.lib Debug\end2end_test_registered_call.lib Debug\end2end_test_request_response_with_binary_metadata_and_payload.lib Debug\end2end_test_request_response_with_metadata_and_payload.lib Debug\end2end_test_request_response_with_payload.lib Debug\end2end_test_request_response_with_payload_and_call_creds.lib Debug\end2end_test_request_response_with_trailing_metadata_and_payload.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_test_request_with_flags.lib Debug\end2end_test_request_with_large_metadata.lib Debug\end2end_test_request_with_payload.lib Debug\end2end_test_server_finishes_request.lib Debug\end2end_test_simple_delayed_request.lib Debug\end2end_test_simple_request.lib Debug\end2end_test_simple_request_with_high_initial_sequence_number.lib Debug\end2end_certs.lib Debug\bad_client_test.lib 
+build_libs: build_gpr build_gpr_test_util build_grpc build_grpc_test_util build_grpc_test_util_unsecure build_grpc_unsecure Debug\grpc_zookeeper.lib Debug\reconnect_server.lib build_grpc++ Debug\grpc++_test_config.lib Debug\grpc++_test_util.lib build_grpc++_unsecure Debug\interop_client_helper.lib Debug\interop_client_main.lib Debug\interop_server_helper.lib Debug\interop_server_main.lib Debug\qps.lib Debug\end2end_fixture_chttp2_fake_security.lib Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_fixture_chttp2_fullstack_with_proxy.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack_with_proxy.lib Debug\end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.lib Debug\end2end_fixture_chttp2_socket_pair.lib Debug\end2end_fixture_chttp2_socket_pair_one_byte_at_a_time.lib Debug\end2end_fixture_chttp2_socket_pair_with_grpc_trace.lib Debug\end2end_test_bad_hostname.lib Debug\end2end_test_cancel_after_accept.lib Debug\end2end_test_cancel_after_accept_and_writes_closed.lib Debug\end2end_test_cancel_after_invoke.lib Debug\end2end_test_cancel_before_invoke.lib Debug\end2end_test_cancel_in_a_vacuum.lib Debug\end2end_test_census_simple_request.lib Debug\end2end_test_channel_connectivity.lib Debug\end2end_test_default_host.lib Debug\end2end_test_disappearing_server.lib Debug\end2end_test_early_server_shutdown_finishes_inflight_calls.lib Debug\end2end_test_early_server_shutdown_finishes_tags.lib Debug\end2end_test_empty_batch.lib Debug\end2end_test_graceful_server_shutdown.lib Debug\end2end_test_invoke_large_request.lib Debug\end2end_test_max_concurrent_streams.lib Debug\end2end_test_max_message_length.lib Debug\end2end_test_no_op.lib Debug\end2end_test_ping_pong_streaming.lib Debug\end2end_test_registered_call.lib Debug\end2end_test_request_response_with_binary_metadata_and_payload.lib Debug\end2end_test_request_response_with_metadata_and_payload.lib Debug\end2end_test_request_response_with_payload.lib Debug\end2end_test_request_response_with_payload_and_call_creds.lib Debug\end2end_test_request_response_with_trailing_metadata_and_payload.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_test_request_with_flags.lib Debug\end2end_test_request_with_large_metadata.lib Debug\end2end_test_request_with_payload.lib Debug\end2end_test_server_finishes_request.lib Debug\end2end_test_simple_delayed_request.lib Debug\end2end_test_simple_request.lib Debug\end2end_test_simple_request_with_high_initial_sequence_number.lib Debug\end2end_certs.lib Debug\bad_client_test.lib 
 buildtests: buildtests_c buildtests_cxx
 
-buildtests_c: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe fling_client.exe fling_server.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_stack_lockfree_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_tls_test.exe gpr_useful_test.exe grpc_auth_context_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_jwt_verifier_test.exe grpc_security_connector_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe json_rewrite.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe multi_init_test.exe multiple_server_queues_test.exe murmur_hash_test.exe no_server_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe time_averaged_stats_test.exe timeout_encoding_test.exe timers_test.exe transport_metadata_test.exe transport_security_test.exe uri_parser_test.exe chttp2_fake_security_bad_hostname_test.exe chttp2_fake_security_cancel_after_accept_test.exe chttp2_fake_security_cancel_after_accept_and_writes_closed_test.exe chttp2_fake_security_cancel_after_invoke_test.exe chttp2_fake_security_cancel_before_invoke_test.exe chttp2_fake_security_cancel_in_a_vacuum_test.exe chttp2_fake_security_census_simple_request_test.exe chttp2_fake_security_channel_connectivity_test.exe chttp2_fake_security_default_host_test.exe chttp2_fake_security_disappearing_server_test.exe chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fake_security_early_server_shutdown_finishes_tags_test.exe chttp2_fake_security_empty_batch_test.exe chttp2_fake_security_graceful_server_shutdown_test.exe chttp2_fake_security_invoke_large_request_test.exe chttp2_fake_security_max_concurrent_streams_test.exe chttp2_fake_security_max_message_length_test.exe chttp2_fake_security_no_op_test.exe chttp2_fake_security_ping_pong_streaming_test.exe chttp2_fake_security_registered_call_test.exe chttp2_fake_security_request_response_with_binary_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_payload_test.exe chttp2_fake_security_request_response_with_payload_and_call_creds_test.exe chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fake_security_request_with_compressed_payload_test.exe chttp2_fake_security_request_with_flags_test.exe chttp2_fake_security_request_with_large_metadata_test.exe chttp2_fake_security_request_with_payload_test.exe chttp2_fake_security_server_finishes_request_test.exe chttp2_fake_security_simple_delayed_request_test.exe chttp2_fake_security_simple_request_test.exe chttp2_fake_security_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_test.exe chttp2_fullstack_cancel_after_accept_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_cancel_after_invoke_test.exe chttp2_fullstack_cancel_before_invoke_test.exe chttp2_fullstack_cancel_in_a_vacuum_test.exe chttp2_fullstack_census_simple_request_test.exe chttp2_fullstack_channel_connectivity_test.exe chttp2_fullstack_default_host_test.exe chttp2_fullstack_disappearing_server_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_empty_batch_test.exe chttp2_fullstack_graceful_server_shutdown_test.exe chttp2_fullstack_invoke_large_request_test.exe chttp2_fullstack_max_concurrent_streams_test.exe chttp2_fullstack_max_message_length_test.exe chttp2_fullstack_no_op_test.exe chttp2_fullstack_ping_pong_streaming_test.exe chttp2_fullstack_registered_call_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_payload_test.exe chttp2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_request_with_compressed_payload_test.exe chttp2_fullstack_request_with_flags_test.exe chttp2_fullstack_request_with_large_metadata_test.exe chttp2_fullstack_request_with_payload_test.exe chttp2_fullstack_server_finishes_request_test.exe chttp2_fullstack_simple_delayed_request_test.exe chttp2_fullstack_simple_request_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_compression_bad_hostname_test.exe chttp2_fullstack_compression_cancel_after_accept_test.exe chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_compression_cancel_after_invoke_test.exe chttp2_fullstack_compression_cancel_before_invoke_test.exe chttp2_fullstack_compression_cancel_in_a_vacuum_test.exe chttp2_fullstack_compression_census_simple_request_test.exe chttp2_fullstack_compression_channel_connectivity_test.exe chttp2_fullstack_compression_default_host_test.exe chttp2_fullstack_compression_disappearing_server_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_compression_empty_batch_test.exe chttp2_fullstack_compression_graceful_server_shutdown_test.exe chttp2_fullstack_compression_invoke_large_request_test.exe chttp2_fullstack_compression_max_concurrent_streams_test.exe chttp2_fullstack_compression_max_message_length_test.exe chttp2_fullstack_compression_no_op_test.exe chttp2_fullstack_compression_ping_pong_streaming_test.exe chttp2_fullstack_compression_registered_call_test.exe chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_compression_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_compression_request_response_with_payload_test.exe chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_compression_request_with_compressed_payload_test.exe chttp2_fullstack_compression_request_with_flags_test.exe chttp2_fullstack_compression_request_with_large_metadata_test.exe chttp2_fullstack_compression_request_with_payload_test.exe chttp2_fullstack_compression_server_finishes_request_test.exe chttp2_fullstack_compression_simple_delayed_request_test.exe chttp2_fullstack_compression_simple_request_test.exe chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_with_proxy_bad_hostname_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_with_proxy_cancel_after_invoke_test.exe chttp2_fullstack_with_proxy_cancel_before_invoke_test.exe chttp2_fullstack_with_proxy_cancel_in_a_vacuum_test.exe chttp2_fullstack_with_proxy_census_simple_request_test.exe chttp2_fullstack_with_proxy_default_host_test.exe chttp2_fullstack_with_proxy_disappearing_server_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_with_proxy_empty_batch_test.exe chttp2_fullstack_with_proxy_graceful_server_shutdown_test.exe chttp2_fullstack_with_proxy_invoke_large_request_test.exe chttp2_fullstack_with_proxy_max_message_length_test.exe chttp2_fullstack_with_proxy_no_op_test.exe chttp2_fullstack_with_proxy_ping_pong_streaming_test.exe chttp2_fullstack_with_proxy_registered_call_test.exe chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_with_proxy_request_response_with_payload_test.exe chttp2_fullstack_with_proxy_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_with_proxy_request_with_large_metadata_test.exe chttp2_fullstack_with_proxy_request_with_payload_test.exe chttp2_fullstack_with_proxy_server_finishes_request_test.exe chttp2_fullstack_with_proxy_simple_delayed_request_test.exe chttp2_fullstack_with_proxy_simple_request_test.exe chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_fullstack_bad_hostname_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_fullstack_census_simple_request_test.exe chttp2_simple_ssl_fullstack_channel_connectivity_test.exe chttp2_simple_ssl_fullstack_default_host_test.exe chttp2_simple_ssl_fullstack_disappearing_server_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_fullstack_empty_batch_test.exe chttp2_simple_ssl_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_fullstack_max_message_length_test.exe chttp2_simple_ssl_fullstack_no_op_test.exe chttp2_simple_ssl_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_fullstack_registered_call_test.exe chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_with_compressed_payload_test.exe chttp2_simple_ssl_fullstack_request_with_flags_test.exe chttp2_simple_ssl_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_fullstack_request_with_payload_test.exe chttp2_simple_ssl_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_fullstack_simple_request_test.exe chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_fullstack_with_proxy_bad_hostname_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_after_invoke_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_before_invoke_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_fullstack_with_proxy_census_simple_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_default_host_test.exe chttp2_simple_ssl_fullstack_with_proxy_disappearing_server_test.exe chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_fullstack_with_proxy_empty_batch_test.exe chttp2_simple_ssl_fullstack_with_proxy_graceful_server_shutdown_test.exe chttp2_simple_ssl_fullstack_with_proxy_invoke_large_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_max_message_length_test.exe chttp2_simple_ssl_fullstack_with_proxy_no_op_test.exe chttp2_simple_ssl_fullstack_with_proxy_ping_pong_streaming_test.exe chttp2_simple_ssl_fullstack_with_proxy_registered_call_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_with_large_metadata_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_with_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_server_finishes_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_simple_delayed_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_simple_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_channel_connectivity_test.exe chttp2_simple_ssl_with_oauth2_fullstack_default_host_test.exe chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test.exe chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test.exe chttp2_simple_ssl_with_oauth2_fullstack_no_op_test.exe chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_bad_hostname_test.exe chttp2_socket_pair_cancel_after_accept_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_cancel_after_invoke_test.exe chttp2_socket_pair_cancel_before_invoke_test.exe chttp2_socket_pair_cancel_in_a_vacuum_test.exe chttp2_socket_pair_census_simple_request_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_empty_batch_test.exe chttp2_socket_pair_graceful_server_shutdown_test.exe chttp2_socket_pair_invoke_large_request_test.exe chttp2_socket_pair_max_concurrent_streams_test.exe chttp2_socket_pair_max_message_length_test.exe chttp2_socket_pair_no_op_test.exe chttp2_socket_pair_ping_pong_streaming_test.exe chttp2_socket_pair_registered_call_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_payload_test.exe chttp2_socket_pair_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_request_with_compressed_payload_test.exe chttp2_socket_pair_request_with_flags_test.exe chttp2_socket_pair_request_with_large_metadata_test.exe chttp2_socket_pair_request_with_payload_test.exe chttp2_socket_pair_server_finishes_request_test.exe chttp2_socket_pair_simple_request_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_test.exe chttp2_socket_pair_with_grpc_trace_no_op_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_unsecure_test.exe chttp2_fullstack_cancel_after_accept_unsecure_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_census_simple_request_unsecure_test.exe chttp2_fullstack_channel_connectivity_unsecure_test.exe chttp2_fullstack_default_host_unsecure_test.exe chttp2_fullstack_disappearing_server_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_empty_batch_unsecure_test.exe chttp2_fullstack_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_invoke_large_request_unsecure_test.exe chttp2_fullstack_max_concurrent_streams_unsecure_test.exe chttp2_fullstack_max_message_length_unsecure_test.exe chttp2_fullstack_no_op_unsecure_test.exe chttp2_fullstack_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_registered_call_unsecure_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_payload_unsecure_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_with_compressed_payload_unsecure_test.exe chttp2_fullstack_request_with_flags_unsecure_test.exe chttp2_fullstack_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_request_with_payload_unsecure_test.exe chttp2_fullstack_server_finishes_request_unsecure_test.exe chttp2_fullstack_simple_delayed_request_unsecure_test.exe chttp2_fullstack_simple_request_unsecure_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_fullstack_compression_bad_hostname_unsecure_test.exe chttp2_fullstack_compression_cancel_after_accept_unsecure_test.exe chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_compression_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_compression_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_compression_census_simple_request_unsecure_test.exe chttp2_fullstack_compression_channel_connectivity_unsecure_test.exe chttp2_fullstack_compression_default_host_unsecure_test.exe chttp2_fullstack_compression_disappearing_server_unsecure_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_compression_empty_batch_unsecure_test.exe chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_compression_invoke_large_request_unsecure_test.exe chttp2_fullstack_compression_max_concurrent_streams_unsecure_test.exe chttp2_fullstack_compression_max_message_length_unsecure_test.exe chttp2_fullstack_compression_no_op_unsecure_test.exe chttp2_fullstack_compression_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_compression_registered_call_unsecure_test.exe chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_compression_request_response_with_payload_unsecure_test.exe chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test.exe chttp2_fullstack_compression_request_with_flags_unsecure_test.exe chttp2_fullstack_compression_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_compression_request_with_payload_unsecure_test.exe chttp2_fullstack_compression_server_finishes_request_unsecure_test.exe chttp2_fullstack_compression_simple_delayed_request_unsecure_test.exe chttp2_fullstack_compression_simple_request_unsecure_test.exe chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_fullstack_with_proxy_bad_hostname_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_with_proxy_census_simple_request_unsecure_test.exe chttp2_fullstack_with_proxy_default_host_unsecure_test.exe chttp2_fullstack_with_proxy_disappearing_server_unsecure_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_with_proxy_empty_batch_unsecure_test.exe chttp2_fullstack_with_proxy_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_with_proxy_invoke_large_request_unsecure_test.exe chttp2_fullstack_with_proxy_max_message_length_unsecure_test.exe chttp2_fullstack_with_proxy_no_op_unsecure_test.exe chttp2_fullstack_with_proxy_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_with_proxy_registered_call_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_with_proxy_request_with_payload_unsecure_test.exe chttp2_fullstack_with_proxy_server_finishes_request_unsecure_test.exe chttp2_fullstack_with_proxy_simple_delayed_request_unsecure_test.exe chttp2_fullstack_with_proxy_simple_request_unsecure_test.exe chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_bad_hostname_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_census_simple_request_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_empty_batch_unsecure_test.exe chttp2_socket_pair_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_invoke_large_request_unsecure_test.exe chttp2_socket_pair_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_max_message_length_unsecure_test.exe chttp2_socket_pair_no_op_unsecure_test.exe chttp2_socket_pair_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_registered_call_unsecure_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_with_compressed_payload_unsecure_test.exe chttp2_socket_pair_request_with_flags_unsecure_test.exe chttp2_socket_pair_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_request_with_payload_unsecure_test.exe chttp2_socket_pair_server_finishes_request_unsecure_test.exe chttp2_socket_pair_simple_request_unsecure_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test.exe connection_prefix_bad_client_test.exe initial_settings_frame_bad_client_test.exe 
+buildtests_c: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe fling_client.exe fling_server.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_stack_lockfree_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_tls_test.exe gpr_useful_test.exe grpc_auth_context_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_jwt_verifier_test.exe grpc_security_connector_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe json_rewrite.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe multi_init_test.exe multiple_server_queues_test.exe murmur_hash_test.exe no_server_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe time_averaged_stats_test.exe timeout_encoding_test.exe timers_test.exe transport_metadata_test.exe transport_security_test.exe uri_parser_test.exe chttp2_fake_security_bad_hostname_test.exe chttp2_fake_security_cancel_after_accept_test.exe chttp2_fake_security_cancel_after_accept_and_writes_closed_test.exe chttp2_fake_security_cancel_after_invoke_test.exe chttp2_fake_security_cancel_before_invoke_test.exe chttp2_fake_security_cancel_in_a_vacuum_test.exe chttp2_fake_security_census_simple_request_test.exe chttp2_fake_security_channel_connectivity_test.exe chttp2_fake_security_default_host_test.exe chttp2_fake_security_disappearing_server_test.exe chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fake_security_early_server_shutdown_finishes_tags_test.exe chttp2_fake_security_empty_batch_test.exe chttp2_fake_security_graceful_server_shutdown_test.exe chttp2_fake_security_invoke_large_request_test.exe chttp2_fake_security_max_concurrent_streams_test.exe chttp2_fake_security_max_message_length_test.exe chttp2_fake_security_no_op_test.exe chttp2_fake_security_ping_pong_streaming_test.exe chttp2_fake_security_registered_call_test.exe chttp2_fake_security_request_response_with_binary_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_payload_test.exe chttp2_fake_security_request_response_with_payload_and_call_creds_test.exe chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fake_security_request_with_compressed_payload_test.exe chttp2_fake_security_request_with_flags_test.exe chttp2_fake_security_request_with_large_metadata_test.exe chttp2_fake_security_request_with_payload_test.exe chttp2_fake_security_server_finishes_request_test.exe chttp2_fake_security_simple_delayed_request_test.exe chttp2_fake_security_simple_request_test.exe chttp2_fake_security_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_test.exe chttp2_fullstack_cancel_after_accept_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_cancel_after_invoke_test.exe chttp2_fullstack_cancel_before_invoke_test.exe chttp2_fullstack_cancel_in_a_vacuum_test.exe chttp2_fullstack_census_simple_request_test.exe chttp2_fullstack_channel_connectivity_test.exe chttp2_fullstack_default_host_test.exe chttp2_fullstack_disappearing_server_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_empty_batch_test.exe chttp2_fullstack_graceful_server_shutdown_test.exe chttp2_fullstack_invoke_large_request_test.exe chttp2_fullstack_max_concurrent_streams_test.exe chttp2_fullstack_max_message_length_test.exe chttp2_fullstack_no_op_test.exe chttp2_fullstack_ping_pong_streaming_test.exe chttp2_fullstack_registered_call_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_payload_test.exe chttp2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_request_with_compressed_payload_test.exe chttp2_fullstack_request_with_flags_test.exe chttp2_fullstack_request_with_large_metadata_test.exe chttp2_fullstack_request_with_payload_test.exe chttp2_fullstack_server_finishes_request_test.exe chttp2_fullstack_simple_delayed_request_test.exe chttp2_fullstack_simple_request_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_compression_bad_hostname_test.exe chttp2_fullstack_compression_cancel_after_accept_test.exe chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_compression_cancel_after_invoke_test.exe chttp2_fullstack_compression_cancel_before_invoke_test.exe chttp2_fullstack_compression_cancel_in_a_vacuum_test.exe chttp2_fullstack_compression_census_simple_request_test.exe chttp2_fullstack_compression_channel_connectivity_test.exe chttp2_fullstack_compression_default_host_test.exe chttp2_fullstack_compression_disappearing_server_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_compression_empty_batch_test.exe chttp2_fullstack_compression_graceful_server_shutdown_test.exe chttp2_fullstack_compression_invoke_large_request_test.exe chttp2_fullstack_compression_max_concurrent_streams_test.exe chttp2_fullstack_compression_max_message_length_test.exe chttp2_fullstack_compression_no_op_test.exe chttp2_fullstack_compression_ping_pong_streaming_test.exe chttp2_fullstack_compression_registered_call_test.exe chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_compression_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_compression_request_response_with_payload_test.exe chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_compression_request_with_compressed_payload_test.exe chttp2_fullstack_compression_request_with_flags_test.exe chttp2_fullstack_compression_request_with_large_metadata_test.exe chttp2_fullstack_compression_request_with_payload_test.exe chttp2_fullstack_compression_server_finishes_request_test.exe chttp2_fullstack_compression_simple_delayed_request_test.exe chttp2_fullstack_compression_simple_request_test.exe chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_with_proxy_bad_hostname_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_with_proxy_cancel_after_invoke_test.exe chttp2_fullstack_with_proxy_cancel_before_invoke_test.exe chttp2_fullstack_with_proxy_cancel_in_a_vacuum_test.exe chttp2_fullstack_with_proxy_census_simple_request_test.exe chttp2_fullstack_with_proxy_default_host_test.exe chttp2_fullstack_with_proxy_disappearing_server_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_with_proxy_empty_batch_test.exe chttp2_fullstack_with_proxy_graceful_server_shutdown_test.exe chttp2_fullstack_with_proxy_invoke_large_request_test.exe chttp2_fullstack_with_proxy_max_message_length_test.exe chttp2_fullstack_with_proxy_no_op_test.exe chttp2_fullstack_with_proxy_ping_pong_streaming_test.exe chttp2_fullstack_with_proxy_registered_call_test.exe chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_with_proxy_request_response_with_payload_test.exe chttp2_fullstack_with_proxy_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_with_proxy_request_with_large_metadata_test.exe chttp2_fullstack_with_proxy_request_with_payload_test.exe chttp2_fullstack_with_proxy_server_finishes_request_test.exe chttp2_fullstack_with_proxy_simple_delayed_request_test.exe chttp2_fullstack_with_proxy_simple_request_test.exe chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_fullstack_bad_hostname_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_fullstack_census_simple_request_test.exe chttp2_simple_ssl_fullstack_channel_connectivity_test.exe chttp2_simple_ssl_fullstack_default_host_test.exe chttp2_simple_ssl_fullstack_disappearing_server_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_fullstack_empty_batch_test.exe chttp2_simple_ssl_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_fullstack_max_message_length_test.exe chttp2_simple_ssl_fullstack_no_op_test.exe chttp2_simple_ssl_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_fullstack_registered_call_test.exe chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_with_compressed_payload_test.exe chttp2_simple_ssl_fullstack_request_with_flags_test.exe chttp2_simple_ssl_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_fullstack_request_with_payload_test.exe chttp2_simple_ssl_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_fullstack_simple_request_test.exe chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_fullstack_with_proxy_bad_hostname_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_after_invoke_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_before_invoke_test.exe chttp2_simple_ssl_fullstack_with_proxy_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_fullstack_with_proxy_census_simple_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_default_host_test.exe chttp2_simple_ssl_fullstack_with_proxy_disappearing_server_test.exe chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_fullstack_with_proxy_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_fullstack_with_proxy_empty_batch_test.exe chttp2_simple_ssl_fullstack_with_proxy_graceful_server_shutdown_test.exe chttp2_simple_ssl_fullstack_with_proxy_invoke_large_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_max_message_length_test.exe chttp2_simple_ssl_fullstack_with_proxy_no_op_test.exe chttp2_simple_ssl_fullstack_with_proxy_ping_pong_streaming_test.exe chttp2_simple_ssl_fullstack_with_proxy_registered_call_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_with_large_metadata_test.exe chttp2_simple_ssl_fullstack_with_proxy_request_with_payload_test.exe chttp2_simple_ssl_fullstack_with_proxy_server_finishes_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_simple_delayed_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_simple_request_test.exe chttp2_simple_ssl_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_channel_connectivity_test.exe chttp2_simple_ssl_with_oauth2_fullstack_default_host_test.exe chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test.exe chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test.exe chttp2_simple_ssl_with_oauth2_fullstack_no_op_test.exe chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_bad_hostname_test.exe chttp2_socket_pair_cancel_after_accept_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_cancel_after_invoke_test.exe chttp2_socket_pair_cancel_before_invoke_test.exe chttp2_socket_pair_cancel_in_a_vacuum_test.exe chttp2_socket_pair_census_simple_request_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_empty_batch_test.exe chttp2_socket_pair_graceful_server_shutdown_test.exe chttp2_socket_pair_invoke_large_request_test.exe chttp2_socket_pair_max_concurrent_streams_test.exe chttp2_socket_pair_max_message_length_test.exe chttp2_socket_pair_no_op_test.exe chttp2_socket_pair_ping_pong_streaming_test.exe chttp2_socket_pair_registered_call_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_payload_test.exe chttp2_socket_pair_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_request_with_compressed_payload_test.exe chttp2_socket_pair_request_with_flags_test.exe chttp2_socket_pair_request_with_large_metadata_test.exe chttp2_socket_pair_request_with_payload_test.exe chttp2_socket_pair_server_finishes_request_test.exe chttp2_socket_pair_simple_request_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_test.exe chttp2_socket_pair_with_grpc_trace_no_op_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_unsecure_test.exe chttp2_fullstack_cancel_after_accept_unsecure_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_census_simple_request_unsecure_test.exe chttp2_fullstack_channel_connectivity_unsecure_test.exe chttp2_fullstack_default_host_unsecure_test.exe chttp2_fullstack_disappearing_server_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_empty_batch_unsecure_test.exe chttp2_fullstack_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_invoke_large_request_unsecure_test.exe chttp2_fullstack_max_concurrent_streams_unsecure_test.exe chttp2_fullstack_max_message_length_unsecure_test.exe chttp2_fullstack_no_op_unsecure_test.exe chttp2_fullstack_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_registered_call_unsecure_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_payload_unsecure_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_with_compressed_payload_unsecure_test.exe chttp2_fullstack_request_with_flags_unsecure_test.exe chttp2_fullstack_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_request_with_payload_unsecure_test.exe chttp2_fullstack_server_finishes_request_unsecure_test.exe chttp2_fullstack_simple_delayed_request_unsecure_test.exe chttp2_fullstack_simple_request_unsecure_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_fullstack_compression_bad_hostname_unsecure_test.exe chttp2_fullstack_compression_cancel_after_accept_unsecure_test.exe chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_compression_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_compression_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_compression_census_simple_request_unsecure_test.exe chttp2_fullstack_compression_channel_connectivity_unsecure_test.exe chttp2_fullstack_compression_default_host_unsecure_test.exe chttp2_fullstack_compression_disappearing_server_unsecure_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_compression_empty_batch_unsecure_test.exe chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_compression_invoke_large_request_unsecure_test.exe chttp2_fullstack_compression_max_concurrent_streams_unsecure_test.exe chttp2_fullstack_compression_max_message_length_unsecure_test.exe chttp2_fullstack_compression_no_op_unsecure_test.exe chttp2_fullstack_compression_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_compression_registered_call_unsecure_test.exe chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_compression_request_response_with_payload_unsecure_test.exe chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test.exe chttp2_fullstack_compression_request_with_flags_unsecure_test.exe chttp2_fullstack_compression_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_compression_request_with_payload_unsecure_test.exe chttp2_fullstack_compression_server_finishes_request_unsecure_test.exe chttp2_fullstack_compression_simple_delayed_request_unsecure_test.exe chttp2_fullstack_compression_simple_request_unsecure_test.exe chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_fullstack_with_proxy_bad_hostname_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_with_proxy_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_with_proxy_census_simple_request_unsecure_test.exe chttp2_fullstack_with_proxy_default_host_unsecure_test.exe chttp2_fullstack_with_proxy_disappearing_server_unsecure_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_with_proxy_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_with_proxy_empty_batch_unsecure_test.exe chttp2_fullstack_with_proxy_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_with_proxy_invoke_large_request_unsecure_test.exe chttp2_fullstack_with_proxy_max_message_length_unsecure_test.exe chttp2_fullstack_with_proxy_no_op_unsecure_test.exe chttp2_fullstack_with_proxy_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_with_proxy_registered_call_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_with_proxy_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_with_proxy_request_with_payload_unsecure_test.exe chttp2_fullstack_with_proxy_server_finishes_request_unsecure_test.exe chttp2_fullstack_with_proxy_simple_delayed_request_unsecure_test.exe chttp2_fullstack_with_proxy_simple_request_unsecure_test.exe chttp2_fullstack_with_proxy_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_bad_hostname_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_census_simple_request_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_empty_batch_unsecure_test.exe chttp2_socket_pair_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_invoke_large_request_unsecure_test.exe chttp2_socket_pair_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_max_message_length_unsecure_test.exe chttp2_socket_pair_no_op_unsecure_test.exe chttp2_socket_pair_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_registered_call_unsecure_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_with_compressed_payload_unsecure_test.exe chttp2_socket_pair_request_with_flags_unsecure_test.exe chttp2_socket_pair_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_request_with_payload_unsecure_test.exe chttp2_socket_pair_server_finishes_request_unsecure_test.exe chttp2_socket_pair_simple_request_unsecure_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test.exe connection_prefix_bad_client_test.exe initial_settings_frame_bad_client_test.exe 
 	echo All C tests built.
 
-buildtests_cxx: async_end2end_test.exe auth_property_iterator_test.exe channel_arguments_test.exe cli_call_test.exe client_crash_test_server.exe credentials_test.exe cxx_byte_buffer_test.exe cxx_slice_test.exe cxx_time_test.exe dynamic_thread_pool_test.exe end2end_test.exe fixed_size_thread_pool_test.exe generic_end2end_test.exe grpc_cli.exe mock_test.exe reconnect_interop_client.exe reconnect_interop_server.exe secure_auth_context_test.exe server_crash_test_client.exe status_test.exe thread_stress_test.exe 
+buildtests_cxx: async_end2end_test.exe auth_property_iterator_test.exe channel_arguments_test.exe cli_call_test.exe client_crash_test_server.exe credentials_test.exe cxx_byte_buffer_test.exe cxx_slice_test.exe cxx_time_test.exe dynamic_thread_pool_test.exe end2end_test.exe fixed_size_thread_pool_test.exe generic_end2end_test.exe grpc_cli.exe mock_test.exe reconnect_interop_client.exe reconnect_interop_server.exe secure_auth_context_test.exe server_crash_test_client.exe status_test.exe thread_stress_test.exe zookeeper_test.exe 
 	echo All C++ tests built.
 
 
@@ -175,14 +175,6 @@
 	echo Running gen_hpack_tables
 	$(OUT_DIR)\gen_hpack_tables.exe
 
-gpr_cancellable_test.exe: build_gpr_test_util build_gpr $(OUT_DIR)
-	echo Building gpr_cancellable_test
-	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\cancellable_test.c 
-	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_cancellable_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\cancellable_test.obj 
-gpr_cancellable_test: gpr_cancellable_test.exe
-	echo Running gpr_cancellable_test
-	$(OUT_DIR)\gpr_cancellable_test.exe
-
 gpr_cmdline_test.exe: build_gpr_test_util build_gpr $(OUT_DIR)
 	echo Building gpr_cmdline_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\cmdline_test.c 
@@ -783,6 +775,14 @@
 	echo Running thread_stress_test
 	$(OUT_DIR)\thread_stress_test.exe
 
+zookeeper_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ Debug\grpc_zookeeper.lib build_grpc build_gpr_test_util build_gpr $(OUT_DIR)
+	echo Building zookeeper_test
+    $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\end2end\zookeeper_test.cc 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\zookeeper_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc_zookeeper.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\zookeeper_test.obj 
+zookeeper_test: zookeeper_test.exe
+	echo Running zookeeper_test
+	$(OUT_DIR)\zookeeper_test.exe
+
 chttp2_fake_security_bad_hostname_test.exe: Debug\end2end_fixture_chttp2_fake_security.lib Debug\end2end_test_bad_hostname.lib Debug\end2end_certs.lib build_grpc_test_util build_grpc build_gpr_test_util build_gpr $(OUT_DIR)
 	echo Building chttp2_fake_security_bad_hostname_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -4705,6 +4705,14 @@
 build_grpc_unsecure:
 	msbuild grpc.sln /t:grpc_unsecure /p:Configuration=Debug /p:Linkage-grpc_dependencies_zlib=static
 
+grpc_zookeeper.exe: build_gpr build_grpc $(OUT_DIR)
+	echo Building grpc_zookeeper
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\src\core\client_config\resolvers\zookeeper_resolver.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_zookeeper.exe" Debug\gpr.lib Debug\grpc.lib $(LIBS) $(OUT_DIR)\zookeeper_resolver.obj 
+grpc_zookeeper: grpc_zookeeper.exe
+	echo Running grpc_zookeeper
+	$(OUT_DIR)\grpc_zookeeper.exe
+
 Debug\reconnect_server.lib: $(OUT_DIR)
 	echo Building reconnect_server
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\util\reconnect_server.c 
diff --git a/vsprojects/gpr/gpr.vcxproj b/vsprojects/gpr/gpr.vcxproj
index 1d1d813..83c2956 100644
--- a/vsprojects/gpr/gpr.vcxproj
+++ b/vsprojects/gpr/gpr.vcxproj
@@ -127,7 +127,6 @@
     <ClInclude Include="..\..\include\grpc\support\atm_gcc_atomic.h" />
     <ClInclude Include="..\..\include\grpc\support\atm_gcc_sync.h" />
     <ClInclude Include="..\..\include\grpc\support\atm_win32.h" />
-    <ClInclude Include="..\..\include\grpc\support\cancellable_platform.h" />
     <ClInclude Include="..\..\include\grpc\support\cmdline.h" />
     <ClInclude Include="..\..\include\grpc\support\cpu.h" />
     <ClInclude Include="..\..\include\grpc\support\histogram.h" />
@@ -163,8 +162,6 @@
   <ItemGroup>
     <ClCompile Include="..\..\src\core\support\alloc.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\support\cancellable.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\support\cmdline.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_iphone.c">
diff --git a/vsprojects/gpr/gpr.vcxproj.filters b/vsprojects/gpr/gpr.vcxproj.filters
index ace549f..64b9092 100644
--- a/vsprojects/gpr/gpr.vcxproj.filters
+++ b/vsprojects/gpr/gpr.vcxproj.filters
@@ -4,9 +4,6 @@
     <ClCompile Include="..\..\src\core\support\alloc.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\support\cancellable.c">
-      <Filter>src\core\support</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\support\cmdline.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -132,9 +129,6 @@
     <ClInclude Include="..\..\include\grpc\support\atm_win32.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\include\grpc\support\cancellable_platform.h">
-      <Filter>include\grpc\support</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\include\grpc\support\cmdline.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index 42ddef4..0a9b5c2 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -52,6 +52,15 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_zookeeper", "grpc_zookeeper\grpc_zookeeper.vcxproj", "{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}"
+	ProjectSection(myProperties) = preProject
+        	lib = "True"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++", "grpc++\grpc++.vcxproj", "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -178,6 +187,22 @@
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release-DLL|Win32.Build.0 = Release-DLL|Win32
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release-DLL|x64.ActiveCfg = Release-DLL|x64
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release-DLL|x64.Build.0 = Release-DLL|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.ActiveCfg = Debug|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.ActiveCfg = Release|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.ActiveCfg = Release|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.Build.0 = Debug|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.Build.0 = Debug|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.Build.0 = Release|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.Build.0 = Release|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|x64.Build.0 = Debug|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|Win32.Build.0 = Release|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|x64.ActiveCfg = Release|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|x64.Build.0 = Release|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Debug|Win32.ActiveCfg = Debug|Win32
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Debug|x64.ActiveCfg = Debug|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/grpc/grpc.vcxproj b/vsprojects/grpc/grpc.vcxproj
index 067f341..ebdc926 100644
--- a/vsprojects/grpc/grpc.vcxproj
+++ b/vsprojects/grpc/grpc.vcxproj
@@ -299,6 +299,7 @@
     <ClInclude Include="..\..\src\core\iomgr\tcp_server.h" />
     <ClInclude Include="..\..\src\core\iomgr\tcp_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="..\..\src\core\iomgr\udp_server.h" />
     <ClInclude Include="..\..\src\core\iomgr\wakeup_fd_pipe.h" />
     <ClInclude Include="..\..\src\core\iomgr\wakeup_fd_posix.h" />
     <ClInclude Include="..\..\src\core\json\json.h" />
@@ -505,6 +506,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\time_averaged_stats.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\udp_server.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\wakeup_fd_eventfd.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\wakeup_fd_nospecial.c">
diff --git a/vsprojects/grpc/grpc.vcxproj.filters b/vsprojects/grpc/grpc.vcxproj.filters
index fcc40c3..baec0db 100644
--- a/vsprojects/grpc/grpc.vcxproj.filters
+++ b/vsprojects/grpc/grpc.vcxproj.filters
@@ -241,6 +241,9 @@
     <ClCompile Include="..\..\src\core\iomgr\time_averaged_stats.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\udp_server.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\wakeup_fd_eventfd.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
@@ -650,6 +653,9 @@
     <ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\iomgr\udp_server.h">
+      <Filter>src\core\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\iomgr\wakeup_fd_pipe.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/grpc_csharp_ext.sln b/vsprojects/grpc_csharp_ext.sln
index df84f3d..aa41d87 100644
--- a/vsprojects/grpc_csharp_ext.sln
+++ b/vsprojects/grpc_csharp_ext.sln
@@ -24,6 +24,15 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_zookeeper", "grpc_zookeeper\grpc_zookeeper.vcxproj", "{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}"
+	ProjectSection(myProperties) = preProject
+        	lib = "True"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_csharp_ext", "grpc_csharp_ext\grpc_csharp_ext.vcxproj", "{D64C6D63-4458-4A88-AB38-35678384A7E4}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -65,6 +74,14 @@
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|Win32.Build.0 = Release-DLL|Win32
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|x64.ActiveCfg = Release-DLL|x64
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|x64.Build.0 = Release-DLL|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.Build.0 = Debug|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.ActiveCfg = Debug|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.Build.0 = Debug|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.ActiveCfg = Release|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.Build.0 = Release|Win32
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.ActiveCfg = Release|x64
+		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.Build.0 = Release|x64
 		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Debug|Win32.Build.0 = Debug|Win32
 		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Debug|x64.ActiveCfg = Debug|x64
diff --git a/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj b/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
index f73f2dd..5325430 100644
--- a/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
+++ b/vsprojects/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
@@ -31,23 +31,12 @@
   <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
     <PlatformToolset>v120</PlatformToolset>
   </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
@@ -56,33 +45,16 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+  <ImportGroup Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="..\global.props" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="..\global.props" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="..\global.props" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="..\winsock.props" />
     <Import Project="..\global.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
     <TargetName>grpc_test_util_unsecure</TargetName>
   </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <TargetName>grpc_test_util_unsecure</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <TargetName>grpc_test_util_unsecure</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
     <TargetName>grpc_test_util_unsecure</TargetName>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -92,6 +64,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -105,6 +78,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -120,6 +94,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -137,6 +112,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -146,11 +122,23 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\test\core\end2end\cq_verifier.h" />
+    <ClInclude Include="..\..\test\core\end2end\fixtures\proxy.h" />
+    <ClInclude Include="..\..\test\core\iomgr\endpoint_tests.h" />
+    <ClInclude Include="..\..\test\core\security\oauth2_utils.h" />
+    <ClInclude Include="..\..\test\core\util\grpc_profiler.h" />
+    <ClInclude Include="..\..\test\core\util\parse_hexstring.h" />
+    <ClInclude Include="..\..\test\core\util\port.h" />
+    <ClInclude Include="..\..\test\core\util\slice_splitter.h" />
+  </ItemGroup>
+  <ItemGroup>
     <ClCompile Include="..\..\test\core\end2end\cq_verifier.c">
     </ClCompile>
+    <ClCompile Include="..\..\test\core\end2end\fixtures\proxy.c">
+    </ClCompile>
     <ClCompile Include="..\..\test\core\iomgr\endpoint_tests.c">
     </ClCompile>
-    <ClCompile Include="..\..\test\core\statistics\census_log_tests.c">
+    <ClCompile Include="..\..\test\core\security\oauth2_utils.c">
     </ClCompile>
     <ClCompile Include="..\..\test\core\util\grpc_profiler.c">
     </ClCompile>
diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
index b95658b..1d60839 100644
--- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
@@ -282,6 +282,7 @@
     <ClInclude Include="..\..\src\core\iomgr\tcp_server.h" />
     <ClInclude Include="..\..\src\core\iomgr\tcp_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="..\..\src\core\iomgr\udp_server.h" />
     <ClInclude Include="..\..\src\core\iomgr\wakeup_fd_pipe.h" />
     <ClInclude Include="..\..\src\core\iomgr\wakeup_fd_posix.h" />
     <ClInclude Include="..\..\src\core\json\json.h" />
@@ -448,6 +449,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\time_averaged_stats.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\udp_server.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\wakeup_fd_eventfd.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\wakeup_fd_nospecial.c">
diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 05e9d13..cb9e8c2 100644
--- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -181,6 +181,9 @@
     <ClCompile Include="..\..\src\core\iomgr\time_averaged_stats.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\udp_server.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\wakeup_fd_eventfd.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
@@ -548,6 +551,9 @@
     <ClInclude Include="..\..\src\core\iomgr\time_averaged_stats.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\iomgr\udp_server.h">
+      <Filter>src\core\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\iomgr\wakeup_fd_pipe.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>