Resolved merge conflicts
diff --git a/.gitignore b/.gitignore
index 9c9ae5a..89bd100 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,8 @@
 libs
 objs
 
-# Python virtual environment (pre-3.4 only)
-python2.7_virtual_environment
+# Python virtual environments
+python*_virtual_environment
 
 # gcov coverage data
 coverage
@@ -31,3 +31,5 @@
 # vim temp files
 .*.swp
 
+# Makefile's cache
+cache.mk
diff --git a/.travis.yml b/.travis.yml
index c626242..b6c8062 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,8 @@
   - echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
   - echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
   - sudo apt-get update -qq
-  - sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv clang-3.5
+  - sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv python-dev python3-dev clang-3.5
+  - sudo pip install --upgrade virtualenv
   - sudo pip install cpp-coveralls mako simplejson
   - sudo apt-get install -qq mono-devel nunit
   - wget www.nuget.org/NuGet.exe -O nuget.exe
@@ -34,7 +35,7 @@
   - if [ ! -z "$USE_GCC" ] ; then export CC=gcc-$USE_GCC ; export CXX=g++-$USE_GCC ; fi
   - ./tools/run_tests/run_tests.py -l $TEST -t -j $JOBS -c $CONFIG -s 4.0
 after_success:
-  - if [ "$CONFIG" = "gcov" ] ; then coveralls --exclude third_party --exclude gens --exclude test --exclude src/compiler -b. --gcov-options '\-p' ; fi
+  - if [ "$CONFIG" = "gcov" ] ; then coveralls --exclude third_party --exclude gens --exclude test --exclude tools --exclude src/compiler -b. --gcov-options '\-p' ; fi
 notifications:
   email: false
   webhooks:
diff --git a/BUILD b/BUILD
index 46e4f67..e116d45 100644
--- a/BUILD
+++ b/BUILD
@@ -1,7 +1,9 @@
 # GRPC Bazel BUILD file.
-# This currently builds C and C++ code.
+# This currently builds C, C++ and Objective-C code.
 # This file has been automatically generated from a template file.
 # Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
 
 # Copyright 2015, Google Inc.
 # All rights reserved.
@@ -45,6 +47,7 @@
     "src/core/support/env.h",
     "src/core/support/file.h",
     "src/core/support/murmur_hash.h",
+    "src/core/support/stack_lockfree.h",
     "src/core/support/string.h",
     "src/core/support/string_win32.h",
     "src/core/support/thd_internal.h",
@@ -71,6 +74,7 @@
     "src/core/support/murmur_hash.c",
     "src/core/support/slice.c",
     "src/core/support/slice_buffer.c",
+    "src/core/support/stack_lockfree.c",
     "src/core/support/string.c",
     "src/core/support/string_posix.c",
     "src/core/support/string_win32.c",
@@ -136,6 +140,7 @@
     "src/core/security/base64.h",
     "src/core/security/credentials.h",
     "src/core/security/json_token.h",
+    "src/core/security/jwt_verifier.h",
     "src/core/security/secure_endpoint.h",
     "src/core/security/secure_transport_setup.h",
     "src/core/security/security_connector.h",
@@ -148,14 +153,25 @@
     "src/core/channel/census_filter.h",
     "src/core/channel/channel_args.h",
     "src/core/channel/channel_stack.h",
-    "src/core/channel/child_channel.h",
     "src/core/channel/client_channel.h",
-    "src/core/channel/client_setup.h",
+    "src/core/channel/compress_filter.h",
     "src/core/channel/connected_channel.h",
     "src/core/channel/context.h",
     "src/core/channel/http_client_filter.h",
     "src/core/channel/http_server_filter.h",
     "src/core/channel/noop_filter.h",
+    "src/core/client_config/client_config.h",
+    "src/core/client_config/connector.h",
+    "src/core/client_config/lb_policies/pick_first.h",
+    "src/core/client_config/lb_policy.h",
+    "src/core/client_config/resolver.h",
+    "src/core/client_config/resolver_factory.h",
+    "src/core/client_config/resolver_registry.h",
+    "src/core/client_config/resolvers/dns_resolver.h",
+    "src/core/client_config/resolvers/unix_resolver_posix.h",
+    "src/core/client_config/subchannel.h",
+    "src/core/client_config/subchannel_factory.h",
+    "src/core/client_config/uri_parser.h",
     "src/core/compression/message_compress.h",
     "src/core/debug/trace.h",
     "src/core/iomgr/alarm.h",
@@ -169,10 +185,11 @@
     "src/core/iomgr/iomgr_internal.h",
     "src/core/iomgr/iomgr_posix.h",
     "src/core/iomgr/pollset.h",
-    "src/core/iomgr/pollset_kick.h",
     "src/core/iomgr/pollset_kick_posix.h",
-    "src/core/iomgr/pollset_kick_windows.h",
     "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_set.h",
+    "src/core/iomgr/pollset_set_posix.h",
+    "src/core/iomgr/pollset_set_windows.h",
     "src/core/iomgr/pollset_windows.h",
     "src/core/iomgr/resolve_address.h",
     "src/core/iomgr/sockaddr.h",
@@ -197,7 +214,6 @@
     "src/core/surface/byte_buffer_queue.h",
     "src/core/surface/call.h",
     "src/core/surface/channel.h",
-    "src/core/surface/client.h",
     "src/core/surface/completion_queue.h",
     "src/core/surface/event_string.h",
     "src/core/surface/init.h",
@@ -216,12 +232,15 @@
     "src/core/transport/chttp2/hpack_table.h",
     "src/core/transport/chttp2/http2_errors.h",
     "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/incoming_metadata.h",
+    "src/core/transport/chttp2/internal.h",
     "src/core/transport/chttp2/status_conversion.h",
     "src/core/transport/chttp2/stream_encoder.h",
     "src/core/transport/chttp2/stream_map.h",
     "src/core/transport/chttp2/timeout_encoding.h",
     "src/core/transport/chttp2/varint.h",
     "src/core/transport/chttp2_transport.h",
+    "src/core/transport/connectivity_state.h",
     "src/core/transport/metadata.h",
     "src/core/transport/stream_op.h",
     "src/core/transport/transport.h",
@@ -239,6 +258,7 @@
     "src/core/security/credentials_win32.c",
     "src/core/security/google_default_credentials.c",
     "src/core/security/json_token.c",
+    "src/core/security/jwt_verifier.c",
     "src/core/security/secure_endpoint.c",
     "src/core/security/secure_transport_setup.c",
     "src/core/security/security_connector.c",
@@ -253,13 +273,24 @@
     "src/core/census/grpc_context.c",
     "src/core/channel/channel_args.c",
     "src/core/channel/channel_stack.c",
-    "src/core/channel/child_channel.c",
     "src/core/channel/client_channel.c",
-    "src/core/channel/client_setup.c",
+    "src/core/channel/compress_filter.c",
     "src/core/channel/connected_channel.c",
     "src/core/channel/http_client_filter.c",
     "src/core/channel/http_server_filter.c",
     "src/core/channel/noop_filter.c",
+    "src/core/client_config/client_config.c",
+    "src/core/client_config/connector.c",
+    "src/core/client_config/lb_policies/pick_first.c",
+    "src/core/client_config/lb_policy.c",
+    "src/core/client_config/resolver.c",
+    "src/core/client_config/resolver_factory.c",
+    "src/core/client_config/resolver_registry.c",
+    "src/core/client_config/resolvers/dns_resolver.c",
+    "src/core/client_config/resolvers/unix_resolver_posix.c",
+    "src/core/client_config/subchannel.c",
+    "src/core/client_config/subchannel_factory.c",
+    "src/core/client_config/uri_parser.c",
     "src/core/compression/algorithm.c",
     "src/core/compression/message_compress.c",
     "src/core/debug/trace.c",
@@ -273,10 +304,12 @@
     "src/core/iomgr/iomgr.c",
     "src/core/iomgr/iomgr_posix.c",
     "src/core/iomgr/iomgr_windows.c",
-    "src/core/iomgr/pollset_kick.c",
+    "src/core/iomgr/pollset_kick_posix.c",
     "src/core/iomgr/pollset_multipoller_with_epoll.c",
     "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
     "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_set_posix.c",
+    "src/core/iomgr/pollset_set_windows.c",
     "src/core/iomgr/pollset_windows.c",
     "src/core/iomgr/resolve_address_posix.c",
     "src/core/iomgr/resolve_address_windows.c",
@@ -310,7 +343,6 @@
     "src/core/surface/call_log_batch.c",
     "src/core/surface/channel.c",
     "src/core/surface/channel_create.c",
-    "src/core/surface/client.c",
     "src/core/surface/completion_queue.c",
     "src/core/surface/event_string.c",
     "src/core/surface/init.c",
@@ -320,6 +352,7 @@
     "src/core/surface/server_chttp2.c",
     "src/core/surface/server_create.c",
     "src/core/surface/surface_trace.c",
+    "src/core/surface/version.c",
     "src/core/transport/chttp2/alpn.c",
     "src/core/transport/chttp2/bin_encoder.c",
     "src/core/transport/chttp2/frame_data.c",
@@ -331,12 +364,17 @@
     "src/core/transport/chttp2/hpack_parser.c",
     "src/core/transport/chttp2/hpack_table.c",
     "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/incoming_metadata.c",
+    "src/core/transport/chttp2/parsing.c",
     "src/core/transport/chttp2/status_conversion.c",
     "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_lists.c",
     "src/core/transport/chttp2/stream_map.c",
     "src/core/transport/chttp2/timeout_encoding.c",
     "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2/writing.c",
     "src/core/transport/chttp2_transport.c",
+    "src/core/transport/connectivity_state.c",
     "src/core/transport/metadata.c",
     "src/core/transport/stream_op.c",
     "src/core/transport/transport.c",
@@ -371,14 +409,25 @@
     "src/core/channel/census_filter.h",
     "src/core/channel/channel_args.h",
     "src/core/channel/channel_stack.h",
-    "src/core/channel/child_channel.h",
     "src/core/channel/client_channel.h",
-    "src/core/channel/client_setup.h",
+    "src/core/channel/compress_filter.h",
     "src/core/channel/connected_channel.h",
     "src/core/channel/context.h",
     "src/core/channel/http_client_filter.h",
     "src/core/channel/http_server_filter.h",
     "src/core/channel/noop_filter.h",
+    "src/core/client_config/client_config.h",
+    "src/core/client_config/connector.h",
+    "src/core/client_config/lb_policies/pick_first.h",
+    "src/core/client_config/lb_policy.h",
+    "src/core/client_config/resolver.h",
+    "src/core/client_config/resolver_factory.h",
+    "src/core/client_config/resolver_registry.h",
+    "src/core/client_config/resolvers/dns_resolver.h",
+    "src/core/client_config/resolvers/unix_resolver_posix.h",
+    "src/core/client_config/subchannel.h",
+    "src/core/client_config/subchannel_factory.h",
+    "src/core/client_config/uri_parser.h",
     "src/core/compression/message_compress.h",
     "src/core/debug/trace.h",
     "src/core/iomgr/alarm.h",
@@ -392,10 +441,11 @@
     "src/core/iomgr/iomgr_internal.h",
     "src/core/iomgr/iomgr_posix.h",
     "src/core/iomgr/pollset.h",
-    "src/core/iomgr/pollset_kick.h",
     "src/core/iomgr/pollset_kick_posix.h",
-    "src/core/iomgr/pollset_kick_windows.h",
     "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_set.h",
+    "src/core/iomgr/pollset_set_posix.h",
+    "src/core/iomgr/pollset_set_windows.h",
     "src/core/iomgr/pollset_windows.h",
     "src/core/iomgr/resolve_address.h",
     "src/core/iomgr/sockaddr.h",
@@ -420,7 +470,6 @@
     "src/core/surface/byte_buffer_queue.h",
     "src/core/surface/call.h",
     "src/core/surface/channel.h",
-    "src/core/surface/client.h",
     "src/core/surface/completion_queue.h",
     "src/core/surface/event_string.h",
     "src/core/surface/init.h",
@@ -439,12 +488,15 @@
     "src/core/transport/chttp2/hpack_table.h",
     "src/core/transport/chttp2/http2_errors.h",
     "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/incoming_metadata.h",
+    "src/core/transport/chttp2/internal.h",
     "src/core/transport/chttp2/status_conversion.h",
     "src/core/transport/chttp2/stream_encoder.h",
     "src/core/transport/chttp2/stream_map.h",
     "src/core/transport/chttp2/timeout_encoding.h",
     "src/core/transport/chttp2/varint.h",
     "src/core/transport/chttp2_transport.h",
+    "src/core/transport/connectivity_state.h",
     "src/core/transport/metadata.h",
     "src/core/transport/stream_op.h",
     "src/core/transport/transport.h",
@@ -454,13 +506,24 @@
     "src/core/census/grpc_context.c",
     "src/core/channel/channel_args.c",
     "src/core/channel/channel_stack.c",
-    "src/core/channel/child_channel.c",
     "src/core/channel/client_channel.c",
-    "src/core/channel/client_setup.c",
+    "src/core/channel/compress_filter.c",
     "src/core/channel/connected_channel.c",
     "src/core/channel/http_client_filter.c",
     "src/core/channel/http_server_filter.c",
     "src/core/channel/noop_filter.c",
+    "src/core/client_config/client_config.c",
+    "src/core/client_config/connector.c",
+    "src/core/client_config/lb_policies/pick_first.c",
+    "src/core/client_config/lb_policy.c",
+    "src/core/client_config/resolver.c",
+    "src/core/client_config/resolver_factory.c",
+    "src/core/client_config/resolver_registry.c",
+    "src/core/client_config/resolvers/dns_resolver.c",
+    "src/core/client_config/resolvers/unix_resolver_posix.c",
+    "src/core/client_config/subchannel.c",
+    "src/core/client_config/subchannel_factory.c",
+    "src/core/client_config/uri_parser.c",
     "src/core/compression/algorithm.c",
     "src/core/compression/message_compress.c",
     "src/core/debug/trace.c",
@@ -474,10 +537,12 @@
     "src/core/iomgr/iomgr.c",
     "src/core/iomgr/iomgr_posix.c",
     "src/core/iomgr/iomgr_windows.c",
-    "src/core/iomgr/pollset_kick.c",
+    "src/core/iomgr/pollset_kick_posix.c",
     "src/core/iomgr/pollset_multipoller_with_epoll.c",
     "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
     "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_set_posix.c",
+    "src/core/iomgr/pollset_set_windows.c",
     "src/core/iomgr/pollset_windows.c",
     "src/core/iomgr/resolve_address_posix.c",
     "src/core/iomgr/resolve_address_windows.c",
@@ -511,7 +576,6 @@
     "src/core/surface/call_log_batch.c",
     "src/core/surface/channel.c",
     "src/core/surface/channel_create.c",
-    "src/core/surface/client.c",
     "src/core/surface/completion_queue.c",
     "src/core/surface/event_string.c",
     "src/core/surface/init.c",
@@ -521,6 +585,7 @@
     "src/core/surface/server_chttp2.c",
     "src/core/surface/server_create.c",
     "src/core/surface/surface_trace.c",
+    "src/core/surface/version.c",
     "src/core/transport/chttp2/alpn.c",
     "src/core/transport/chttp2/bin_encoder.c",
     "src/core/transport/chttp2/frame_data.c",
@@ -532,12 +597,17 @@
     "src/core/transport/chttp2/hpack_parser.c",
     "src/core/transport/chttp2/hpack_table.c",
     "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/incoming_metadata.c",
+    "src/core/transport/chttp2/parsing.c",
     "src/core/transport/chttp2/status_conversion.c",
     "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_lists.c",
     "src/core/transport/chttp2/stream_map.c",
     "src/core/transport/chttp2/timeout_encoding.c",
     "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2/writing.c",
     "src/core/transport/chttp2_transport.c",
+    "src/core/transport/connectivity_state.c",
     "src/core/transport/metadata.c",
     "src/core/transport/stream_op.c",
     "src/core/transport/transport.c",
@@ -567,16 +637,19 @@
   name = "grpc++",
   srcs = [
     "src/cpp/client/secure_credentials.h",
+    "src/cpp/common/secure_auth_context.h",
     "src/cpp/server/secure_server_credentials.h",
     "src/cpp/client/channel.h",
-    "src/cpp/proto/proto_utils.h",
-    "src/cpp/server/thread_pool.h",
+    "src/cpp/common/create_auth_context.h",
+    "src/cpp/client/secure_channel_arguments.cc",
     "src/cpp/client/secure_credentials.cc",
+    "src/cpp/common/auth_property_iterator.cc",
+    "src/cpp/common/secure_auth_context.cc",
+    "src/cpp/common/secure_create_auth_context.cc",
     "src/cpp/server/secure_server_credentials.cc",
     "src/cpp/client/channel.cc",
     "src/cpp/client/channel_arguments.cc",
     "src/cpp/client/client_context.cc",
-    "src/cpp/client/client_unary_call.cc",
     "src/cpp/client/create_channel.cc",
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
@@ -588,12 +661,12 @@
     "src/cpp/proto/proto_utils.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
+    "src/cpp/server/fixed_size_thread_pool.cc",
     "src/cpp/server/insecure_server_credentials.cc",
     "src/cpp/server/server.cc",
     "src/cpp/server/server_builder.cc",
     "src/cpp/server/server_context.cc",
     "src/cpp/server/server_credentials.cc",
-    "src/cpp/server/thread_pool.cc",
     "src/cpp/util/byte_buffer.cc",
     "src/cpp/util/slice.cc",
     "src/cpp/util/status.cc",
@@ -602,21 +675,27 @@
   hdrs = [
     "include/grpc++/async_generic_service.h",
     "include/grpc++/async_unary_call.h",
+    "include/grpc++/auth_context.h",
+    "include/grpc++/auth_property_iterator.h",
     "include/grpc++/byte_buffer.h",
     "include/grpc++/channel_arguments.h",
     "include/grpc++/channel_interface.h",
     "include/grpc++/client_context.h",
     "include/grpc++/completion_queue.h",
     "include/grpc++/config.h",
+    "include/grpc++/config_protobuf.h",
     "include/grpc++/create_channel.h",
     "include/grpc++/credentials.h",
+    "include/grpc++/fixed_size_thread_pool.h",
     "include/grpc++/generic_stub.h",
     "include/grpc++/impl/call.h",
     "include/grpc++/impl/client_unary_call.h",
     "include/grpc++/impl/grpc_library.h",
     "include/grpc++/impl/internal_stub.h",
+    "include/grpc++/impl/proto_utils.h",
     "include/grpc++/impl/rpc_method.h",
     "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/serialization_traits.h",
     "include/grpc++/impl/service_type.h",
     "include/grpc++/impl/sync.h",
     "include/grpc++/impl/sync_cxx11.h",
@@ -651,12 +730,11 @@
   name = "grpc++_unsecure",
   srcs = [
     "src/cpp/client/channel.h",
-    "src/cpp/proto/proto_utils.h",
-    "src/cpp/server/thread_pool.h",
+    "src/cpp/common/create_auth_context.h",
+    "src/cpp/common/insecure_create_auth_context.cc",
     "src/cpp/client/channel.cc",
     "src/cpp/client/channel_arguments.cc",
     "src/cpp/client/client_context.cc",
-    "src/cpp/client/client_unary_call.cc",
     "src/cpp/client/create_channel.cc",
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
@@ -668,12 +746,12 @@
     "src/cpp/proto/proto_utils.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
+    "src/cpp/server/fixed_size_thread_pool.cc",
     "src/cpp/server/insecure_server_credentials.cc",
     "src/cpp/server/server.cc",
     "src/cpp/server/server_builder.cc",
     "src/cpp/server/server_context.cc",
     "src/cpp/server/server_credentials.cc",
-    "src/cpp/server/thread_pool.cc",
     "src/cpp/util/byte_buffer.cc",
     "src/cpp/util/slice.cc",
     "src/cpp/util/status.cc",
@@ -682,21 +760,27 @@
   hdrs = [
     "include/grpc++/async_generic_service.h",
     "include/grpc++/async_unary_call.h",
+    "include/grpc++/auth_context.h",
+    "include/grpc++/auth_property_iterator.h",
     "include/grpc++/byte_buffer.h",
     "include/grpc++/channel_arguments.h",
     "include/grpc++/channel_interface.h",
     "include/grpc++/client_context.h",
     "include/grpc++/completion_queue.h",
     "include/grpc++/config.h",
+    "include/grpc++/config_protobuf.h",
     "include/grpc++/create_channel.h",
     "include/grpc++/credentials.h",
+    "include/grpc++/fixed_size_thread_pool.h",
     "include/grpc++/generic_stub.h",
     "include/grpc++/impl/call.h",
     "include/grpc++/impl/client_unary_call.h",
     "include/grpc++/impl/grpc_library.h",
     "include/grpc++/impl/internal_stub.h",
+    "include/grpc++/impl/proto_utils.h",
     "include/grpc++/impl/rpc_method.h",
     "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/serialization_traits.h",
     "include/grpc++/impl/service_type.h",
     "include/grpc++/impl/sync.h",
     "include/grpc++/impl/sync_cxx11.h",
@@ -730,6 +814,8 @@
 cc_library(
   name = "grpc_plugin_support",
   srcs = [
+    "include/grpc++/config.h",
+    "include/grpc++/config_protobuf.h",
     "src/compiler/config.h",
     "src/compiler/cpp_generator.h",
     "src/compiler/cpp_generator_helpers.h",
@@ -780,6 +866,369 @@
 
 
 
+objc_library(
+  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",
+    "src/core/support/cpu_posix.c",
+    "src/core/support/cpu_windows.c",
+    "src/core/support/env_linux.c",
+    "src/core/support/env_posix.c",
+    "src/core/support/env_win32.c",
+    "src/core/support/file.c",
+    "src/core/support/file_posix.c",
+    "src/core/support/file_win32.c",
+    "src/core/support/histogram.c",
+    "src/core/support/host_port.c",
+    "src/core/support/log.c",
+    "src/core/support/log_android.c",
+    "src/core/support/log_linux.c",
+    "src/core/support/log_posix.c",
+    "src/core/support/log_win32.c",
+    "src/core/support/murmur_hash.c",
+    "src/core/support/slice.c",
+    "src/core/support/slice_buffer.c",
+    "src/core/support/stack_lockfree.c",
+    "src/core/support/string.c",
+    "src/core/support/string_posix.c",
+    "src/core/support/string_win32.c",
+    "src/core/support/subprocess_posix.c",
+    "src/core/support/sync.c",
+    "src/core/support/sync_posix.c",
+    "src/core/support/sync_win32.c",
+    "src/core/support/thd.c",
+    "src/core/support/thd_posix.c",
+    "src/core/support/thd_win32.c",
+    "src/core/support/time.c",
+    "src/core/support/time_posix.c",
+    "src/core/support/time_win32.c",
+    "src/core/support/tls_pthread.c",
+  ],
+  hdrs = [
+    "include/grpc/support/alloc.h",
+    "include/grpc/support/atm.h",
+    "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",
+    "include/grpc/support/host_port.h",
+    "include/grpc/support/log.h",
+    "include/grpc/support/log_win32.h",
+    "include/grpc/support/port_platform.h",
+    "include/grpc/support/slice.h",
+    "include/grpc/support/slice_buffer.h",
+    "include/grpc/support/string_util.h",
+    "include/grpc/support/subprocess.h",
+    "include/grpc/support/sync.h",
+    "include/grpc/support/sync_generic.h",
+    "include/grpc/support/sync_posix.h",
+    "include/grpc/support/sync_win32.h",
+    "include/grpc/support/thd.h",
+    "include/grpc/support/time.h",
+    "include/grpc/support/tls.h",
+    "include/grpc/support/tls_gcc.h",
+    "include/grpc/support/tls_msvc.h",
+    "include/grpc/support/tls_pthread.h",
+    "include/grpc/support/useful.h",
+    "src/core/support/env.h",
+    "src/core/support/file.h",
+    "src/core/support/murmur_hash.h",
+    "src/core/support/stack_lockfree.h",
+    "src/core/support/string.h",
+    "src/core/support/string_win32.h",
+    "src/core/support/thd_internal.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+  ],
+)
+
+
+objc_library(
+  name = "grpc_objc",
+  srcs = [
+    "src/core/httpcli/format_request.c",
+    "src/core/httpcli/httpcli.c",
+    "src/core/httpcli/httpcli_security_connector.c",
+    "src/core/httpcli/parser.c",
+    "src/core/security/base64.c",
+    "src/core/security/client_auth_filter.c",
+    "src/core/security/credentials.c",
+    "src/core/security/credentials_metadata.c",
+    "src/core/security/credentials_posix.c",
+    "src/core/security/credentials_win32.c",
+    "src/core/security/google_default_credentials.c",
+    "src/core/security/json_token.c",
+    "src/core/security/jwt_verifier.c",
+    "src/core/security/secure_endpoint.c",
+    "src/core/security/secure_transport_setup.c",
+    "src/core/security/security_connector.c",
+    "src/core/security/security_context.c",
+    "src/core/security/server_auth_filter.c",
+    "src/core/security/server_secure_chttp2.c",
+    "src/core/surface/init_secure.c",
+    "src/core/surface/secure_channel_create.c",
+    "src/core/tsi/fake_transport_security.c",
+    "src/core/tsi/ssl_transport_security.c",
+    "src/core/tsi/transport_security.c",
+    "src/core/census/grpc_context.c",
+    "src/core/channel/channel_args.c",
+    "src/core/channel/channel_stack.c",
+    "src/core/channel/client_channel.c",
+    "src/core/channel/compress_filter.c",
+    "src/core/channel/connected_channel.c",
+    "src/core/channel/http_client_filter.c",
+    "src/core/channel/http_server_filter.c",
+    "src/core/channel/noop_filter.c",
+    "src/core/client_config/client_config.c",
+    "src/core/client_config/connector.c",
+    "src/core/client_config/lb_policies/pick_first.c",
+    "src/core/client_config/lb_policy.c",
+    "src/core/client_config/resolver.c",
+    "src/core/client_config/resolver_factory.c",
+    "src/core/client_config/resolver_registry.c",
+    "src/core/client_config/resolvers/dns_resolver.c",
+    "src/core/client_config/resolvers/unix_resolver_posix.c",
+    "src/core/client_config/subchannel.c",
+    "src/core/client_config/subchannel_factory.c",
+    "src/core/client_config/uri_parser.c",
+    "src/core/compression/algorithm.c",
+    "src/core/compression/message_compress.c",
+    "src/core/debug/trace.c",
+    "src/core/iomgr/alarm.c",
+    "src/core/iomgr/alarm_heap.c",
+    "src/core/iomgr/endpoint.c",
+    "src/core/iomgr/endpoint_pair_posix.c",
+    "src/core/iomgr/endpoint_pair_windows.c",
+    "src/core/iomgr/fd_posix.c",
+    "src/core/iomgr/iocp_windows.c",
+    "src/core/iomgr/iomgr.c",
+    "src/core/iomgr/iomgr_posix.c",
+    "src/core/iomgr/iomgr_windows.c",
+    "src/core/iomgr/pollset_kick_posix.c",
+    "src/core/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_set_posix.c",
+    "src/core/iomgr/pollset_set_windows.c",
+    "src/core/iomgr/pollset_windows.c",
+    "src/core/iomgr/resolve_address_posix.c",
+    "src/core/iomgr/resolve_address_windows.c",
+    "src/core/iomgr/sockaddr_utils.c",
+    "src/core/iomgr/socket_utils_common_posix.c",
+    "src/core/iomgr/socket_utils_linux.c",
+    "src/core/iomgr/socket_utils_posix.c",
+    "src/core/iomgr/socket_windows.c",
+    "src/core/iomgr/tcp_client_posix.c",
+    "src/core/iomgr/tcp_client_windows.c",
+    "src/core/iomgr/tcp_posix.c",
+    "src/core/iomgr/tcp_server_posix.c",
+    "src/core/iomgr/tcp_server_windows.c",
+    "src/core/iomgr/tcp_windows.c",
+    "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/wakeup_fd_eventfd.c",
+    "src/core/iomgr/wakeup_fd_nospecial.c",
+    "src/core/iomgr/wakeup_fd_pipe.c",
+    "src/core/iomgr/wakeup_fd_posix.c",
+    "src/core/json/json.c",
+    "src/core/json/json_reader.c",
+    "src/core/json/json_string.c",
+    "src/core/json/json_writer.c",
+    "src/core/profiling/basic_timers.c",
+    "src/core/profiling/stap_timers.c",
+    "src/core/surface/byte_buffer.c",
+    "src/core/surface/byte_buffer_queue.c",
+    "src/core/surface/byte_buffer_reader.c",
+    "src/core/surface/call.c",
+    "src/core/surface/call_details.c",
+    "src/core/surface/call_log_batch.c",
+    "src/core/surface/channel.c",
+    "src/core/surface/channel_create.c",
+    "src/core/surface/completion_queue.c",
+    "src/core/surface/event_string.c",
+    "src/core/surface/init.c",
+    "src/core/surface/lame_client.c",
+    "src/core/surface/metadata_array.c",
+    "src/core/surface/server.c",
+    "src/core/surface/server_chttp2.c",
+    "src/core/surface/server_create.c",
+    "src/core/surface/surface_trace.c",
+    "src/core/surface/version.c",
+    "src/core/transport/chttp2/alpn.c",
+    "src/core/transport/chttp2/bin_encoder.c",
+    "src/core/transport/chttp2/frame_data.c",
+    "src/core/transport/chttp2/frame_goaway.c",
+    "src/core/transport/chttp2/frame_ping.c",
+    "src/core/transport/chttp2/frame_rst_stream.c",
+    "src/core/transport/chttp2/frame_settings.c",
+    "src/core/transport/chttp2/frame_window_update.c",
+    "src/core/transport/chttp2/hpack_parser.c",
+    "src/core/transport/chttp2/hpack_table.c",
+    "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/incoming_metadata.c",
+    "src/core/transport/chttp2/parsing.c",
+    "src/core/transport/chttp2/status_conversion.c",
+    "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_lists.c",
+    "src/core/transport/chttp2/stream_map.c",
+    "src/core/transport/chttp2/timeout_encoding.c",
+    "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2/writing.c",
+    "src/core/transport/chttp2_transport.c",
+    "src/core/transport/connectivity_state.c",
+    "src/core/transport/metadata.c",
+    "src/core/transport/stream_op.c",
+    "src/core/transport/transport.c",
+    "src/core/transport/transport_op_string.c",
+    "src/core/census/context.c",
+    "src/core/census/initialize.c",
+  ],
+  hdrs = [
+    "include/grpc/grpc_security.h",
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/compression.h",
+    "include/grpc/grpc.h",
+    "include/grpc/status.h",
+    "include/grpc/census.h",
+    "src/core/httpcli/format_request.h",
+    "src/core/httpcli/httpcli.h",
+    "src/core/httpcli/httpcli_security_connector.h",
+    "src/core/httpcli/parser.h",
+    "src/core/security/auth_filters.h",
+    "src/core/security/base64.h",
+    "src/core/security/credentials.h",
+    "src/core/security/json_token.h",
+    "src/core/security/jwt_verifier.h",
+    "src/core/security/secure_endpoint.h",
+    "src/core/security/secure_transport_setup.h",
+    "src/core/security/security_connector.h",
+    "src/core/security/security_context.h",
+    "src/core/tsi/fake_transport_security.h",
+    "src/core/tsi/ssl_transport_security.h",
+    "src/core/tsi/transport_security.h",
+    "src/core/tsi/transport_security_interface.h",
+    "src/core/census/grpc_context.h",
+    "src/core/channel/census_filter.h",
+    "src/core/channel/channel_args.h",
+    "src/core/channel/channel_stack.h",
+    "src/core/channel/client_channel.h",
+    "src/core/channel/compress_filter.h",
+    "src/core/channel/connected_channel.h",
+    "src/core/channel/context.h",
+    "src/core/channel/http_client_filter.h",
+    "src/core/channel/http_server_filter.h",
+    "src/core/channel/noop_filter.h",
+    "src/core/client_config/client_config.h",
+    "src/core/client_config/connector.h",
+    "src/core/client_config/lb_policies/pick_first.h",
+    "src/core/client_config/lb_policy.h",
+    "src/core/client_config/resolver.h",
+    "src/core/client_config/resolver_factory.h",
+    "src/core/client_config/resolver_registry.h",
+    "src/core/client_config/resolvers/dns_resolver.h",
+    "src/core/client_config/resolvers/unix_resolver_posix.h",
+    "src/core/client_config/subchannel.h",
+    "src/core/client_config/subchannel_factory.h",
+    "src/core/client_config/uri_parser.h",
+    "src/core/compression/message_compress.h",
+    "src/core/debug/trace.h",
+    "src/core/iomgr/alarm.h",
+    "src/core/iomgr/alarm_heap.h",
+    "src/core/iomgr/alarm_internal.h",
+    "src/core/iomgr/endpoint.h",
+    "src/core/iomgr/endpoint_pair.h",
+    "src/core/iomgr/fd_posix.h",
+    "src/core/iomgr/iocp_windows.h",
+    "src/core/iomgr/iomgr.h",
+    "src/core/iomgr/iomgr_internal.h",
+    "src/core/iomgr/iomgr_posix.h",
+    "src/core/iomgr/pollset.h",
+    "src/core/iomgr/pollset_kick_posix.h",
+    "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_set.h",
+    "src/core/iomgr/pollset_set_posix.h",
+    "src/core/iomgr/pollset_set_windows.h",
+    "src/core/iomgr/pollset_windows.h",
+    "src/core/iomgr/resolve_address.h",
+    "src/core/iomgr/sockaddr.h",
+    "src/core/iomgr/sockaddr_posix.h",
+    "src/core/iomgr/sockaddr_utils.h",
+    "src/core/iomgr/sockaddr_win32.h",
+    "src/core/iomgr/socket_utils_posix.h",
+    "src/core/iomgr/socket_windows.h",
+    "src/core/iomgr/tcp_client.h",
+    "src/core/iomgr/tcp_posix.h",
+    "src/core/iomgr/tcp_server.h",
+    "src/core/iomgr/tcp_windows.h",
+    "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/wakeup_fd_pipe.h",
+    "src/core/iomgr/wakeup_fd_posix.h",
+    "src/core/json/json.h",
+    "src/core/json/json_common.h",
+    "src/core/json/json_reader.h",
+    "src/core/json/json_writer.h",
+    "src/core/profiling/timers.h",
+    "src/core/profiling/timers_preciseclock.h",
+    "src/core/surface/byte_buffer_queue.h",
+    "src/core/surface/call.h",
+    "src/core/surface/channel.h",
+    "src/core/surface/completion_queue.h",
+    "src/core/surface/event_string.h",
+    "src/core/surface/init.h",
+    "src/core/surface/server.h",
+    "src/core/surface/surface_trace.h",
+    "src/core/transport/chttp2/alpn.h",
+    "src/core/transport/chttp2/bin_encoder.h",
+    "src/core/transport/chttp2/frame.h",
+    "src/core/transport/chttp2/frame_data.h",
+    "src/core/transport/chttp2/frame_goaway.h",
+    "src/core/transport/chttp2/frame_ping.h",
+    "src/core/transport/chttp2/frame_rst_stream.h",
+    "src/core/transport/chttp2/frame_settings.h",
+    "src/core/transport/chttp2/frame_window_update.h",
+    "src/core/transport/chttp2/hpack_parser.h",
+    "src/core/transport/chttp2/hpack_table.h",
+    "src/core/transport/chttp2/http2_errors.h",
+    "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/incoming_metadata.h",
+    "src/core/transport/chttp2/internal.h",
+    "src/core/transport/chttp2/status_conversion.h",
+    "src/core/transport/chttp2/stream_encoder.h",
+    "src/core/transport/chttp2/stream_map.h",
+    "src/core/transport/chttp2/timeout_encoding.h",
+    "src/core/transport/chttp2/varint.h",
+    "src/core/transport/chttp2_transport.h",
+    "src/core/transport/connectivity_state.h",
+    "src/core/transport/metadata.h",
+    "src/core/transport/stream_op.h",
+    "src/core/transport/transport.h",
+    "src/core/transport/transport_impl.h",
+    "src/core/census/context.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":gpr_objc",
+    "//external:libssl_objc",
+  ],
+  sdk_dylibs = ["libz"],
+)
+
+
+
 cc_binary(
   name = "grpc_cpp_plugin",
   srcs = [
@@ -843,3 +1292,76 @@
 
 
 
+
+
+
+objc_path = "src/objective-c"
+
+rx_library_path = objc_path + "/RxLibrary"
+
+objc_library(
+  name = "rx_library",
+  hdrs = glob([
+    rx_library_path + "/*.h",
+    rx_library_path + "/transformations/*.h",
+  ]),
+  srcs = glob([
+    rx_library_path + "/*.m",
+    rx_library_path + "/transformations/*.m",
+  ]),
+  includes = [objc_path],
+  deps = [
+    ":rx_library_private",
+  ],
+)
+
+objc_library(
+  name = "rx_library_private",
+  hdrs = glob([rx_library_path + "/private/*.h"]),
+  srcs = glob([rx_library_path + "/private/*.m"]),
+  visibility = ["//visibility:private"],
+)
+
+objc_client_path = objc_path + "/GRPCClient"
+
+objc_library(
+  name = "grpc_client",
+  hdrs = glob([
+    objc_client_path + "/*.h",
+    objc_client_path + "/private/*.h",
+  ]),
+  srcs = glob([
+    objc_client_path + "/*.m",
+    objc_client_path + "/private/*.m",
+  ]),
+  includes = [objc_path],
+  bundles = [":gRPCCertificates"],
+  deps = [
+    ":grpc_objc",
+    ":rx_library",
+  ],
+)
+
+objc_bundle_library(
+    # The choice of name is signicant here, since it determines the bundle name.
+    name = "gRPCCertificates",
+    resources = ["etc/roots.pem"],
+)
+
+proto_objc_rpc_path = objc_path + "/ProtoRPC"
+
+objc_library(
+  name = "proto_objc_rpc",
+  hdrs = glob([
+    proto_objc_rpc_path + "/*.h",
+  ]),
+  srcs = glob([
+    proto_objc_rpc_path + "/*.m",
+  ]),
+  includes = [objc_path],
+  deps = [
+    ":grpc_client",
+    ":rx_library",
+    "//external:protobuf_objc",
+  ],
+)
diff --git a/Makefile b/Makefile
index 5529af7..4756b75 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,8 @@
 # This currently builds C and C++ code.
 # This file has been automatically generated from a template file.
 # Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
 
 # Copyright 2015, Google Inc.
 # All rights reserved.
@@ -143,7 +145,7 @@
 CXX_tsan = clang++
 LD_tsan = clang
 LDXX_tsan = clang++
-CPPFLAGS_tsan = -O1 -fsanitize=thread -fno-omit-frame-pointer
+CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer
 LDFLAGS_tsan = -fsanitize=thread
 DEFINES_tsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
 
@@ -155,7 +157,7 @@
 LDXX_asan = clang++
 CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer
 LDFLAGS_asan = -fsanitize=address
-DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=5
+DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
 
 VALID_CONFIG_msan = 1
 REQUIRE_CUSTOM_LIBRARIES_msan = 1
@@ -166,7 +168,7 @@
 CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
 OPENSSL_CFLAGS_msan = -DPURIFY
 LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
-DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=20
+DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4
 
 VALID_CONFIG_ubsan = 1
 REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
@@ -177,7 +179,7 @@
 CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer
 OPENSSL_CFLAGS_ubsan = -DPURIFY
 LDFLAGS_ubsan = -fsanitize=undefined
-DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
+DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
 
 VALID_CONFIG_gcov = 1
 CC_gcov = gcc
@@ -213,6 +215,7 @@
 endif
 INSTALL = install
 RM = rm -f
+PKG_CONFIG = pkg-config
 
 ifndef VALID_CONFIG_$(CONFIG)
 $(error Invalid CONFIG value '$(CONFIG)')
@@ -329,6 +332,30 @@
 # These are automatically computed variables.
 # There shouldn't be any need to change anything from now on.
 
+-include cache.mk
+
+CACHE_MK =
+
+HAS_PKG_CONFIG ?= $(shell command -v $(PKG_CONFIG) >/dev/null 2>&1 && echo true || echo false)
+
+ifeq ($(HAS_PKG_CONFIG), true)
+CACHE_MK += HAS_PKG_CONFIG = true,
+endif
+
+PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
+
+# gpr .pc file
+PC_NAME = gRPC Portable Runtime
+PC_DESCRIPTION = gRPC Portable Runtime
+PC_CFLAGS = -pthread
+PC_REQUIRES_PRIVATE =
+PC_LIBS_PRIVATE = -lpthread
+PC_LIB = -lgpr
+ifneq ($(SYSTEM),Darwin)
+PC_LIBS_PRIVATE += -lrt
+endif
+GPR_PC_FILE := $(PC_TEMPLATE)
+
 ifeq ($(SYSTEM),MINGW32)
 SHARED_EXT = dll
 endif
@@ -353,6 +380,13 @@
 OPENSSL_REQUIRES_DL = true
 endif
 
+ifeq ($(HAS_PKG_CONFIG),true)
+OPENSSL_ALPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.2 openssl
+OPENSSL_NPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.1 openssl
+ZLIB_CHECK_CMD = $(PKG_CONFIG) --exists zlib
+PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0-alpha-3 protobuf
+else # HAS_PKG_CONFIG
+
 ifeq ($(SYSTEM),MINGW32)
 OPENSSL_LIBS = ssl32 eay32
 else
@@ -360,41 +394,68 @@
 endif
 
 OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-alpn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
+OPENSSL_NPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-npn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
 ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
-PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
 PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
+
+ifeq ($(OPENSSL_REQUIRES_DL),true)
+OPENSSL_ALPN_CHECK_CMD += -ldl
+OPENSSL_NPN_CHECK_CMD += -ldl
+endif
+
+endif # HAS_PKG_CONFIG
+
+PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
+
 PROTOC_CHECK_CMD = which protoc > /dev/null
 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)
 
-ifeq ($(OPENSSL_REQUIRES_DL),true)
-OPENSSL_ALPN_CHECK_CMD += -ldl
-endif
-
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_PERFTOOLS = $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_SYSTEM_PERFTOOLS),true)
 DEFINES += GRPC_HAVE_PERFTOOLS
 LIBS += profiler
+CACHE_MK += HAS_SYSTEM_PERFTOOLS = true,
 endif
 endif
 
 HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
-HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
-HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY)
+HAS_SYSTEM_OPENSSL_ALPN ?= $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),true)
+HAS_SYSTEM_OPENSSL_NPN = true
+CACHE_MK += HAS_SYSTEM_OPENSSL_ALPN = true,
+else
+HAS_SYSTEM_OPENSSL_NPN ?= $(shell $(OPENSSL_NPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+endif
+ifeq ($(HAS_SYSTEM_OPENSSL_NPN),true)
+CACHE_MK += HAS_SYSTEM_OPENSSL_NPN = true,
+endif
+HAS_SYSTEM_ZLIB ?= $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_SYSTEM_ZLIB),true)
+CACHE_MK += HAS_SYSTEM_ZLIB = true,
+endif
+HAS_SYSTEM_PROTOBUF ?= $(HAS_SYSTEM_PROTOBUF_VERIFY)
+ifeq ($(HAS_SYSTEM_PROTOBUF),true)
+CACHE_MK += HAS_SYSTEM_PROTOBUF = true,
+endif
 else
 # override system libraries if the config requires a custom compiled library
 HAS_SYSTEM_OPENSSL_ALPN = false
+HAS_SYSTEM_OPENSSL_NPN = false
 HAS_SYSTEM_ZLIB = false
 HAS_SYSTEM_PROTOBUF = false
 endif
 
-HAS_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_PROTOC ?= $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_PROTOC),true)
-HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+CACHE_MK += HAS_PROTOC = true,
+HAS_VALID_PROTOC ?= $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_VALID_PROTOC),true)
+CACHE_MK += HAS_VALID_PROTOC = true,
+endif
 else
 HAS_VALID_PROTOC = false
 endif
@@ -402,6 +463,7 @@
 # Check for Systemtap (https://sourceware.org/systemtap/), first by making sure <sys/sdt.h> is present
 # in the system and secondly by checking for the "dtrace" binary (on Linux, this is part of the Systemtap
 # distribution. It's part of the base system on BSD/Solaris machines).
+ifndef HAS_SYSTEMTAP
 HAS_SYSTEMTAP_HEADERS = $(shell $(SYSTEMTAP_HEADERS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_DTRACE = $(shell $(DTRACE_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_SYSTEMTAP = false
@@ -410,7 +472,15 @@
 HAS_SYSTEMTAP = true
 endif
 endif
+endif
 
+ifeq ($(HAS_SYSTEMTAP),true)
+CACHE_MK += HAS_SYSTEMTAP = true,
+endif
+
+# 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.
 ifeq ($(wildcard third_party/openssl/ssl/ssl.h),)
 HAS_EMBEDDED_OPENSSL_ALPN = false
 else
@@ -432,6 +502,9 @@
 HAS_EMBEDDED_PROTOBUF = true
 endif
 
+PC_REQUIRES_GRPC = gpr
+PC_LIBS_GRPC =
+
 ifeq ($(HAS_SYSTEM_ZLIB),false)
 ifeq ($(HAS_EMBEDDED_ZLIB),true)
 ZLIB_DEP = $(LIBDIR)/$(CONFIG)/zlib/libz.a
@@ -440,10 +513,43 @@
 else
 DEP_MISSING += zlib
 endif
+else
+ifeq ($(HAS_PKG_CONFIG),true)
+CPPFLAGS += $(shell $(PKG_CONFIG) --cflags zlib)
+LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L zlib)
+PC_REQUIRES_GRPC += zlib
+else
+PC_LIBS_GRPC += -lz
+endif
 endif
 
-ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),false)
+OPENSSL_PKG_CONFIG = false
+
+PC_REQUIRES_SECURE =
+PC_LIBS_SECURE =
+
+ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),true)
+ifeq ($(HAS_PKG_CONFIG),true)
+OPENSSL_PKG_CONFIG = true
+PC_REQUIRES_SECURE = openssl
+CPPFLAGS := $(shell $(PKG_CONFIG) --cflags openssl) $(CPPFLAGS)
+LDFLAGS_OPENSSL_PKG_CONFIG = $(shell $(PKG_CONFIG) --libs-only-L openssl)
+ifeq ($(SYSTEM),Linux)
+ifneq ($(LDFLAGS_OPENSSL_PKG_CONFIG),)
+LDFLAGS_OPENSSL_PKG_CONFIG += $(shell $(PKG_CONFIG) --libs-only-L openssl | sed s/L/Wl,-rpath,/)
+endif
+endif
+LDFLAGS := $(LDFLAGS_OPENSSL_PKG_CONFIG) $(LDFLAGS)
+else
+LIBS_SECURE = $(OPENSSL_LIBS)
+ifeq ($(OPENSSL_REQUIRES_DL),true)
+LIBS_SECURE += dl
+PC_LIBS_SECURE = $(addprefix -l, $(LIBS_SECURE))
+endif
+endif
+else
 ifeq ($(HAS_EMBEDDED_OPENSSL_ALPN),true)
+USE_SYSTEM_OPENSSL = false
 OPENSSL_DEP = $(LIBDIR)/$(CONFIG)/openssl/libssl.a
 OPENSSL_MERGE_LIBS += $(LIBDIR)/$(CONFIG)/openssl/libssl.a $(LIBDIR)/$(CONFIG)/openssl/libcrypto.a
 # need to prefix these to ensure overriding system libraries
@@ -453,18 +559,63 @@
 LIBS_SECURE = dl
 endif
 else
-NO_SECURE = true
-endif
-else
+ifeq ($(HAS_SYSTEM_OPENSSL_NPN),true)
+USE_SYSTEM_OPENSSL = true
+CPPFLAGS += -DTSI_OPENSSL_ALPN_SUPPORT=0
 LIBS_SECURE = $(OPENSSL_LIBS)
 ifeq ($(OPENSSL_REQUIRES_DL),true)
 LIBS_SECURE += dl
 endif
+else
+NO_SECURE = true
+endif
+endif
 endif
 
+ifeq ($(OPENSSL_PKG_CONFIG),true)
+LDLIBS_SECURE += $(shell $(PKG_CONFIG) --libs-only-l openssl)
+else
 LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
+endif
 
-ifeq ($(HAS_SYSTEM_PROTOBUF),false)
+# grpc .pc file
+PC_NAME = gRPC
+PC_DESCRIPTION = high performance general RPC framework
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPC) $(PC_LIBS_SECURE)
+PC_LIB = -lgrpc
+GRPC_PC_FILE := $(PC_TEMPLATE)
+
+# gprc_unsecure .pc file
+PC_NAME = gRPC unsecure
+PC_DESCRIPTION = high performance general RPC framework without SSL
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
+PC_LIB = -lgrpc
+GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+
+PROTOBUF_PKG_CONFIG = false
+
+PC_REQUIRES_GRPCXX =
+PC_LIBS_GRPCXX =
+
+ifeq ($(HAS_SYSTEM_PROTOBUF),true)
+ifeq ($(HAS_PKG_CONFIG),true)
+PROTOBUF_PKG_CONFIG = true
+PC_REQUIRES_GRPCXX = protobuf
+CPPFLAGS := $(shell $(PKG_CONFIG) --cflags protobuf) $(CPPFLAGS)
+LDFLAGS_PROTOBUF_PKG_CONFIG = $(shell $(PKG_CONFIG) --libs-only-L protobuf)
+ifeq ($(SYSTEM),Linux)
+ifneq ($(LDFLAGS_PROTOBUF_PKG_CONFIG),)
+LDFLAGS_PROTOBUF_PKG_CONFIG += $(shell $(PKG_CONFIG) --libs-only-L protobuf | sed s/L/Wl,-rpath,/)
+endif
+endif
+else
+PC_LIBS_GRPCXX = -lprotobuf
+endif
+else
 ifeq ($(HAS_EMBEDDED_PROTOBUF),true)
 PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a
 CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS)
@@ -473,15 +624,37 @@
 else
 NO_PROTOBUF = true
 endif
-else
 endif
 
 LIBS_PROTOBUF = protobuf
 LIBS_PROTOC = protoc protobuf
 
-LDLIBS_PROTOBUF += $(addprefix -l, $(LIBS_PROTOBUF))
 HOST_LDLIBS_PROTOC += $(addprefix -l, $(LIBS_PROTOC))
 
+ifeq ($(PROTOBUF_PKG_CONFIG),true)
+LDLIBS_PROTOBUF += $(shell $(PKG_CONFIG) --libs-only-l protobuf)
+else
+LDLIBS_PROTOBUF += $(addprefix -l, $(LIBS_PROTOBUF))
+endif
+
+# grpc++ .pc file
+PC_NAME = gRPC++
+PC_DESCRIPTION = C++ wrapper for gRPC
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = grpc $(PC_REQUIRES_GRPCXX)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
+PC_LIB = -lgrpc++
+GRPCXX_PC_FILE := $(PC_TEMPLATE)
+
+# grpc++_unsecure .pc file
+PC_NAME = gRPC++ unsecure
+PC_DESCRIPTION = C++ wrapper for gRPC without SSL
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
+PC_LIB = -lgrpc++
+GRPCXX_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+
 ifeq ($(MAKECMDGOALS),clean)
 NO_DEPS = true
 endif
@@ -540,7 +713,7 @@
 	@echo
 	@echo "DEPENDENCY ERROR"
 	@echo
-	@echo "The target you are trying to run requires OpenSSL with ALPN support."
+	@echo "The target you are trying to run requires OpenSSL."
 	@echo "Your system doesn't have it, and neither does the third_party directory."
 	@echo
 	@echo "Please consult INSTALL to get more information."
@@ -601,6 +774,7 @@
 chttp2_stream_encoder_test: $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test
 chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
 dualstack_socket_test: $(BINDIR)/$(CONFIG)/dualstack_socket_test
+fd_conservation_posix_test: $(BINDIR)/$(CONFIG)/fd_conservation_posix_test
 fd_posix_test: $(BINDIR)/$(CONFIG)/fd_posix_test
 fling_client: $(BINDIR)/$(CONFIG)/fling_client
 fling_server: $(BINDIR)/$(CONFIG)/fling_server
@@ -616,6 +790,7 @@
 gpr_log_test: $(BINDIR)/$(CONFIG)/gpr_log_test
 gpr_slice_buffer_test: $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test
 gpr_slice_test: $(BINDIR)/$(CONFIG)/gpr_slice_test
+gpr_stack_lockfree_test: $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
 gpr_string_test: $(BINDIR)/$(CONFIG)/gpr_string_test
 gpr_sync_test: $(BINDIR)/$(CONFIG)/gpr_sync_test
 gpr_thd_test: $(BINDIR)/$(CONFIG)/gpr_thd_test
@@ -631,8 +806,11 @@
 grpc_credentials_test: $(BINDIR)/$(CONFIG)/grpc_credentials_test
 grpc_fetch_oauth2: $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2
 grpc_json_token_test: $(BINDIR)/$(CONFIG)/grpc_json_token_test
+grpc_jwt_verifier_test: $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test
 grpc_print_google_default_creds_token: $(BINDIR)/$(CONFIG)/grpc_print_google_default_creds_token
+grpc_security_connector_test: $(BINDIR)/$(CONFIG)/grpc_security_connector_test
 grpc_stream_op_test: $(BINDIR)/$(CONFIG)/grpc_stream_op_test
+grpc_verify_jwt: $(BINDIR)/$(CONFIG)/grpc_verify_jwt
 hpack_parser_test: $(BINDIR)/$(CONFIG)/hpack_parser_test
 hpack_table_test: $(BINDIR)/$(CONFIG)/hpack_table_test
 httpcli_format_request_test: $(BINDIR)/$(CONFIG)/httpcli_format_request_test
@@ -645,6 +823,7 @@
 low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
 message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
 multi_init_test: $(BINDIR)/$(CONFIG)/multi_init_test
+multiple_server_queues_test: $(BINDIR)/$(CONFIG)/multiple_server_queues_test
 murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test
 no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
 poll_kick_posix_test: $(BINDIR)/$(CONFIG)/poll_kick_posix_test
@@ -655,21 +834,25 @@
 tcp_posix_test: $(BINDIR)/$(CONFIG)/tcp_posix_test
 tcp_server_posix_test: $(BINDIR)/$(CONFIG)/tcp_server_posix_test
 time_averaged_stats_test: $(BINDIR)/$(CONFIG)/time_averaged_stats_test
-time_test: $(BINDIR)/$(CONFIG)/time_test
 timeout_encoding_test: $(BINDIR)/$(CONFIG)/timeout_encoding_test
 timers_test: $(BINDIR)/$(CONFIG)/timers_test
 transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test
 transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_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
 async_unary_ping_pong_test: $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test
+auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
 channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
 cli_call_test: $(BINDIR)/$(CONFIG)/cli_call_test
 client_crash_test: $(BINDIR)/$(CONFIG)/client_crash_test
 client_crash_test_server: $(BINDIR)/$(CONFIG)/client_crash_test_server
 credentials_test: $(BINDIR)/$(CONFIG)/credentials_test
+cxx_byte_buffer_test: $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test
+cxx_slice_test: $(BINDIR)/$(CONFIG)/cxx_slice_test
 cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
 end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
+fixed_size_thread_pool_test: $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
 grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
 grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
@@ -686,15 +869,15 @@
 pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
 qps_driver: $(BINDIR)/$(CONFIG)/qps_driver
 qps_interarrival_test: $(BINDIR)/$(CONFIG)/qps_interarrival_test
+qps_openloop_test: $(BINDIR)/$(CONFIG)/qps_openloop_test
 qps_test: $(BINDIR)/$(CONFIG)/qps_test
-qps_test_openloop: $(BINDIR)/$(CONFIG)/qps_test_openloop
 qps_worker: $(BINDIR)/$(CONFIG)/qps_worker
+secure_auth_context_test: $(BINDIR)/$(CONFIG)/secure_auth_context_test
 server_crash_test: $(BINDIR)/$(CONFIG)/server_crash_test
 server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client
 status_test: $(BINDIR)/$(CONFIG)/status_test
 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_pool_test: $(BINDIR)/$(CONFIG)/thread_pool_test
 thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_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
@@ -719,6 +902,7 @@
 chttp2_fake_security_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test
 chttp2_fake_security_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test
 chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test
+chttp2_fake_security_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test
 chttp2_fake_security_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test
 chttp2_fake_security_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test
 chttp2_fake_security_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test
@@ -749,6 +933,7 @@
 chttp2_fullstack_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test
 chttp2_fullstack_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test
 chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test
+chttp2_fullstack_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test
 chttp2_fullstack_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test
 chttp2_fullstack_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test
 chttp2_fullstack_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test
@@ -756,6 +941,37 @@
 chttp2_fullstack_simple_delayed_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test
 chttp2_fullstack_simple_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test
 chttp2_fullstack_simple_request_with_high_initial_sequence_number_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test
+chttp2_fullstack_compression_bad_hostname_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test
+chttp2_fullstack_compression_cancel_after_accept_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test
+chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test
+chttp2_fullstack_compression_cancel_after_invoke_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test
+chttp2_fullstack_compression_cancel_before_invoke_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test
+chttp2_fullstack_compression_cancel_in_a_vacuum_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test
+chttp2_fullstack_compression_census_simple_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test
+chttp2_fullstack_compression_disappearing_server_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test
+chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test
+chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test
+chttp2_fullstack_compression_empty_batch_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test
+chttp2_fullstack_compression_graceful_server_shutdown_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test
+chttp2_fullstack_compression_invoke_large_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test
+chttp2_fullstack_compression_max_concurrent_streams_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test
+chttp2_fullstack_compression_max_message_length_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test
+chttp2_fullstack_compression_no_op_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test
+chttp2_fullstack_compression_ping_pong_streaming_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test
+chttp2_fullstack_compression_registered_call_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test
+chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test
+chttp2_fullstack_compression_request_response_with_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test
+chttp2_fullstack_compression_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test
+chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test
+chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test
+chttp2_fullstack_compression_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test
+chttp2_fullstack_compression_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test
+chttp2_fullstack_compression_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test
+chttp2_fullstack_compression_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test
+chttp2_fullstack_compression_server_finishes_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test
+chttp2_fullstack_compression_simple_delayed_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test
+chttp2_fullstack_compression_simple_request_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test
+chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test
 chttp2_fullstack_uds_posix_bad_hostname_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test
 chttp2_fullstack_uds_posix_cancel_after_accept_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test
 chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test
@@ -779,6 +995,7 @@
 chttp2_fullstack_uds_posix_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test
 chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test
 chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test
+chttp2_fullstack_uds_posix_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test
 chttp2_fullstack_uds_posix_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test
 chttp2_fullstack_uds_posix_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test
 chttp2_fullstack_uds_posix_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test
@@ -809,6 +1026,7 @@
 chttp2_fullstack_with_poll_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test
 chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test
 chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test
+chttp2_fullstack_with_poll_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test
 chttp2_fullstack_with_poll_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test
 chttp2_fullstack_with_poll_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test
 chttp2_fullstack_with_poll_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test
@@ -839,6 +1057,7 @@
 chttp2_simple_ssl_fullstack_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test
 chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test
 chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test
+chttp2_simple_ssl_fullstack_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test
 chttp2_simple_ssl_fullstack_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test
 chttp2_simple_ssl_fullstack_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test
 chttp2_simple_ssl_fullstack_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test
@@ -869,6 +1088,7 @@
 chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test
 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_payload_and_call_creds_test
 chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test
+chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test
 chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test
 chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test
 chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test
@@ -899,6 +1119,7 @@
 chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test
 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_payload_and_call_creds_test
 chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test
+chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test
 chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test
 chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test
 chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test
@@ -929,6 +1150,7 @@
 chttp2_socket_pair_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test
 chttp2_socket_pair_request_response_with_payload_and_call_creds_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test
 chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test
+chttp2_socket_pair_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test
 chttp2_socket_pair_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test
 chttp2_socket_pair_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test
 chttp2_socket_pair_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test
@@ -959,6 +1181,7 @@
 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_test
 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_payload_and_call_creds_test
 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_response_with_trailing_metadata_and_payload_test
+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_compressed_payload_test
 chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test
 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_large_metadata_test
 chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test
@@ -989,6 +1212,7 @@
 chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test
 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_payload_and_call_creds_test
 chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test
+chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test
 chttp2_socket_pair_with_grpc_trace_request_with_flags_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test
 chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test
 chttp2_socket_pair_with_grpc_trace_request_with_payload_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test
@@ -1018,6 +1242,7 @@
 chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test
 chttp2_fullstack_request_response_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test
 chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test
+chttp2_fullstack_request_with_compressed_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test
 chttp2_fullstack_request_with_flags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test
 chttp2_fullstack_request_with_large_metadata_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test
 chttp2_fullstack_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test
@@ -1025,6 +1250,36 @@
 chttp2_fullstack_simple_delayed_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test
 chttp2_fullstack_simple_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test
 chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test
+chttp2_fullstack_compression_bad_hostname_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test
+chttp2_fullstack_compression_cancel_after_accept_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test
+chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test
+chttp2_fullstack_compression_cancel_after_invoke_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test
+chttp2_fullstack_compression_cancel_before_invoke_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test
+chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test
+chttp2_fullstack_compression_census_simple_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test
+chttp2_fullstack_compression_disappearing_server_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test
+chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test
+chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test
+chttp2_fullstack_compression_empty_batch_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test
+chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test
+chttp2_fullstack_compression_invoke_large_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test
+chttp2_fullstack_compression_max_concurrent_streams_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test
+chttp2_fullstack_compression_max_message_length_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test
+chttp2_fullstack_compression_no_op_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test
+chttp2_fullstack_compression_ping_pong_streaming_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test
+chttp2_fullstack_compression_registered_call_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test
+chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test
+chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test
+chttp2_fullstack_compression_request_response_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test
+chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test
+chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test
+chttp2_fullstack_compression_request_with_flags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test
+chttp2_fullstack_compression_request_with_large_metadata_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test
+chttp2_fullstack_compression_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test
+chttp2_fullstack_compression_server_finishes_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test
+chttp2_fullstack_compression_simple_delayed_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test
+chttp2_fullstack_compression_simple_request_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test
+chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test
 chttp2_fullstack_uds_posix_bad_hostname_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test
 chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test
 chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test
@@ -1047,6 +1302,7 @@
 chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test
 chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test
 chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test
+chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test
 chttp2_fullstack_uds_posix_request_with_flags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test
 chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test
 chttp2_fullstack_uds_posix_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test
@@ -1076,6 +1332,7 @@
 chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test
 chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test
 chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test
+chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test
 chttp2_fullstack_with_poll_request_with_flags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test
 chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test
 chttp2_fullstack_with_poll_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test
@@ -1105,6 +1362,7 @@
 chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test
 chttp2_socket_pair_request_response_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test
 chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test
+chttp2_socket_pair_request_with_compressed_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test
 chttp2_socket_pair_request_with_flags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test
 chttp2_socket_pair_request_with_large_metadata_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test
 chttp2_socket_pair_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test
@@ -1134,6 +1392,7 @@
 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_metadata_and_payload_unsecure_test
 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_payload_unsecure_test
 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_response_with_trailing_metadata_and_payload_unsecure_test
+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_compressed_payload_unsecure_test
 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_flags_unsecure_test
 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_large_metadata_unsecure_test
 chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test
@@ -1163,6 +1422,7 @@
 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_metadata_and_payload_unsecure_test
 chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test
 chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test
+chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test
 chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test
 chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test
 chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test: $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test
@@ -1175,6 +1435,7 @@
 
 run_dep_checks:
 	$(OPENSSL_ALPN_CHECK_CMD) || true
+	$(OPENSSL_NPN_CHECK_CMD) || true
 	$(ZLIB_CHECK_CMD) || true
 	$(PERFTOOLS_CHECK_CMD) || true
 	$(PROTOBUF_CHECK_CMD) || true
@@ -1195,7 +1456,7 @@
 else
 ifeq ($(SYSTEM),MINGW32)
 	@echo "We currently don't have a good way to compile OpenSSL in-place under msys."
-	@echo "Please provide an ALPN-capable OpenSSL in your mingw32 system."
+	@echo "Please provide a OpenSSL in your mingw32 system."
 	@echo
 	@echo "Note that you can find a compatible version of the libraries here:"
 	@echo
@@ -1237,15 +1498,15 @@
 
 static: static_c static_cxx
 
-static_c:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
+static_c: pc_c pc_c_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 
-static_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
+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:  $(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 $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
 
-shared_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT)
+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)
 grpc_csharp_ext: shared_csharp
@@ -1254,15 +1515,24 @@
 
 privatelibs: privatelibs_c privatelibs_cxx
 
-privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_message_length.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_test_registered_call.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_and_call_creds.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_server_finishes_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_with_high_initial_sequence_number.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a
+privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_message_length.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_test_registered_call.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_and_call_creds.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_server_finishes_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_with_high_initial_sequence_number.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a
+pc_gpr: $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
 
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(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
+pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
+
+pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
+
+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
 
-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_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_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_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)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_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)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_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_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_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_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_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_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_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_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_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_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)/poll_kick_posix_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_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_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_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_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_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_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_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_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_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_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_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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_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_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_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_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_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_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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)/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_time_test $(BINDIR)/$(CONFIG)/end2end_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_test $(BINDIR)/$(CONFIG)/qps_test_openloop $(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_pool_test $(BINDIR)/$(CONFIG)/thread_stress_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)/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)/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
 
 test: test_c test_cxx
 
@@ -1287,6 +1557,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_stream_map_test || ( echo test chttp2_stream_map_test failed ; exit 1 )
 	$(E) "[RUN]     Testing dualstack_socket_test"
 	$(Q) $(BINDIR)/$(CONFIG)/dualstack_socket_test || ( echo test dualstack_socket_test failed ; exit 1 )
+	$(E) "[RUN]     Testing fd_conservation_posix_test"
+	$(Q) $(BINDIR)/$(CONFIG)/fd_conservation_posix_test || ( echo test fd_conservation_posix_test failed ; exit 1 )
 	$(E) "[RUN]     Testing fd_posix_test"
 	$(Q) $(BINDIR)/$(CONFIG)/fd_posix_test || ( echo test fd_posix_test failed ; exit 1 )
 	$(E) "[RUN]     Testing fling_stream_test"
@@ -1311,6 +1583,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test || ( echo test gpr_slice_buffer_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_slice_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_slice_test || ( echo test gpr_slice_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_stack_lockfree_test"
+	$(Q) $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test || ( echo test gpr_stack_lockfree_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_string_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_string_test || ( echo test gpr_string_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_sync_test"
@@ -1337,6 +1611,10 @@
 	$(Q) $(BINDIR)/$(CONFIG)/grpc_credentials_test || ( echo test grpc_credentials_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpc_json_token_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpc_json_token_test || ( echo test grpc_json_token_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_jwt_verifier_test"
+	$(Q) $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test || ( echo test grpc_jwt_verifier_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_security_connector_test"
+	$(Q) $(BINDIR)/$(CONFIG)/grpc_security_connector_test || ( echo test grpc_security_connector_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpc_stream_op_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpc_stream_op_test || ( echo test grpc_stream_op_test failed ; exit 1 )
 	$(E) "[RUN]     Testing hpack_parser_test"
@@ -1359,6 +1637,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
 	$(E) "[RUN]     Testing multi_init_test"
 	$(Q) $(BINDIR)/$(CONFIG)/multi_init_test || ( echo test multi_init_test failed ; exit 1 )
+	$(E) "[RUN]     Testing multiple_server_queues_test"
+	$(Q) $(BINDIR)/$(CONFIG)/multiple_server_queues_test || ( echo test multiple_server_queues_test failed ; exit 1 )
 	$(E) "[RUN]     Testing murmur_hash_test"
 	$(Q) $(BINDIR)/$(CONFIG)/murmur_hash_test || ( echo test murmur_hash_test failed ; exit 1 )
 	$(E) "[RUN]     Testing no_server_test"
@@ -1379,8 +1659,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/tcp_server_posix_test || ( echo test tcp_server_posix_test failed ; exit 1 )
 	$(E) "[RUN]     Testing time_averaged_stats_test"
 	$(Q) $(BINDIR)/$(CONFIG)/time_averaged_stats_test || ( echo test time_averaged_stats_test failed ; exit 1 )
-	$(E) "[RUN]     Testing time_test"
-	$(Q) $(BINDIR)/$(CONFIG)/time_test || ( echo test time_test failed ; exit 1 )
 	$(E) "[RUN]     Testing timeout_encoding_test"
 	$(Q) $(BINDIR)/$(CONFIG)/timeout_encoding_test || ( echo test timeout_encoding_test failed ; exit 1 )
 	$(E) "[RUN]     Testing timers_test"
@@ -1389,8 +1667,12 @@
 	$(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 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"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test || ( echo test chttp2_fake_security_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test || ( echo test chttp2_fake_security_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fake_security_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_invoke_test"
@@ -1411,6 +1693,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test || ( echo test chttp2_fake_security_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test || ( echo test chttp2_fake_security_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test || ( echo test chttp2_fake_security_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test || ( echo test chttp2_fake_security_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_max_message_length_test"
@@ -1431,6 +1715,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test || ( echo test chttp2_fake_security_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fake_security_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test || ( echo test chttp2_fake_security_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test || ( echo test chttp2_fake_security_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fake_security_request_with_large_metadata_test"
@@ -1447,6 +1733,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_fake_security_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test || ( echo test chttp2_fullstack_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test || ( echo test chttp2_fullstack_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fullstack_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_invoke_test"
@@ -1467,6 +1755,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test || ( echo test chttp2_fullstack_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test || ( echo test chttp2_fullstack_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test || ( echo test chttp2_fullstack_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test || ( echo test chttp2_fullstack_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_max_message_length_test"
@@ -1487,6 +1777,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test || ( echo test chttp2_fullstack_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test || ( echo test chttp2_fullstack_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test || ( echo test chttp2_fullstack_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_request_with_large_metadata_test"
@@ -1501,8 +1793,72 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test || ( echo test chttp2_fullstack_simple_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_simple_request_with_high_initial_sequence_number_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_fullstack_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_bad_hostname_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test || ( echo test chttp2_fullstack_compression_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test || ( echo test chttp2_fullstack_compression_cancel_after_accept_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_after_invoke_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test || ( echo test chttp2_fullstack_compression_cancel_after_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_before_invoke_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test || ( echo test chttp2_fullstack_compression_cancel_before_invoke_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_in_a_vacuum_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test || ( echo test chttp2_fullstack_compression_cancel_in_a_vacuum_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_census_simple_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test || ( echo test chttp2_fullstack_compression_census_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_disappearing_server_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test || ( echo test chttp2_fullstack_compression_disappearing_server_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test || ( echo test chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test || ( echo test chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_empty_batch_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test || ( echo test chttp2_fullstack_compression_empty_batch_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_graceful_server_shutdown_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test || ( echo test chttp2_fullstack_compression_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test || ( echo test chttp2_fullstack_compression_invoke_large_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_max_concurrent_streams_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test || ( echo test chttp2_fullstack_compression_max_concurrent_streams_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_max_message_length_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test || ( echo test chttp2_fullstack_compression_max_message_length_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_no_op_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test || ( echo test chttp2_fullstack_compression_no_op_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_ping_pong_streaming_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test || ( echo test chttp2_fullstack_compression_ping_pong_streaming_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_registered_call_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test || ( echo test chttp2_fullstack_compression_registered_call_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test || ( echo test chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_metadata_and_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test || ( echo test chttp2_fullstack_compression_request_response_with_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test || ( echo test chttp2_fullstack_compression_request_response_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test || ( echo test chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test || ( echo test chttp2_fullstack_compression_request_with_compressed_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_flags_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test || ( echo test chttp2_fullstack_compression_request_with_flags_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_large_metadata_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test || ( echo test chttp2_fullstack_compression_request_with_large_metadata_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test || ( echo test chttp2_fullstack_compression_request_with_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_server_finishes_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test || ( echo test chttp2_fullstack_compression_server_finishes_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_simple_delayed_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test || ( echo test chttp2_fullstack_compression_simple_delayed_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_simple_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test || ( echo test chttp2_fullstack_compression_simple_request_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test || ( echo test chttp2_fullstack_uds_posix_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test || ( echo test chttp2_fullstack_uds_posix_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_cancel_after_invoke_test"
@@ -1523,6 +1879,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test || ( echo test chttp2_fullstack_uds_posix_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test || ( echo test chttp2_fullstack_uds_posix_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test || ( echo test chttp2_fullstack_uds_posix_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test || ( echo test chttp2_fullstack_uds_posix_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_max_message_length_test"
@@ -1543,6 +1901,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test || ( echo test chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test || ( echo test chttp2_fullstack_uds_posix_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test || ( echo test chttp2_fullstack_uds_posix_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_with_large_metadata_test"
@@ -1559,6 +1919,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test || ( echo test chttp2_fullstack_with_poll_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test || ( echo test chttp2_fullstack_with_poll_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_cancel_after_invoke_test"
@@ -1579,6 +1941,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test || ( echo test chttp2_fullstack_with_poll_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test || ( echo test chttp2_fullstack_with_poll_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test || ( echo test chttp2_fullstack_with_poll_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test || ( echo test chttp2_fullstack_with_poll_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_max_message_length_test"
@@ -1599,6 +1963,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test || ( echo test chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test || ( echo test chttp2_fullstack_with_poll_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test || ( echo test chttp2_fullstack_with_poll_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_with_large_metadata_test"
@@ -1615,6 +1981,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test || ( echo test chttp2_simple_ssl_fullstack_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test || ( echo test chttp2_simple_ssl_fullstack_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_invoke_test"
@@ -1635,6 +2003,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test || ( echo test chttp2_simple_ssl_fullstack_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test || ( echo test chttp2_simple_ssl_fullstack_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test || ( echo test chttp2_simple_ssl_fullstack_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test || ( echo test chttp2_simple_ssl_fullstack_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_max_message_length_test"
@@ -1655,6 +2025,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test || ( echo test chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test || ( echo test chttp2_simple_ssl_fullstack_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test || ( echo test chttp2_simple_ssl_fullstack_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_request_with_large_metadata_test"
@@ -1671,6 +2043,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test"
@@ -1691,6 +2065,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_max_message_length_test"
@@ -1711,6 +2087,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test"
@@ -1727,6 +2105,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test"
@@ -1747,6 +2127,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test"
@@ -1767,6 +2149,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test"
@@ -1783,6 +2167,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test || ( echo test chttp2_socket_pair_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test || ( echo test chttp2_socket_pair_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_socket_pair_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_invoke_test"
@@ -1803,6 +2189,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test || ( echo test chttp2_socket_pair_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test || ( echo test chttp2_socket_pair_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test || ( echo test chttp2_socket_pair_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test || ( echo test chttp2_socket_pair_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_max_message_length_test"
@@ -1823,6 +2211,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test || ( echo test chttp2_socket_pair_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test || ( echo test chttp2_socket_pair_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test || ( echo test chttp2_socket_pair_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_request_with_large_metadata_test"
@@ -1839,6 +2229,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test"
@@ -1859,6 +2251,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_max_message_length_test"
@@ -1879,6 +2273,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test"
@@ -1895,6 +2291,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_bad_hostname_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test || ( echo test chttp2_socket_pair_with_grpc_trace_bad_hostname_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test || ( echo test chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test || ( echo test chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test"
@@ -1915,6 +2313,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test || ( echo test chttp2_socket_pair_with_grpc_trace_empty_batch_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test || ( echo test chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_invoke_large_request_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test || ( echo test chttp2_socket_pair_with_grpc_trace_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test || ( echo test chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_max_message_length_test"
@@ -1935,6 +2335,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_with_flags_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_with_flags_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test"
@@ -1991,6 +2393,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test || ( echo test chttp2_fullstack_request_response_with_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test || ( echo test chttp2_fullstack_request_with_compressed_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_request_with_flags_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test || ( echo test chttp2_fullstack_request_with_flags_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_request_with_large_metadata_unsecure_test"
@@ -2005,6 +2409,64 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test || ( echo test chttp2_fullstack_simple_request_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test || ( echo test chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_bad_hostname_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test || ( echo test chttp2_fullstack_compression_bad_hostname_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_after_accept_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test || ( echo test chttp2_fullstack_compression_cancel_after_accept_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test || ( echo test chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_after_invoke_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test || ( echo test chttp2_fullstack_compression_cancel_after_invoke_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_before_invoke_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test || ( echo test chttp2_fullstack_compression_cancel_before_invoke_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test || ( echo test chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_census_simple_request_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test || ( echo test chttp2_fullstack_compression_census_simple_request_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_disappearing_server_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test || ( echo test chttp2_fullstack_compression_disappearing_server_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test || ( echo test chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test || ( echo test chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_empty_batch_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test || ( echo test chttp2_fullstack_compression_empty_batch_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test || ( echo test chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_max_concurrent_streams_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test || ( echo test chttp2_fullstack_compression_max_concurrent_streams_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_max_message_length_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test || ( echo test chttp2_fullstack_compression_max_message_length_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_no_op_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test || ( echo test chttp2_fullstack_compression_no_op_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_ping_pong_streaming_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test || ( echo test chttp2_fullstack_compression_ping_pong_streaming_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_registered_call_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test || ( echo test chttp2_fullstack_compression_registered_call_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test || ( echo test chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test || ( echo test chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test || ( echo test chttp2_fullstack_compression_request_response_with_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test || ( echo test chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_flags_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test || ( echo test chttp2_fullstack_compression_request_with_flags_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_large_metadata_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test || ( echo test chttp2_fullstack_compression_request_with_large_metadata_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_request_with_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test || ( echo test chttp2_fullstack_compression_request_with_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_server_finishes_request_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test || ( echo test chttp2_fullstack_compression_server_finishes_request_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_simple_delayed_request_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test || ( echo test chttp2_fullstack_compression_simple_delayed_request_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_simple_request_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test || ( echo test chttp2_fullstack_compression_simple_request_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test || ( echo test chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_bad_hostname_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test || ( echo test chttp2_fullstack_uds_posix_bad_hostname_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test"
@@ -2047,6 +2509,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test || ( echo test chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test || ( echo test chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_with_flags_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test || ( echo test chttp2_fullstack_uds_posix_request_with_flags_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test"
@@ -2103,6 +2567,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test || ( echo test chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test || ( echo test chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_with_flags_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test || ( echo test chttp2_fullstack_with_poll_request_with_flags_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test"
@@ -2159,6 +2625,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test || ( echo test chttp2_socket_pair_request_response_with_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test || ( echo test chttp2_socket_pair_request_with_compressed_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_request_with_flags_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test || ( echo test chttp2_socket_pair_request_with_flags_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_request_with_large_metadata_unsecure_test"
@@ -2215,6 +2683,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test"
@@ -2271,6 +2741,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test || ( echo test chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test"
@@ -2292,48 +2764,10 @@
 
 
 flaky_test_c: buildtests_c
-	$(E) "[RUN]     Testing chttp2_fake_security_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test || ( echo test chttp2_fake_security_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fake_security_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test || ( echo test chttp2_fake_security_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fullstack_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test || ( echo test chttp2_fullstack_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fullstack_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test || ( echo test chttp2_fullstack_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test || ( echo test chttp2_fullstack_uds_posix_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test || ( echo test chttp2_fullstack_uds_posix_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test || ( echo test chttp2_fullstack_with_poll_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test || ( echo test chttp2_fullstack_with_poll_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test || ( echo test chttp2_simple_ssl_fullstack_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test || ( echo test chttp2_simple_ssl_fullstack_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test || ( echo test chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test || ( echo test chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_socket_pair_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test || ( echo test chttp2_socket_pair_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_socket_pair_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test || ( echo test chttp2_socket_pair_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test || ( echo test chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test || ( echo test chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test failed ; exit 1 )
-	$(E) "[RUN]     Testing chttp2_socket_pair_with_grpc_trace_invoke_large_request_test"
-	$(Q) $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test || ( echo test chttp2_socket_pair_with_grpc_trace_invoke_large_request_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_invoke_large_request_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test || ( echo test chttp2_fullstack_invoke_large_request_unsecure_test failed ; exit 1 )
+	$(E) "[RUN]     Testing chttp2_fullstack_compression_invoke_large_request_unsecure_test"
+	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test || ( echo test chttp2_fullstack_compression_invoke_large_request_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test || ( echo test chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_fullstack_with_poll_invoke_large_request_unsecure_test"
@@ -2353,6 +2787,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test || ( echo test async_streaming_ping_pong_test failed ; exit 1 )
 	$(E) "[RUN]     Testing async_unary_ping_pong_test"
 	$(Q) $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test || ( echo test async_unary_ping_pong_test failed ; exit 1 )
+	$(E) "[RUN]     Testing auth_property_iterator_test"
+	$(Q) $(BINDIR)/$(CONFIG)/auth_property_iterator_test || ( echo test auth_property_iterator_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_arguments_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_arguments_test || ( echo test channel_arguments_test failed ; exit 1 )
 	$(E) "[RUN]     Testing cli_call_test"
@@ -2361,20 +2797,28 @@
 	$(Q) $(BINDIR)/$(CONFIG)/client_crash_test || ( echo test client_crash_test failed ; exit 1 )
 	$(E) "[RUN]     Testing credentials_test"
 	$(Q) $(BINDIR)/$(CONFIG)/credentials_test || ( echo test credentials_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cxx_byte_buffer_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test || ( echo test cxx_byte_buffer_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cxx_slice_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cxx_slice_test || ( echo test cxx_slice_test failed ; exit 1 )
 	$(E) "[RUN]     Testing cxx_time_test"
 	$(Q) $(BINDIR)/$(CONFIG)/cxx_time_test || ( echo test cxx_time_test failed ; exit 1 )
 	$(E) "[RUN]     Testing end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
+	$(E) "[RUN]     Testing fixed_size_thread_pool_test"
+	$(Q) $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test || ( echo test fixed_size_thread_pool_test failed ; exit 1 )
 	$(E) "[RUN]     Testing generic_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing interop_test"
 	$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
 	$(E) "[RUN]     Testing mock_test"
 	$(Q) $(BINDIR)/$(CONFIG)/mock_test || ( echo test mock_test failed ; exit 1 )
+	$(E) "[RUN]     Testing qps_openloop_test"
+	$(Q) $(BINDIR)/$(CONFIG)/qps_openloop_test || ( echo test qps_openloop_test failed ; exit 1 )
 	$(E) "[RUN]     Testing qps_test"
 	$(Q) $(BINDIR)/$(CONFIG)/qps_test || ( echo test qps_test failed ; exit 1 )
-	$(E) "[RUN]     Testing qps_test_openloop"
-	$(Q) $(BINDIR)/$(CONFIG)/qps_test_openloop || ( echo test qps_test_openloop failed ; exit 1 )
+	$(E) "[RUN]     Testing secure_auth_context_test"
+	$(Q) $(BINDIR)/$(CONFIG)/secure_auth_context_test || ( echo test secure_auth_context_test failed ; exit 1 )
 	$(E) "[RUN]     Testing server_crash_test"
 	$(Q) $(BINDIR)/$(CONFIG)/server_crash_test || ( echo test server_crash_test failed ; exit 1 )
 	$(E) "[RUN]     Testing status_test"
@@ -2383,8 +2827,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test || ( echo test sync_streaming_ping_pong_test failed ; exit 1 )
 	$(E) "[RUN]     Testing sync_unary_ping_pong_test"
 	$(Q) $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test || ( echo test sync_unary_ping_pong_test failed ; exit 1 )
-	$(E) "[RUN]     Testing thread_pool_test"
-	$(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 )
 	$(E) "[RUN]     Testing thread_stress_test"
 	$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
 
@@ -2397,7 +2839,12 @@
 	$(Q) tools/run_tests/run_tests.py -lpython -c$(CONFIG)
 
 
-tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_create_jwt $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 $(BINDIR)/$(CONFIG)/grpc_print_google_default_creds_token
+tools: tools_c tools_cxx
+
+
+tools_c: privatelibs_c $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_create_jwt $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 $(BINDIR)/$(CONFIG)/grpc_print_google_default_creds_token $(BINDIR)/$(CONFIG)/grpc_verify_jwt
+
+tools_cxx: privatelibs_cxx
 
 buildbenchmarks: privatelibs $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_worker
 
@@ -2456,6 +2903,35 @@
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
 endif
 
+cache.mk::
+	$(E) "[MAKE]    Generating $@"
+	$(Q) echo "$(CACHE_MK)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GPR_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPC_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPC_UNSECURE_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPCXX_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPCXX_UNSECURE_PC_FILE)" | tr , '\n' >$@
+
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/examples/pubsub/empty.pb.cc: protoc_dep_error
 $(GENDIR)/examples/pubsub/empty.grpc.pb.cc: protoc_dep_error
@@ -2502,6 +2978,21 @@
 endif
 
 ifeq ($(NO_PROTOC),true)
+$(GENDIR)/test/cpp/qps/perf_db.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc: protoc_dep_error
+else
+$(GENDIR)/test/cpp/qps/perf_db.pb.cc: test/cpp/qps/perf_db.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc: test/cpp/qps/perf_db.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+endif
+
+ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/qps/qpstest.pb.cc: protoc_dep_error
 $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc: protoc_dep_error
 else
@@ -2663,7 +3154,7 @@
 
 install-static: install-static_c install-static_cxx
 
-install-static_c: static_c strip-static_c
+install-static_c: static_c strip-static_c install-pkg-config_c
 	$(E) "[INSTALL] Installing libgpr.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr.a $(prefix)/lib/libgpr.a
@@ -2674,7 +3165,7 @@
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(prefix)/lib/libgrpc_unsecure.a
 
-install-static_cxx: static_cxx strip-static_cxx
+install-static_cxx: static_cxx strip-static_cxx install-pkg-config_cxx
 	$(E) "[INSTALL] Installing libgrpc++.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(prefix)/lib/libgrpc++.a
@@ -2684,7 +3175,7 @@
 
 
 
-install-shared_c: shared_c strip-shared_c
+install-shared_c: shared_c strip-shared_c install-pkg-config_c
 ifeq ($(SYSTEM),MINGW32)
 	$(E) "[INSTALL] Installing gpr.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
@@ -2734,7 +3225,7 @@
 endif
 
 
-install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c
+install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-config_cxx
 ifeq ($(SYSTEM),MINGW32)
 	$(E) "[INSTALL] Installing grpc++.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
@@ -2809,6 +3300,19 @@
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
 endif
 
+install-pkg-config_c: pc_gpr pc_c pc_c_unsecure
+	$(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
+
+install-pkg-config_cxx: pc_cxx pc_cxx_unsecure
+	$(E) "[INSTALL] Installing C++ pkg-config files"
+	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
+	$(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
+
 install-certs: etc/roots.pem
 	$(E) "[INSTALL] Installing root certificates"
 	$(Q) $(INSTALL) -d $(prefix)/share/grpc
@@ -2836,7 +3340,7 @@
 
 clean:
 	$(E) "[CLEAN]   Cleaning build directories."
-	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR)
+	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) cache.mk
 
 
 # The various libraries
@@ -2866,6 +3370,7 @@
     src/core/support/murmur_hash.c \
     src/core/support/slice.c \
     src/core/support/slice_buffer.c \
+    src/core/support/stack_lockfree.c \
     src/core/support/string.c \
     src/core/support/string_posix.c \
     src/core/support/string_win32.c \
@@ -2983,6 +3488,7 @@
     src/core/security/credentials_win32.c \
     src/core/security/google_default_credentials.c \
     src/core/security/json_token.c \
+    src/core/security/jwt_verifier.c \
     src/core/security/secure_endpoint.c \
     src/core/security/secure_transport_setup.c \
     src/core/security/security_connector.c \
@@ -2997,13 +3503,24 @@
     src/core/census/grpc_context.c \
     src/core/channel/channel_args.c \
     src/core/channel/channel_stack.c \
-    src/core/channel/child_channel.c \
     src/core/channel/client_channel.c \
-    src/core/channel/client_setup.c \
+    src/core/channel/compress_filter.c \
     src/core/channel/connected_channel.c \
     src/core/channel/http_client_filter.c \
     src/core/channel/http_server_filter.c \
     src/core/channel/noop_filter.c \
+    src/core/client_config/client_config.c \
+    src/core/client_config/connector.c \
+    src/core/client_config/lb_policies/pick_first.c \
+    src/core/client_config/lb_policy.c \
+    src/core/client_config/resolver.c \
+    src/core/client_config/resolver_factory.c \
+    src/core/client_config/resolver_registry.c \
+    src/core/client_config/resolvers/dns_resolver.c \
+    src/core/client_config/resolvers/unix_resolver_posix.c \
+    src/core/client_config/subchannel.c \
+    src/core/client_config/subchannel_factory.c \
+    src/core/client_config/uri_parser.c \
     src/core/compression/algorithm.c \
     src/core/compression/message_compress.c \
     src/core/debug/trace.c \
@@ -3017,10 +3534,12 @@
     src/core/iomgr/iomgr.c \
     src/core/iomgr/iomgr_posix.c \
     src/core/iomgr/iomgr_windows.c \
-    src/core/iomgr/pollset_kick.c \
+    src/core/iomgr/pollset_kick_posix.c \
     src/core/iomgr/pollset_multipoller_with_epoll.c \
     src/core/iomgr/pollset_multipoller_with_poll_posix.c \
     src/core/iomgr/pollset_posix.c \
+    src/core/iomgr/pollset_set_posix.c \
+    src/core/iomgr/pollset_set_windows.c \
     src/core/iomgr/pollset_windows.c \
     src/core/iomgr/resolve_address_posix.c \
     src/core/iomgr/resolve_address_windows.c \
@@ -3054,7 +3573,6 @@
     src/core/surface/call_log_batch.c \
     src/core/surface/channel.c \
     src/core/surface/channel_create.c \
-    src/core/surface/client.c \
     src/core/surface/completion_queue.c \
     src/core/surface/event_string.c \
     src/core/surface/init.c \
@@ -3064,6 +3582,7 @@
     src/core/surface/server_chttp2.c \
     src/core/surface/server_create.c \
     src/core/surface/surface_trace.c \
+    src/core/surface/version.c \
     src/core/transport/chttp2/alpn.c \
     src/core/transport/chttp2/bin_encoder.c \
     src/core/transport/chttp2/frame_data.c \
@@ -3075,12 +3594,17 @@
     src/core/transport/chttp2/hpack_parser.c \
     src/core/transport/chttp2/hpack_table.c \
     src/core/transport/chttp2/huffsyms.c \
+    src/core/transport/chttp2/incoming_metadata.c \
+    src/core/transport/chttp2/parsing.c \
     src/core/transport/chttp2/status_conversion.c \
     src/core/transport/chttp2/stream_encoder.c \
+    src/core/transport/chttp2/stream_lists.c \
     src/core/transport/chttp2/stream_map.c \
     src/core/transport/chttp2/timeout_encoding.c \
     src/core/transport/chttp2/varint.c \
+    src/core/transport/chttp2/writing.c \
     src/core/transport/chttp2_transport.c \
+    src/core/transport/connectivity_state.c \
     src/core/transport/metadata.c \
     src/core/transport/stream_op.c \
     src/core/transport/transport.c \
@@ -3101,7 +3625,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libgrpc.a: openssl_dep_error
 
@@ -3165,6 +3689,7 @@
     test/core/end2end/data/test_root_cert.c \
     test/core/end2end/cq_verifier.c \
     test/core/iomgr/endpoint_tests.c \
+    test/core/security/oauth2_utils.c \
     test/core/util/grpc_profiler.c \
     test/core/util/parse_hexstring.c \
     test/core/util/port_posix.c \
@@ -3177,7 +3702,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: openssl_dep_error
 
@@ -3209,6 +3734,7 @@
 LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
     test/core/end2end/cq_verifier.c \
     test/core/iomgr/endpoint_tests.c \
+    test/core/security/oauth2_utils.c \
     test/core/util/grpc_profiler.c \
     test/core/util/parse_hexstring.c \
     test/core/util/port_posix.c \
@@ -3241,13 +3767,24 @@
     src/core/census/grpc_context.c \
     src/core/channel/channel_args.c \
     src/core/channel/channel_stack.c \
-    src/core/channel/child_channel.c \
     src/core/channel/client_channel.c \
-    src/core/channel/client_setup.c \
+    src/core/channel/compress_filter.c \
     src/core/channel/connected_channel.c \
     src/core/channel/http_client_filter.c \
     src/core/channel/http_server_filter.c \
     src/core/channel/noop_filter.c \
+    src/core/client_config/client_config.c \
+    src/core/client_config/connector.c \
+    src/core/client_config/lb_policies/pick_first.c \
+    src/core/client_config/lb_policy.c \
+    src/core/client_config/resolver.c \
+    src/core/client_config/resolver_factory.c \
+    src/core/client_config/resolver_registry.c \
+    src/core/client_config/resolvers/dns_resolver.c \
+    src/core/client_config/resolvers/unix_resolver_posix.c \
+    src/core/client_config/subchannel.c \
+    src/core/client_config/subchannel_factory.c \
+    src/core/client_config/uri_parser.c \
     src/core/compression/algorithm.c \
     src/core/compression/message_compress.c \
     src/core/debug/trace.c \
@@ -3261,10 +3798,12 @@
     src/core/iomgr/iomgr.c \
     src/core/iomgr/iomgr_posix.c \
     src/core/iomgr/iomgr_windows.c \
-    src/core/iomgr/pollset_kick.c \
+    src/core/iomgr/pollset_kick_posix.c \
     src/core/iomgr/pollset_multipoller_with_epoll.c \
     src/core/iomgr/pollset_multipoller_with_poll_posix.c \
     src/core/iomgr/pollset_posix.c \
+    src/core/iomgr/pollset_set_posix.c \
+    src/core/iomgr/pollset_set_windows.c \
     src/core/iomgr/pollset_windows.c \
     src/core/iomgr/resolve_address_posix.c \
     src/core/iomgr/resolve_address_windows.c \
@@ -3298,7 +3837,6 @@
     src/core/surface/call_log_batch.c \
     src/core/surface/channel.c \
     src/core/surface/channel_create.c \
-    src/core/surface/client.c \
     src/core/surface/completion_queue.c \
     src/core/surface/event_string.c \
     src/core/surface/init.c \
@@ -3308,6 +3846,7 @@
     src/core/surface/server_chttp2.c \
     src/core/surface/server_create.c \
     src/core/surface/surface_trace.c \
+    src/core/surface/version.c \
     src/core/transport/chttp2/alpn.c \
     src/core/transport/chttp2/bin_encoder.c \
     src/core/transport/chttp2/frame_data.c \
@@ -3319,12 +3858,17 @@
     src/core/transport/chttp2/hpack_parser.c \
     src/core/transport/chttp2/hpack_table.c \
     src/core/transport/chttp2/huffsyms.c \
+    src/core/transport/chttp2/incoming_metadata.c \
+    src/core/transport/chttp2/parsing.c \
     src/core/transport/chttp2/status_conversion.c \
     src/core/transport/chttp2/stream_encoder.c \
+    src/core/transport/chttp2/stream_lists.c \
     src/core/transport/chttp2/stream_map.c \
     src/core/transport/chttp2/timeout_encoding.c \
     src/core/transport/chttp2/varint.c \
+    src/core/transport/chttp2/writing.c \
     src/core/transport/chttp2_transport.c \
+    src/core/transport/connectivity_state.c \
     src/core/transport/metadata.c \
     src/core/transport/stream_op.c \
     src/core/transport/transport.c \
@@ -3377,12 +3921,15 @@
 
 
 LIBGRPC++_SRC = \
+    src/cpp/client/secure_channel_arguments.cc \
     src/cpp/client/secure_credentials.cc \
+    src/cpp/common/auth_property_iterator.cc \
+    src/cpp/common/secure_auth_context.cc \
+    src/cpp/common/secure_create_auth_context.cc \
     src/cpp/server/secure_server_credentials.cc \
     src/cpp/client/channel.cc \
     src/cpp/client/channel_arguments.cc \
     src/cpp/client/client_context.cc \
-    src/cpp/client/client_unary_call.cc \
     src/cpp/client/create_channel.cc \
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
@@ -3394,12 +3941,12 @@
     src/cpp/proto/proto_utils.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
+    src/cpp/server/fixed_size_thread_pool.cc \
     src/cpp/server/insecure_server_credentials.cc \
     src/cpp/server/server.cc \
     src/cpp/server/server_builder.cc \
     src/cpp/server/server_context.cc \
     src/cpp/server/server_credentials.cc \
-    src/cpp/server/thread_pool.cc \
     src/cpp/util/byte_buffer.cc \
     src/cpp/util/slice.cc \
     src/cpp/util/status.cc \
@@ -3408,21 +3955,27 @@
 PUBLIC_HEADERS_CXX += \
     include/grpc++/async_generic_service.h \
     include/grpc++/async_unary_call.h \
+    include/grpc++/auth_context.h \
+    include/grpc++/auth_property_iterator.h \
     include/grpc++/byte_buffer.h \
     include/grpc++/channel_arguments.h \
     include/grpc++/channel_interface.h \
     include/grpc++/client_context.h \
     include/grpc++/completion_queue.h \
     include/grpc++/config.h \
+    include/grpc++/config_protobuf.h \
     include/grpc++/create_channel.h \
     include/grpc++/credentials.h \
+    include/grpc++/fixed_size_thread_pool.h \
     include/grpc++/generic_stub.h \
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
     include/grpc++/impl/grpc_library.h \
     include/grpc++/impl/internal_stub.h \
+    include/grpc++/impl/proto_utils.h \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
+    include/grpc++/impl/serialization_traits.h \
     include/grpc++/impl/service_type.h \
     include/grpc++/impl/sync.h \
     include/grpc++/impl/sync_cxx11.h \
@@ -3445,7 +3998,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libgrpc++.a: openssl_dep_error
 
@@ -3511,57 +4064,6 @@
 endif
 
 
-LIBGRPC++_BENCHMARK_CONFIG_SRC = \
-    $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc \
-    test/cpp/qps/report.cc \
-    test/cpp/util/benchmark_config.cc \
-
-
-LIBGRPC++_BENCHMARK_CONFIG_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_BENCHMARK_CONFIG_SRC))))
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
-
-$(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a: openssl_dep_error
-
-
-else
-
-ifeq ($(NO_PROTOBUF),true)
-
-# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
-
-$(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a: protobuf_dep_error
-
-
-else
-
-$(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_BENCHMARK_CONFIG_OBJS)
-	$(E) "[AR]      Creating $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBGRPC++_BENCHMARK_CONFIG_OBJS)
-ifeq ($(SYSTEM),Darwin)
-	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a
-endif
-
-
-
-
-endif
-
-endif
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(LIBGRPC++_BENCHMARK_CONFIG_OBJS:.o=.dep)
-endif
-endif
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-
-
 LIBGRPC++_TEST_CONFIG_SRC = \
     test/cpp/util/test_config.cc \
 
@@ -3570,7 +4072,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a: openssl_dep_error
 
@@ -3623,7 +4125,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a: openssl_dep_error
 
@@ -3667,10 +4169,10 @@
 
 
 LIBGRPC++_UNSECURE_SRC = \
+    src/cpp/common/insecure_create_auth_context.cc \
     src/cpp/client/channel.cc \
     src/cpp/client/channel_arguments.cc \
     src/cpp/client/client_context.cc \
-    src/cpp/client/client_unary_call.cc \
     src/cpp/client/create_channel.cc \
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
@@ -3682,12 +4184,12 @@
     src/cpp/proto/proto_utils.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
+    src/cpp/server/fixed_size_thread_pool.cc \
     src/cpp/server/insecure_server_credentials.cc \
     src/cpp/server/server.cc \
     src/cpp/server/server_builder.cc \
     src/cpp/server/server_context.cc \
     src/cpp/server/server_credentials.cc \
-    src/cpp/server/thread_pool.cc \
     src/cpp/util/byte_buffer.cc \
     src/cpp/util/slice.cc \
     src/cpp/util/status.cc \
@@ -3696,21 +4198,27 @@
 PUBLIC_HEADERS_CXX += \
     include/grpc++/async_generic_service.h \
     include/grpc++/async_unary_call.h \
+    include/grpc++/auth_context.h \
+    include/grpc++/auth_property_iterator.h \
     include/grpc++/byte_buffer.h \
     include/grpc++/channel_arguments.h \
     include/grpc++/channel_interface.h \
     include/grpc++/client_context.h \
     include/grpc++/completion_queue.h \
     include/grpc++/config.h \
+    include/grpc++/config_protobuf.h \
     include/grpc++/create_channel.h \
     include/grpc++/credentials.h \
+    include/grpc++/fixed_size_thread_pool.h \
     include/grpc++/generic_stub.h \
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
     include/grpc++/impl/grpc_library.h \
     include/grpc++/impl/internal_stub.h \
+    include/grpc++/impl/proto_utils.h \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
+    include/grpc++/impl/serialization_traits.h \
     include/grpc++/impl/service_type.h \
     include/grpc++/impl/sync.h \
     include/grpc++/impl/sync_cxx11.h \
@@ -3827,7 +4335,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: openssl_dep_error
 
@@ -3878,7 +4386,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libinterop_client_main.a: openssl_dep_error
 
@@ -3927,7 +4435,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: openssl_dep_error
 
@@ -3977,7 +4485,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libinterop_server_main.a: openssl_dep_error
 
@@ -4029,7 +4537,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a: openssl_dep_error
 
@@ -4072,20 +4580,24 @@
 
 LIBQPS_SRC = \
     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc \
+    $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc \
     test/cpp/qps/client_async.cc \
     test/cpp/qps/client_sync.cc \
     test/cpp/qps/driver.cc \
+    test/cpp/qps/perf_db_client.cc \
     test/cpp/qps/qps_worker.cc \
+    test/cpp/qps/report.cc \
     test/cpp/qps/server_async.cc \
     test/cpp/qps/server_sync.cc \
     test/cpp/qps/timer.cc \
+    test/cpp/util/benchmark_config.cc \
 
 
 LIBQPS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBQPS_SRC))))
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libqps.a: openssl_dep_error
 
@@ -4122,13 +4634,16 @@
 -include $(LIBQPS_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
 
 
 LIBGRPC_CSHARP_EXT_SRC = \
@@ -4139,7 +4654,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: openssl_dep_error
 
@@ -4198,7 +4713,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a: openssl_dep_error
 
@@ -4250,6 +4765,29 @@
 endif
 
 
+LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_COMPRESSION_SRC = \
+    test/core/end2end/fixtures/chttp2_fullstack_compression.c \
+
+
+LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_COMPRESSION_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_COMPRESSION_SRC))))
+
+$(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a: $(ZLIB_DEP) $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_COMPRESSION_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_COMPRESSION_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a
+endif
+
+
+
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_COMPRESSION_OBJS:.o=.dep)
+endif
+
+
 LIBEND2END_FIXTURE_CHTTP2_FULLSTACK_UDS_POSIX_SRC = \
     test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c \
 
@@ -4304,7 +4842,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a: openssl_dep_error
 
@@ -4341,7 +4879,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack_with_poll.a: openssl_dep_error
 
@@ -4378,7 +4916,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a: openssl_dep_error
 
@@ -4967,7 +5505,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_and_call_creds.a: openssl_dep_error
 
@@ -5019,6 +5557,29 @@
 endif
 
 
+LIBEND2END_TEST_REQUEST_WITH_COMPRESSED_PAYLOAD_SRC = \
+    test/core/end2end/tests/request_with_compressed_payload.c \
+
+
+LIBEND2END_TEST_REQUEST_WITH_COMPRESSED_PAYLOAD_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_TEST_REQUEST_WITH_COMPRESSED_PAYLOAD_SRC))))
+
+$(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a: $(ZLIB_DEP) $(LIBEND2END_TEST_REQUEST_WITH_COMPRESSED_PAYLOAD_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBEND2END_TEST_REQUEST_WITH_COMPRESSED_PAYLOAD_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a
+endif
+
+
+
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBEND2END_TEST_REQUEST_WITH_COMPRESSED_PAYLOAD_OBJS:.o=.dep)
+endif
+
+
 LIBEND2END_TEST_REQUEST_WITH_FLAGS_SRC = \
     test/core/end2end/tests/request_with_flags.c \
 
@@ -5190,7 +5751,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libend2end_certs.a: openssl_dep_error
 
@@ -5227,7 +5788,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/libbad_client_test.a: openssl_dep_error
 
@@ -5266,7 +5827,7 @@
 ALARM_HEAP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALARM_HEAP_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/alarm_heap_test: openssl_dep_error
 
@@ -5295,7 +5856,7 @@
 ALARM_LIST_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALARM_LIST_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/alarm_list_test: openssl_dep_error
 
@@ -5324,7 +5885,7 @@
 ALARM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALARM_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/alarm_test: openssl_dep_error
 
@@ -5353,7 +5914,7 @@
 ALPN_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALPN_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/alpn_test: openssl_dep_error
 
@@ -5382,7 +5943,7 @@
 BIN_ENCODER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BIN_ENCODER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/bin_encoder_test: openssl_dep_error
 
@@ -5411,7 +5972,7 @@
 CHTTP2_STATUS_CONVERSION_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHTTP2_STATUS_CONVERSION_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test: openssl_dep_error
 
@@ -5440,7 +6001,7 @@
 CHTTP2_STREAM_ENCODER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHTTP2_STREAM_ENCODER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test: openssl_dep_error
 
@@ -5469,7 +6030,7 @@
 CHTTP2_STREAM_MAP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHTTP2_STREAM_MAP_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_stream_map_test: openssl_dep_error
 
@@ -5498,7 +6059,7 @@
 DUALSTACK_SOCKET_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DUALSTACK_SOCKET_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/dualstack_socket_test: openssl_dep_error
 
@@ -5521,13 +6082,42 @@
 endif
 
 
+FD_CONSERVATION_POSIX_TEST_SRC = \
+    test/core/iomgr/fd_conservation_posix_test.c \
+
+FD_CONSERVATION_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FD_CONSERVATION_POSIX_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/fd_conservation_posix_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/fd_conservation_posix_test: $(FD_CONSERVATION_POSIX_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) $(FD_CONSERVATION_POSIX_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)/fd_conservation_posix_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/fd_conservation_posix_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_fd_conservation_posix_test: $(FD_CONSERVATION_POSIX_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(FD_CONSERVATION_POSIX_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 FD_POSIX_TEST_SRC = \
     test/core/iomgr/fd_posix_test.c \
 
 FD_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FD_POSIX_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/fd_posix_test: openssl_dep_error
 
@@ -5556,7 +6146,7 @@
 FLING_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FLING_CLIENT_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/fling_client: openssl_dep_error
 
@@ -5585,7 +6175,7 @@
 FLING_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FLING_SERVER_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/fling_server: openssl_dep_error
 
@@ -5614,7 +6204,7 @@
 FLING_STREAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FLING_STREAM_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/fling_stream_test: openssl_dep_error
 
@@ -5643,7 +6233,7 @@
 FLING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FLING_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/fling_test: openssl_dep_error
 
@@ -5667,25 +6257,25 @@
 
 
 GEN_HPACK_TABLES_SRC = \
-    src/core/transport/chttp2/gen_hpack_tables.c \
+    tools/codegen/core/gen_hpack_tables.c \
 
 GEN_HPACK_TABLES_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GEN_HPACK_TABLES_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gen_hpack_tables: openssl_dep_error
 
 else
 
-$(BINDIR)/$(CONFIG)/gen_hpack_tables: $(GEN_HPACK_TABLES_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+$(BINDIR)/$(CONFIG)/gen_hpack_tables: $(GEN_HPACK_TABLES_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GEN_HPACK_TABLES_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gen_hpack_tables
+	$(Q) $(LD) $(LDFLAGS) $(GEN_HPACK_TABLES_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gen_hpack_tables
 
 endif
 
-$(OBJDIR)/$(CONFIG)/src/core/transport/chttp2/gen_hpack_tables.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+$(OBJDIR)/$(CONFIG)/tools/codegen/core/gen_hpack_tables.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
 deps_gen_hpack_tables: $(GEN_HPACK_TABLES_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -5701,7 +6291,7 @@
 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 with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_cancellable_test: openssl_dep_error
 
@@ -5730,7 +6320,7 @@
 GPR_CMDLINE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_CMDLINE_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_cmdline_test: openssl_dep_error
 
@@ -5759,7 +6349,7 @@
 GPR_ENV_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_ENV_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_env_test: openssl_dep_error
 
@@ -5788,7 +6378,7 @@
 GPR_FILE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_FILE_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_file_test: openssl_dep_error
 
@@ -5817,7 +6407,7 @@
 GPR_HISTOGRAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_HISTOGRAM_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_histogram_test: openssl_dep_error
 
@@ -5846,7 +6436,7 @@
 GPR_HOST_PORT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_HOST_PORT_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_host_port_test: openssl_dep_error
 
@@ -5875,7 +6465,7 @@
 GPR_LOG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_LOG_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_log_test: openssl_dep_error
 
@@ -5904,7 +6494,7 @@
 GPR_SLICE_BUFFER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_SLICE_BUFFER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test: openssl_dep_error
 
@@ -5933,7 +6523,7 @@
 GPR_SLICE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_SLICE_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_slice_test: openssl_dep_error
 
@@ -5956,13 +6546,42 @@
 endif
 
 
+GPR_STACK_LOCKFREE_TEST_SRC = \
+    test/core/support/stack_lockfree_test.c \
+
+GPR_STACK_LOCKFREE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_STACK_LOCKFREE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/stack_lockfree_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GPR_STRING_TEST_SRC = \
     test/core/support/string_test.c \
 
 GPR_STRING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_STRING_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_string_test: openssl_dep_error
 
@@ -5991,7 +6610,7 @@
 GPR_SYNC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_SYNC_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_sync_test: openssl_dep_error
 
@@ -6020,7 +6639,7 @@
 GPR_THD_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_THD_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_thd_test: openssl_dep_error
 
@@ -6049,7 +6668,7 @@
 GPR_TIME_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_TIME_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_time_test: openssl_dep_error
 
@@ -6078,7 +6697,7 @@
 GPR_TLS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_TLS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_tls_test: openssl_dep_error
 
@@ -6107,7 +6726,7 @@
 GPR_USEFUL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_USEFUL_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/gpr_useful_test: openssl_dep_error
 
@@ -6136,7 +6755,7 @@
 GRPC_AUTH_CONTEXT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_AUTH_CONTEXT_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_auth_context_test: openssl_dep_error
 
@@ -6165,7 +6784,7 @@
 GRPC_BASE64_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_BASE64_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_base64_test: openssl_dep_error
 
@@ -6194,7 +6813,7 @@
 GRPC_BYTE_BUFFER_READER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_BYTE_BUFFER_READER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test: openssl_dep_error
 
@@ -6223,7 +6842,7 @@
 GRPC_CHANNEL_STACK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CHANNEL_STACK_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_channel_stack_test: openssl_dep_error
 
@@ -6252,7 +6871,7 @@
 GRPC_COMPLETION_QUEUE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_COMPLETION_QUEUE_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_completion_queue_test: openssl_dep_error
 
@@ -6281,7 +6900,7 @@
 GRPC_CREATE_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CREATE_JWT_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_create_jwt: openssl_dep_error
 
@@ -6310,7 +6929,7 @@
 GRPC_CREDENTIALS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CREDENTIALS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_credentials_test: openssl_dep_error
 
@@ -6339,7 +6958,7 @@
 GRPC_FETCH_OAUTH2_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_FETCH_OAUTH2_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2: openssl_dep_error
 
@@ -6368,7 +6987,7 @@
 GRPC_JSON_TOKEN_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_JSON_TOKEN_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_json_token_test: openssl_dep_error
 
@@ -6391,13 +7010,42 @@
 endif
 
 
+GRPC_JWT_VERIFIER_TEST_SRC = \
+    test/core/security/jwt_verifier_test.c \
+
+GRPC_JWT_VERIFIER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_JWT_VERIFIER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test: $(GRPC_JWT_VERIFIER_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) $(GRPC_JWT_VERIFIER_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)/grpc_jwt_verifier_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/jwt_verifier_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_grpc_jwt_verifier_test: $(GRPC_JWT_VERIFIER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_JWT_VERIFIER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_SRC = \
     test/core/security/print_google_default_creds_token.c \
 
 GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_print_google_default_creds_token: openssl_dep_error
 
@@ -6420,13 +7068,42 @@
 endif
 
 
+GRPC_SECURITY_CONNECTOR_TEST_SRC = \
+    test/core/security/security_connector_test.c \
+
+GRPC_SECURITY_CONNECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_SECURITY_CONNECTOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpc_security_connector_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_security_connector_test: $(GRPC_SECURITY_CONNECTOR_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) $(GRPC_SECURITY_CONNECTOR_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)/grpc_security_connector_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/security_connector_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_grpc_security_connector_test: $(GRPC_SECURITY_CONNECTOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_SECURITY_CONNECTOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GRPC_STREAM_OP_TEST_SRC = \
     test/core/transport/stream_op_test.c \
 
 GRPC_STREAM_OP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_STREAM_OP_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_stream_op_test: openssl_dep_error
 
@@ -6449,13 +7126,42 @@
 endif
 
 
+GRPC_VERIFY_JWT_SRC = \
+    test/core/security/verify_jwt.c \
+
+GRPC_VERIFY_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_VERIFY_JWT_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpc_verify_jwt: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_verify_jwt: $(GRPC_VERIFY_JWT_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) $(GRPC_VERIFY_JWT_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)/grpc_verify_jwt
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/verify_jwt.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_grpc_verify_jwt: $(GRPC_VERIFY_JWT_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_VERIFY_JWT_OBJS:.o=.dep)
+endif
+endif
+
+
 HPACK_PARSER_TEST_SRC = \
     test/core/transport/chttp2/hpack_parser_test.c \
 
 HPACK_PARSER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HPACK_PARSER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/hpack_parser_test: openssl_dep_error
 
@@ -6484,7 +7190,7 @@
 HPACK_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HPACK_TABLE_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/hpack_table_test: openssl_dep_error
 
@@ -6513,7 +7219,7 @@
 HTTPCLI_FORMAT_REQUEST_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPCLI_FORMAT_REQUEST_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/httpcli_format_request_test: openssl_dep_error
 
@@ -6542,7 +7248,7 @@
 HTTPCLI_PARSER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPCLI_PARSER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/httpcli_parser_test: openssl_dep_error
 
@@ -6571,7 +7277,7 @@
 HTTPCLI_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPCLI_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/httpcli_test: openssl_dep_error
 
@@ -6600,7 +7306,7 @@
 JSON_REWRITE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_REWRITE_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/json_rewrite: openssl_dep_error
 
@@ -6629,7 +7335,7 @@
 JSON_REWRITE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_REWRITE_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/json_rewrite_test: openssl_dep_error
 
@@ -6658,7 +7364,7 @@
 JSON_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/json_test: openssl_dep_error
 
@@ -6687,7 +7393,7 @@
 LAME_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LAME_CLIENT_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/lame_client_test: openssl_dep_error
 
@@ -6716,7 +7422,7 @@
 LOW_LEVEL_PING_PONG_BENCHMARK_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LOW_LEVEL_PING_PONG_BENCHMARK_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark: openssl_dep_error
 
@@ -6745,7 +7451,7 @@
 MESSAGE_COMPRESS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MESSAGE_COMPRESS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/message_compress_test: openssl_dep_error
 
@@ -6774,7 +7480,7 @@
 MULTI_INIT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MULTI_INIT_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/multi_init_test: openssl_dep_error
 
@@ -6797,13 +7503,42 @@
 endif
 
 
+MULTIPLE_SERVER_QUEUES_TEST_SRC = \
+    test/core/end2end/multiple_server_queues_test.c \
+
+MULTIPLE_SERVER_QUEUES_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MULTIPLE_SERVER_QUEUES_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/multiple_server_queues_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/multiple_server_queues_test: $(MULTIPLE_SERVER_QUEUES_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) $(MULTIPLE_SERVER_QUEUES_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)/multiple_server_queues_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/multiple_server_queues_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_multiple_server_queues_test: $(MULTIPLE_SERVER_QUEUES_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(MULTIPLE_SERVER_QUEUES_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 MURMUR_HASH_TEST_SRC = \
     test/core/support/murmur_hash_test.c \
 
 MURMUR_HASH_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MURMUR_HASH_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/murmur_hash_test: openssl_dep_error
 
@@ -6832,7 +7567,7 @@
 NO_SERVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(NO_SERVER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/no_server_test: openssl_dep_error
 
@@ -6861,7 +7596,7 @@
 POLL_KICK_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(POLL_KICK_POSIX_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/poll_kick_posix_test: openssl_dep_error
 
@@ -6890,7 +7625,7 @@
 RESOLVE_ADDRESS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/resolve_address_test: openssl_dep_error
 
@@ -6919,7 +7654,7 @@
 SECURE_ENDPOINT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SECURE_ENDPOINT_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/secure_endpoint_test: openssl_dep_error
 
@@ -6948,7 +7683,7 @@
 SOCKADDR_UTILS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SOCKADDR_UTILS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/sockaddr_utils_test: openssl_dep_error
 
@@ -6977,7 +7712,7 @@
 TCP_CLIENT_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TCP_CLIENT_POSIX_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/tcp_client_posix_test: openssl_dep_error
 
@@ -7006,7 +7741,7 @@
 TCP_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TCP_POSIX_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/tcp_posix_test: openssl_dep_error
 
@@ -7035,7 +7770,7 @@
 TCP_SERVER_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TCP_SERVER_POSIX_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/tcp_server_posix_test: openssl_dep_error
 
@@ -7064,7 +7799,7 @@
 TIME_AVERAGED_STATS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIME_AVERAGED_STATS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/time_averaged_stats_test: openssl_dep_error
 
@@ -7087,42 +7822,13 @@
 endif
 
 
-TIME_TEST_SRC = \
-    test/core/support/time_test.c \
-
-TIME_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIME_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/time_test: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/time_test: $(TIME_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) $(TIME_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)/time_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/support/time_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_time_test: $(TIME_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(TIME_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 TIMEOUT_ENCODING_TEST_SRC = \
     test/core/transport/chttp2/timeout_encoding_test.c \
 
 TIMEOUT_ENCODING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIMEOUT_ENCODING_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/timeout_encoding_test: openssl_dep_error
 
@@ -7151,7 +7857,7 @@
 TIMERS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIMERS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/timers_test: openssl_dep_error
 
@@ -7180,7 +7886,7 @@
 TRANSPORT_METADATA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_METADATA_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/transport_metadata_test: openssl_dep_error
 
@@ -7209,7 +7915,7 @@
 TRANSPORT_SECURITY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_SECURITY_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/transport_security_test: openssl_dep_error
 
@@ -7232,13 +7938,42 @@
 endif
 
 
+URI_PARSER_TEST_SRC = \
+    test/core/client_config/uri_parser_test.c \
+
+URI_PARSER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(URI_PARSER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/uri_parser_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/uri_parser_test: $(URI_PARSER_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) $(URI_PARSER_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)/uri_parser_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/client_config/uri_parser_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_uri_parser_test: $(URI_PARSER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(URI_PARSER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ASYNC_END2END_TEST_SRC = \
     test/cpp/end2end/async_end2end_test.cc \
 
 ASYNC_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ASYNC_END2END_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/async_end2end_test: openssl_dep_error
 
@@ -7278,7 +8013,7 @@
 ASYNC_STREAMING_PING_PONG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ASYNC_STREAMING_PING_PONG_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test: openssl_dep_error
 
@@ -7293,16 +8028,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test: $(PROTOBUF_DEP) $(ASYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test: $(PROTOBUF_DEP) $(ASYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(ASYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test
+	$(Q) $(LDXX) $(LDFLAGS) $(ASYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/async_streaming_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/async_streaming_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 deps_async_streaming_ping_pong_test: $(ASYNC_STREAMING_PING_PONG_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -7318,7 +8053,7 @@
 ASYNC_UNARY_PING_PONG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ASYNC_UNARY_PING_PONG_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test: openssl_dep_error
 
@@ -7333,16 +8068,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/async_unary_ping_pong_test: $(PROTOBUF_DEP) $(ASYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/async_unary_ping_pong_test: $(PROTOBUF_DEP) $(ASYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(ASYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test
+	$(Q) $(LDXX) $(LDFLAGS) $(ASYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/async_unary_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/async_unary_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 deps_async_unary_ping_pong_test: $(ASYNC_UNARY_PING_PONG_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -7352,13 +8087,53 @@
 endif
 
 
+AUTH_PROPERTY_ITERATOR_TEST_SRC = \
+    test/cpp/common/auth_property_iterator_test.cc \
+
+AUTH_PROPERTY_ITERATOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(AUTH_PROPERTY_ITERATOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/auth_property_iterator_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)/auth_property_iterator_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_auth_property_iterator_test: $(AUTH_PROPERTY_ITERATOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(AUTH_PROPERTY_ITERATOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CHANNEL_ARGUMENTS_TEST_SRC = \
     test/cpp/client/channel_arguments_test.cc \
 
 CHANNEL_ARGUMENTS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHANNEL_ARGUMENTS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/channel_arguments_test: openssl_dep_error
 
@@ -7398,7 +8173,7 @@
 CLI_CALL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLI_CALL_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/cli_call_test: openssl_dep_error
 
@@ -7438,7 +8213,7 @@
 CLIENT_CRASH_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLIENT_CRASH_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/client_crash_test: openssl_dep_error
 
@@ -7478,7 +8253,7 @@
 CLIENT_CRASH_TEST_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLIENT_CRASH_TEST_SERVER_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/client_crash_test_server: openssl_dep_error
 
@@ -7518,7 +8293,7 @@
 CREDENTIALS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CREDENTIALS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/credentials_test: openssl_dep_error
 
@@ -7552,13 +8327,93 @@
 endif
 
 
+CXX_BYTE_BUFFER_TEST_SRC = \
+    test/cpp/util/byte_buffer_test.cc \
+
+CXX_BYTE_BUFFER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CXX_BYTE_BUFFER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/cxx_byte_buffer_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)/cxx_byte_buffer_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/cxx_byte_buffer_test: $(PROTOBUF_DEP) $(CXX_BYTE_BUFFER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(CXX_BYTE_BUFFER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_cxx_byte_buffer_test: $(CXX_BYTE_BUFFER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CXX_BYTE_BUFFER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+CXX_SLICE_TEST_SRC = \
+    test/cpp/util/slice_test.cc \
+
+CXX_SLICE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CXX_SLICE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/cxx_slice_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)/cxx_slice_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/cxx_slice_test: $(PROTOBUF_DEP) $(CXX_SLICE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(CXX_SLICE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cxx_slice_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/slice_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_cxx_slice_test: $(CXX_SLICE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CXX_SLICE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CXX_TIME_TEST_SRC = \
     test/cpp/util/time_test.cc \
 
 CXX_TIME_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CXX_TIME_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/cxx_time_test: openssl_dep_error
 
@@ -7598,7 +8453,7 @@
 END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(END2END_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/end2end_test: openssl_dep_error
 
@@ -7632,13 +8487,53 @@
 endif
 
 
+FIXED_SIZE_THREAD_POOL_TEST_SRC = \
+    test/cpp/server/fixed_size_thread_pool_test.cc \
+
+FIXED_SIZE_THREAD_POOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FIXED_SIZE_THREAD_POOL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/fixed_size_thread_pool_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)/fixed_size_thread_pool_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test: $(PROTOBUF_DEP) $(FIXED_SIZE_THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(FIXED_SIZE_THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/server/fixed_size_thread_pool_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_fixed_size_thread_pool_test: $(FIXED_SIZE_THREAD_POOL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(FIXED_SIZE_THREAD_POOL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GENERIC_END2END_TEST_SRC = \
     test/cpp/end2end/generic_end2end_test.cc \
 
 GENERIC_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GENERIC_END2END_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/generic_end2end_test: openssl_dep_error
 
@@ -7678,7 +8573,7 @@
 GRPC_CLI_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CLI_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/grpc_cli: openssl_dep_error
 
@@ -7854,7 +8749,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/interop_client: openssl_dep_error
 
@@ -7883,7 +8778,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/interop_server: openssl_dep_error
 
@@ -7916,7 +8811,7 @@
 INTEROP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/interop_test: openssl_dep_error
 
@@ -7956,7 +8851,7 @@
 MOCK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MOCK_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/mock_test: openssl_dep_error
 
@@ -7996,7 +8891,7 @@
 PUBSUB_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_CLIENT_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/pubsub_client: openssl_dep_error
 
@@ -8036,7 +8931,7 @@
 PUBSUB_PUBLISHER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_PUBLISHER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/pubsub_publisher_test: openssl_dep_error
 
@@ -8076,7 +8971,7 @@
 PUBSUB_SUBSCRIBER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_SUBSCRIBER_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/pubsub_subscriber_test: openssl_dep_error
 
@@ -8116,7 +9011,7 @@
 QPS_DRIVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_DRIVER_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/qps_driver: openssl_dep_error
 
@@ -8131,16 +9026,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/qps_driver: $(PROTOBUF_DEP) $(QPS_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a
+$(BINDIR)/$(CONFIG)/qps_driver: $(PROTOBUF_DEP) $(QPS_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(QPS_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_driver
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_DRIVER_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_driver
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_driver.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_driver.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 deps_qps_driver: $(QPS_DRIVER_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -8156,7 +9051,7 @@
 QPS_INTERARRIVAL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_INTERARRIVAL_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/qps_interarrival_test: openssl_dep_error
 
@@ -8190,13 +9085,53 @@
 endif
 
 
+QPS_OPENLOOP_TEST_SRC = \
+    test/cpp/qps/qps_openloop_test.cc \
+
+QPS_OPENLOOP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_OPENLOOP_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/qps_openloop_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)/qps_openloop_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/qps_openloop_test: $(PROTOBUF_DEP) $(QPS_OPENLOOP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_OPENLOOP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_openloop_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_openloop_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+deps_qps_openloop_test: $(QPS_OPENLOOP_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(QPS_OPENLOOP_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 QPS_TEST_SRC = \
     test/cpp/qps/qps_test.cc \
 
 QPS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/qps_test: openssl_dep_error
 
@@ -8211,16 +9146,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/qps_test: $(PROTOBUF_DEP) $(QPS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(BINDIR)/$(CONFIG)/qps_test: $(PROTOBUF_DEP) $(QPS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(QPS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_test
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 deps_qps_test: $(QPS_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -8230,53 +9165,13 @@
 endif
 
 
-QPS_TEST_OPENLOOP_SRC = \
-    test/cpp/qps/qps_test_openloop.cc \
-
-QPS_TEST_OPENLOOP_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_TEST_OPENLOOP_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/qps_test_openloop: 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)/qps_test_openloop: protobuf_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/qps_test_openloop: $(PROTOBUF_DEP) $(QPS_TEST_OPENLOOP_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(QPS_TEST_OPENLOOP_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_test_openloop
-
-endif
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_test_openloop.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
-deps_qps_test_openloop: $(QPS_TEST_OPENLOOP_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(QPS_TEST_OPENLOOP_OBJS:.o=.dep)
-endif
-endif
-
-
 QPS_WORKER_SRC = \
     test/cpp/qps/worker.cc \
 
 QPS_WORKER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_WORKER_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/qps_worker: openssl_dep_error
 
@@ -8310,13 +9205,53 @@
 endif
 
 
+SECURE_AUTH_CONTEXT_TEST_SRC = \
+    test/cpp/common/secure_auth_context_test.cc \
+
+SECURE_AUTH_CONTEXT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SECURE_AUTH_CONTEXT_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/secure_auth_context_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)/secure_auth_context_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_secure_auth_context_test: $(SECURE_AUTH_CONTEXT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(SECURE_AUTH_CONTEXT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 SERVER_CRASH_TEST_SRC = \
     test/cpp/end2end/server_crash_test.cc \
 
 SERVER_CRASH_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVER_CRASH_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/server_crash_test: openssl_dep_error
 
@@ -8356,7 +9291,7 @@
 SERVER_CRASH_TEST_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVER_CRASH_TEST_CLIENT_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/server_crash_test_client: openssl_dep_error
 
@@ -8396,7 +9331,7 @@
 STATUS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STATUS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/status_test: openssl_dep_error
 
@@ -8436,7 +9371,7 @@
 SYNC_STREAMING_PING_PONG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SYNC_STREAMING_PING_PONG_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test: openssl_dep_error
 
@@ -8451,16 +9386,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test: $(PROTOBUF_DEP) $(SYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test: $(PROTOBUF_DEP) $(SYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(SYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test
+	$(Q) $(LDXX) $(LDFLAGS) $(SYNC_STREAMING_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/sync_streaming_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/sync_streaming_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 deps_sync_streaming_ping_pong_test: $(SYNC_STREAMING_PING_PONG_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -8476,7 +9411,7 @@
 SYNC_UNARY_PING_PONG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SYNC_UNARY_PING_PONG_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test: openssl_dep_error
 
@@ -8491,16 +9426,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test: $(PROTOBUF_DEP) $(SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test: $(PROTOBUF_DEP) $(SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test
+	$(Q) $(LDXX) $(LDFLAGS) $(SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/sync_unary_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_benchmark_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/sync_unary_ping_pong_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 deps_sync_unary_ping_pong_test: $(SYNC_UNARY_PING_PONG_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -8510,53 +9445,13 @@
 endif
 
 
-THREAD_POOL_TEST_SRC = \
-    test/cpp/server/thread_pool_test.cc \
-
-THREAD_POOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(THREAD_POOL_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/thread_pool_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)/thread_pool_test: protobuf_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/thread_pool_test: $(PROTOBUF_DEP) $(THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.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) $(THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/thread_pool_test
-
-endif
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/cpp/server/thread_pool_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_thread_pool_test: $(THREAD_POOL_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(THREAD_POOL_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 THREAD_STRESS_TEST_SRC = \
     test/cpp/end2end/thread_stress_test.cc \
 
 THREAD_STRESS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(THREAD_STRESS_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/thread_stress_test: openssl_dep_error
 
@@ -8592,7 +9487,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test: openssl_dep_error
 
@@ -8610,7 +9505,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test: openssl_dep_error
 
@@ -8628,7 +9523,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -8646,7 +9541,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test: openssl_dep_error
 
@@ -8664,7 +9559,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test: openssl_dep_error
 
@@ -8682,7 +9577,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -8700,7 +9595,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test: openssl_dep_error
 
@@ -8718,7 +9613,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test: openssl_dep_error
 
@@ -8736,7 +9631,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -8754,7 +9649,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -8772,7 +9667,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test: openssl_dep_error
 
@@ -8790,7 +9685,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test: openssl_dep_error
 
@@ -8808,7 +9703,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test: openssl_dep_error
 
@@ -8826,7 +9721,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test: openssl_dep_error
 
@@ -8844,7 +9739,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test: openssl_dep_error
 
@@ -8862,7 +9757,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test: openssl_dep_error
 
@@ -8880,7 +9775,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test: openssl_dep_error
 
@@ -8898,7 +9793,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test: openssl_dep_error
 
@@ -8916,7 +9811,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -8934,7 +9829,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -8952,7 +9847,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test: openssl_dep_error
 
@@ -8970,7 +9865,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -8988,7 +9883,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -9006,7 +9901,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fake_security_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test: openssl_dep_error
 
@@ -9024,7 +9937,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test: openssl_dep_error
 
@@ -9042,7 +9955,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test: openssl_dep_error
 
@@ -9060,7 +9973,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test: openssl_dep_error
 
@@ -9078,7 +9991,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test: openssl_dep_error
 
@@ -9096,7 +10009,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test: openssl_dep_error
 
@@ -9114,7 +10027,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -9132,7 +10045,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test: openssl_dep_error
 
@@ -9150,7 +10063,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test: openssl_dep_error
 
@@ -9168,7 +10081,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -9186,7 +10099,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test: openssl_dep_error
 
@@ -9204,7 +10117,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test: openssl_dep_error
 
@@ -9222,7 +10135,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -9240,7 +10153,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test: openssl_dep_error
 
@@ -9258,7 +10171,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test: openssl_dep_error
 
@@ -9276,7 +10189,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -9294,7 +10207,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -9312,7 +10225,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test: openssl_dep_error
 
@@ -9330,7 +10243,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test: openssl_dep_error
 
@@ -9348,7 +10261,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test: openssl_dep_error
 
@@ -9366,7 +10279,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test: openssl_dep_error
 
@@ -9384,7 +10297,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test: openssl_dep_error
 
@@ -9402,7 +10315,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test: openssl_dep_error
 
@@ -9420,7 +10333,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test: openssl_dep_error
 
@@ -9438,7 +10351,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test: openssl_dep_error
 
@@ -9456,7 +10369,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -9474,7 +10387,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -9492,7 +10405,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test: openssl_dep_error
 
@@ -9510,7 +10423,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -9528,7 +10441,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -9546,7 +10459,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test: openssl_dep_error
 
@@ -9564,7 +10495,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test: openssl_dep_error
 
@@ -9582,7 +10513,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test: openssl_dep_error
 
@@ -9600,7 +10531,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test: openssl_dep_error
 
@@ -9618,7 +10549,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test: openssl_dep_error
 
@@ -9636,7 +10567,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test: openssl_dep_error
 
@@ -9654,7 +10585,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -9672,7 +10603,565 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_bad_hostname_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_cancel_after_accept_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_cancel_after_invoke_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_cancel_before_invoke_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_cancel_in_a_vacuum_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_census_simple_request_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_disappearing_server_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_empty_batch_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_graceful_server_shutdown_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_invoke_large_request_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_max_concurrent_streams_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_message_length.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_message_length.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_max_message_length_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_no_op_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_ping_pong_streaming_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_registered_call.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_registered_call.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_registered_call_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_response_with_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_and_call_creds.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_and_call_creds.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_with_flags_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_with_large_metadata_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_request_with_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_server_finishes_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_server_finishes_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_server_finishes_request_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_simple_delayed_request_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_simple_request_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_with_high_initial_sequence_number.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_with_high_initial_sequence_number.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test: openssl_dep_error
 
@@ -9690,7 +11179,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test: openssl_dep_error
 
@@ -9708,7 +11197,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -9726,7 +11215,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test: openssl_dep_error
 
@@ -9744,7 +11233,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test: openssl_dep_error
 
@@ -9762,7 +11251,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -9780,7 +11269,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test: openssl_dep_error
 
@@ -9798,7 +11287,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test: openssl_dep_error
 
@@ -9816,7 +11305,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -9834,7 +11323,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -9852,7 +11341,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test: openssl_dep_error
 
@@ -9870,7 +11359,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test: openssl_dep_error
 
@@ -9888,7 +11377,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test: openssl_dep_error
 
@@ -9906,7 +11395,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test: openssl_dep_error
 
@@ -9924,7 +11413,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test: openssl_dep_error
 
@@ -9942,7 +11431,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test: openssl_dep_error
 
@@ -9960,7 +11449,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test: openssl_dep_error
 
@@ -9978,7 +11467,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test: openssl_dep_error
 
@@ -9996,7 +11485,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -10014,7 +11503,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -10032,7 +11521,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test: openssl_dep_error
 
@@ -10050,7 +11539,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -10068,7 +11557,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -10086,7 +11575,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test: openssl_dep_error
 
@@ -10104,7 +11611,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test: openssl_dep_error
 
@@ -10122,7 +11629,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test: openssl_dep_error
 
@@ -10140,7 +11647,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test: openssl_dep_error
 
@@ -10158,7 +11665,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test: openssl_dep_error
 
@@ -10176,7 +11683,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test: openssl_dep_error
 
@@ -10194,7 +11701,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -10212,7 +11719,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test: openssl_dep_error
 
@@ -10230,7 +11737,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test: openssl_dep_error
 
@@ -10248,7 +11755,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -10266,7 +11773,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test: openssl_dep_error
 
@@ -10284,7 +11791,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test: openssl_dep_error
 
@@ -10302,7 +11809,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -10320,7 +11827,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test: openssl_dep_error
 
@@ -10338,7 +11845,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test: openssl_dep_error
 
@@ -10356,7 +11863,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -10374,7 +11881,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -10392,7 +11899,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test: openssl_dep_error
 
@@ -10410,7 +11917,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test: openssl_dep_error
 
@@ -10428,7 +11935,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test: openssl_dep_error
 
@@ -10446,7 +11953,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test: openssl_dep_error
 
@@ -10464,7 +11971,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test: openssl_dep_error
 
@@ -10482,7 +11989,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test: openssl_dep_error
 
@@ -10500,7 +12007,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test: openssl_dep_error
 
@@ -10518,7 +12025,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test: openssl_dep_error
 
@@ -10536,7 +12043,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -10554,7 +12061,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -10572,7 +12079,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test: openssl_dep_error
 
@@ -10590,7 +12097,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -10608,7 +12115,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -10626,7 +12133,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_fullstack_with_poll_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test: openssl_dep_error
 
@@ -10644,7 +12169,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test: openssl_dep_error
 
@@ -10662,7 +12187,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test: openssl_dep_error
 
@@ -10680,7 +12205,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test: openssl_dep_error
 
@@ -10698,7 +12223,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test: openssl_dep_error
 
@@ -10716,7 +12241,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test: openssl_dep_error
 
@@ -10734,7 +12259,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -10752,7 +12277,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test: openssl_dep_error
 
@@ -10770,7 +12295,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test: openssl_dep_error
 
@@ -10788,7 +12313,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -10806,7 +12331,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test: openssl_dep_error
 
@@ -10824,7 +12349,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test: openssl_dep_error
 
@@ -10842,7 +12367,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -10860,7 +12385,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test: openssl_dep_error
 
@@ -10878,7 +12403,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test: openssl_dep_error
 
@@ -10896,7 +12421,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -10914,7 +12439,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -10932,7 +12457,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test: openssl_dep_error
 
@@ -10950,7 +12475,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test: openssl_dep_error
 
@@ -10968,7 +12493,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test: openssl_dep_error
 
@@ -10986,7 +12511,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test: openssl_dep_error
 
@@ -11004,7 +12529,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test: openssl_dep_error
 
@@ -11022,7 +12547,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test: openssl_dep_error
 
@@ -11040,7 +12565,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test: openssl_dep_error
 
@@ -11058,7 +12583,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test: openssl_dep_error
 
@@ -11076,7 +12601,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -11094,7 +12619,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -11112,7 +12637,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test: openssl_dep_error
 
@@ -11130,7 +12655,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -11148,7 +12673,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -11166,7 +12691,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test: openssl_dep_error
 
@@ -11184,7 +12727,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test: openssl_dep_error
 
@@ -11202,7 +12745,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test: openssl_dep_error
 
@@ -11220,7 +12763,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test: openssl_dep_error
 
@@ -11238,7 +12781,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test: openssl_dep_error
 
@@ -11256,7 +12799,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test: openssl_dep_error
 
@@ -11274,7 +12817,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -11292,7 +12835,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test: openssl_dep_error
 
@@ -11310,7 +12853,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test: openssl_dep_error
 
@@ -11328,7 +12871,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -11346,7 +12889,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test: openssl_dep_error
 
@@ -11364,7 +12907,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test: openssl_dep_error
 
@@ -11382,7 +12925,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -11400,7 +12943,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test: openssl_dep_error
 
@@ -11418,7 +12961,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test: openssl_dep_error
 
@@ -11436,7 +12979,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -11454,7 +12997,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -11472,7 +13015,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test: openssl_dep_error
 
@@ -11490,7 +13033,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test: openssl_dep_error
 
@@ -11508,7 +13051,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test: openssl_dep_error
 
@@ -11526,7 +13069,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test: openssl_dep_error
 
@@ -11544,7 +13087,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test: openssl_dep_error
 
@@ -11562,7 +13105,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test: openssl_dep_error
 
@@ -11580,7 +13123,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test: openssl_dep_error
 
@@ -11598,7 +13141,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test: openssl_dep_error
 
@@ -11616,7 +13159,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -11634,7 +13177,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -11652,7 +13195,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test: openssl_dep_error
 
@@ -11670,7 +13213,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -11688,7 +13231,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -11706,7 +13249,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test: openssl_dep_error
 
@@ -11724,7 +13285,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test: openssl_dep_error
 
@@ -11742,7 +13303,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test: openssl_dep_error
 
@@ -11760,7 +13321,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test: openssl_dep_error
 
@@ -11778,7 +13339,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test: openssl_dep_error
 
@@ -11796,7 +13357,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test: openssl_dep_error
 
@@ -11814,7 +13375,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -11832,7 +13393,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test: openssl_dep_error
 
@@ -11850,7 +13411,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test: openssl_dep_error
 
@@ -11868,7 +13429,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -11886,7 +13447,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test: openssl_dep_error
 
@@ -11904,7 +13465,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test: openssl_dep_error
 
@@ -11922,7 +13483,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -11940,7 +13501,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test: openssl_dep_error
 
@@ -11958,7 +13519,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test: openssl_dep_error
 
@@ -11976,7 +13537,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -11994,7 +13555,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -12012,7 +13573,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test: openssl_dep_error
 
@@ -12030,7 +13591,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test: openssl_dep_error
 
@@ -12048,7 +13609,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test: openssl_dep_error
 
@@ -12066,7 +13627,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test: openssl_dep_error
 
@@ -12084,7 +13645,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test: openssl_dep_error
 
@@ -12102,7 +13663,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test: openssl_dep_error
 
@@ -12120,7 +13681,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test: openssl_dep_error
 
@@ -12138,7 +13699,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test: openssl_dep_error
 
@@ -12156,7 +13717,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -12174,7 +13735,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -12192,7 +13753,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test: openssl_dep_error
 
@@ -12210,7 +13771,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -12228,7 +13789,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -12246,7 +13807,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test: openssl_dep_error
 
@@ -12264,7 +13843,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test: openssl_dep_error
 
@@ -12282,7 +13861,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test: openssl_dep_error
 
@@ -12300,7 +13879,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test: openssl_dep_error
 
@@ -12318,7 +13897,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test: openssl_dep_error
 
@@ -12336,7 +13915,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test: openssl_dep_error
 
@@ -12354,7 +13933,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -12372,7 +13951,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test: openssl_dep_error
 
@@ -12390,7 +13969,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test: openssl_dep_error
 
@@ -12408,7 +13987,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -12426,7 +14005,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test: openssl_dep_error
 
@@ -12444,7 +14023,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test: openssl_dep_error
 
@@ -12462,7 +14041,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -12480,7 +14059,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test: openssl_dep_error
 
@@ -12498,7 +14077,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test: openssl_dep_error
 
@@ -12516,7 +14095,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -12534,7 +14113,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -12552,7 +14131,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test: openssl_dep_error
 
@@ -12570,7 +14149,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test: openssl_dep_error
 
@@ -12588,7 +14167,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test: openssl_dep_error
 
@@ -12606,7 +14185,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test: openssl_dep_error
 
@@ -12624,7 +14203,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test: openssl_dep_error
 
@@ -12642,7 +14221,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test: openssl_dep_error
 
@@ -12660,7 +14239,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test: openssl_dep_error
 
@@ -12678,7 +14257,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test: openssl_dep_error
 
@@ -12696,7 +14275,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -12714,7 +14293,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -12732,7 +14311,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test: openssl_dep_error
 
@@ -12750,7 +14329,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -12768,7 +14347,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -12786,7 +14365,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_socket_pair_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test: openssl_dep_error
 
@@ -12804,7 +14401,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test: openssl_dep_error
 
@@ -12822,7 +14419,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test: openssl_dep_error
 
@@ -12840,7 +14437,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test: openssl_dep_error
 
@@ -12858,7 +14455,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test: openssl_dep_error
 
@@ -12876,7 +14473,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test: openssl_dep_error
 
@@ -12894,7 +14491,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -12912,7 +14509,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test: openssl_dep_error
 
@@ -12930,7 +14527,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test: openssl_dep_error
 
@@ -12948,7 +14545,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -12966,7 +14563,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test: openssl_dep_error
 
@@ -12984,7 +14581,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test: openssl_dep_error
 
@@ -13002,7 +14599,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -13020,7 +14617,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test: openssl_dep_error
 
@@ -13038,7 +14635,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test: openssl_dep_error
 
@@ -13056,7 +14653,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -13074,7 +14671,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -13092,7 +14689,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test: openssl_dep_error
 
@@ -13110,7 +14707,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test: openssl_dep_error
 
@@ -13128,7 +14725,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test: openssl_dep_error
 
@@ -13146,7 +14743,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test: openssl_dep_error
 
@@ -13164,7 +14761,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test: openssl_dep_error
 
@@ -13182,7 +14779,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test: openssl_dep_error
 
@@ -13200,7 +14797,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test: openssl_dep_error
 
@@ -13218,7 +14815,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test: openssl_dep_error
 
@@ -13236,7 +14833,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -13254,7 +14851,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -13272,7 +14869,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test: openssl_dep_error
 
@@ -13290,7 +14887,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -13308,7 +14905,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -13326,7 +14923,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test: openssl_dep_error
 
@@ -13344,7 +14959,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test: openssl_dep_error
 
@@ -13362,7 +14977,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test: openssl_dep_error
 
@@ -13380,7 +14995,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test: openssl_dep_error
 
@@ -13398,7 +15013,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test: openssl_dep_error
 
@@ -13416,7 +15031,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test: openssl_dep_error
 
@@ -13434,7 +15049,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -13452,7 +15067,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test: openssl_dep_error
 
@@ -13470,7 +15085,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test: openssl_dep_error
 
@@ -13488,7 +15103,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test: openssl_dep_error
 
@@ -13506,7 +15121,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test: openssl_dep_error
 
@@ -13524,7 +15139,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test: openssl_dep_error
 
@@ -13542,7 +15157,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test: openssl_dep_error
 
@@ -13560,7 +15175,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test: openssl_dep_error
 
@@ -13578,7 +15193,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_test: openssl_dep_error
 
@@ -13596,7 +15211,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test: openssl_dep_error
 
@@ -13614,7 +15229,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test: openssl_dep_error
 
@@ -13632,7 +15247,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test: openssl_dep_error
 
@@ -13650,7 +15265,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test: openssl_dep_error
 
@@ -13668,7 +15283,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test: openssl_dep_error
 
@@ -13686,7 +15301,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test: openssl_dep_error
 
@@ -13704,7 +15319,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test: openssl_dep_error
 
@@ -13722,7 +15337,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test: openssl_dep_error
 
@@ -13740,7 +15355,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test: openssl_dep_error
 
@@ -13758,7 +15373,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test: openssl_dep_error
 
@@ -13776,7 +15391,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test: openssl_dep_error
 
@@ -13794,7 +15409,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test: openssl_dep_error
 
@@ -13812,7 +15427,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test: openssl_dep_error
 
@@ -13830,7 +15445,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test: openssl_dep_error
 
@@ -13848,7 +15463,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test: openssl_dep_error
 
@@ -13866,7 +15481,25 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(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)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test
+
+endif
+
+
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test: openssl_dep_error
 
@@ -13884,7 +15517,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test: openssl_dep_error
 
@@ -13902,7 +15535,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test: openssl_dep_error
 
@@ -13920,7 +15553,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test: openssl_dep_error
 
@@ -13938,7 +15571,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test: openssl_dep_error
 
@@ -13956,7 +15589,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test: openssl_dep_error
 
@@ -13974,7 +15607,7 @@
 
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test: openssl_dep_error
 
@@ -14166,6 +15799,14 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test
+
+
+
+
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -14222,6 +15863,246 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(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:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_message_length.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_message_length.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_registered_call.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_registered_call.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(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:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(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:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(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:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_server_finishes_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_server_finishes_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test
+
+
+
+
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_with_high_initial_sequence_number.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_compression.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_with_high_initial_sequence_number.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test
+
+
+
+
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -14398,6 +16279,14 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test
+
+
+
+
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds_posix.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -14630,6 +16519,14 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test
+
+
+
+
 $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_with_poll.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -14862,6 +16759,14 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test
+
+
+
+
 $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -15094,6 +16999,14 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(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:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -15326,6 +17239,14 @@
 
 
 
+$(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(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:  $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_with_grpc_trace.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_flags.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
@@ -15436,6 +17357,7 @@
 src/core/security/credentials_win32.c: $(OPENSSL_DEP)
 src/core/security/google_default_credentials.c: $(OPENSSL_DEP)
 src/core/security/json_token.c: $(OPENSSL_DEP)
+src/core/security/jwt_verifier.c: $(OPENSSL_DEP)
 src/core/security/secure_endpoint.c: $(OPENSSL_DEP)
 src/core/security/secure_transport_setup.c: $(OPENSSL_DEP)
 src/core/security/security_connector.c: $(OPENSSL_DEP)
diff --git a/README.md b/README.md
index f71ee6a..36d9fa0 100644
--- a/README.md
+++ b/README.md
@@ -39,9 +39,9 @@
    * Ruby Library: [src/ruby] (src/ruby) : Early adopter ready - Alpha.
    * NodeJS Library: [src/node] (src/node) : Early adopter ready - Alpha.
    * Python Library: [src/python] (src/python) : Early adopter ready - Alpha.
-   * C# Library: [src/csharp] (src/csharp) : Early adopter ready - Alpha.   
+   * C# Library: [src/csharp] (src/csharp) : Early adopter ready - Alpha.
+   * Objective-C Library: [src/objective-c] (src/objective-c): Early adopter ready - Alpha.
    * PHP Library: [src/php] (src/php) : Pre-Alpha.
-   * Objective-C Library: [src/objective-c] (src/objective-c): Pre-Alpha.
 
 #Overview
 
diff --git a/build.json b/build.json
index d932543..2755703 100644
--- a/build.json
+++ b/build.json
@@ -30,21 +30,27 @@
       "public_headers": [
         "include/grpc++/async_generic_service.h",
         "include/grpc++/async_unary_call.h",
+        "include/grpc++/auth_context.h",
+        "include/grpc++/auth_property_iterator.h",
         "include/grpc++/byte_buffer.h",
         "include/grpc++/channel_arguments.h",
         "include/grpc++/channel_interface.h",
         "include/grpc++/client_context.h",
         "include/grpc++/completion_queue.h",
         "include/grpc++/config.h",
+        "include/grpc++/config_protobuf.h",
         "include/grpc++/create_channel.h",
         "include/grpc++/credentials.h",
+        "include/grpc++/fixed_size_thread_pool.h",
         "include/grpc++/generic_stub.h",
         "include/grpc++/impl/call.h",
         "include/grpc++/impl/client_unary_call.h",
         "include/grpc++/impl/grpc_library.h",
         "include/grpc++/impl/internal_stub.h",
+        "include/grpc++/impl/proto_utils.h",
         "include/grpc++/impl/rpc_method.h",
         "include/grpc++/impl/rpc_service_method.h",
+        "include/grpc++/impl/serialization_traits.h",
         "include/grpc++/impl/service_type.h",
         "include/grpc++/impl/sync.h",
         "include/grpc++/impl/sync_cxx11.h",
@@ -65,14 +71,12 @@
       ],
       "headers": [
         "src/cpp/client/channel.h",
-        "src/cpp/proto/proto_utils.h",
-        "src/cpp/server/thread_pool.h"
+        "src/cpp/common/create_auth_context.h"
       ],
       "src": [
         "src/cpp/client/channel.cc",
         "src/cpp/client/channel_arguments.cc",
         "src/cpp/client/client_context.cc",
-        "src/cpp/client/client_unary_call.cc",
         "src/cpp/client/create_channel.cc",
         "src/cpp/client/credentials.cc",
         "src/cpp/client/generic_stub.cc",
@@ -84,12 +88,12 @@
         "src/cpp/proto/proto_utils.cc",
         "src/cpp/server/async_generic_service.cc",
         "src/cpp/server/create_default_thread_pool.cc",
+        "src/cpp/server/fixed_size_thread_pool.cc",
         "src/cpp/server/insecure_server_credentials.cc",
         "src/cpp/server/server.cc",
         "src/cpp/server/server_builder.cc",
         "src/cpp/server/server_context.cc",
         "src/cpp/server/server_credentials.cc",
-        "src/cpp/server/thread_pool.cc",
         "src/cpp/util/byte_buffer.cc",
         "src/cpp/util/slice.cc",
         "src/cpp/util/status.cc",
@@ -110,14 +114,25 @@
         "src/core/channel/census_filter.h",
         "src/core/channel/channel_args.h",
         "src/core/channel/channel_stack.h",
-        "src/core/channel/child_channel.h",
         "src/core/channel/client_channel.h",
-        "src/core/channel/client_setup.h",
+        "src/core/channel/compress_filter.h",
         "src/core/channel/connected_channel.h",
         "src/core/channel/context.h",
         "src/core/channel/http_client_filter.h",
         "src/core/channel/http_server_filter.h",
         "src/core/channel/noop_filter.h",
+        "src/core/client_config/client_config.h",
+        "src/core/client_config/connector.h",
+        "src/core/client_config/lb_policies/pick_first.h",
+        "src/core/client_config/lb_policy.h",
+        "src/core/client_config/resolver.h",
+        "src/core/client_config/resolver_factory.h",
+        "src/core/client_config/resolver_registry.h",
+        "src/core/client_config/resolvers/dns_resolver.h",
+        "src/core/client_config/resolvers/unix_resolver_posix.h",
+        "src/core/client_config/subchannel.h",
+        "src/core/client_config/subchannel_factory.h",
+        "src/core/client_config/uri_parser.h",
         "src/core/compression/message_compress.h",
         "src/core/debug/trace.h",
         "src/core/iomgr/alarm.h",
@@ -131,10 +146,11 @@
         "src/core/iomgr/iomgr_internal.h",
         "src/core/iomgr/iomgr_posix.h",
         "src/core/iomgr/pollset.h",
-        "src/core/iomgr/pollset_kick.h",
         "src/core/iomgr/pollset_kick_posix.h",
-        "src/core/iomgr/pollset_kick_windows.h",
         "src/core/iomgr/pollset_posix.h",
+        "src/core/iomgr/pollset_set.h",
+        "src/core/iomgr/pollset_set_posix.h",
+        "src/core/iomgr/pollset_set_windows.h",
         "src/core/iomgr/pollset_windows.h",
         "src/core/iomgr/resolve_address.h",
         "src/core/iomgr/sockaddr.h",
@@ -159,7 +175,6 @@
         "src/core/surface/byte_buffer_queue.h",
         "src/core/surface/call.h",
         "src/core/surface/channel.h",
-        "src/core/surface/client.h",
         "src/core/surface/completion_queue.h",
         "src/core/surface/event_string.h",
         "src/core/surface/init.h",
@@ -178,12 +193,15 @@
         "src/core/transport/chttp2/hpack_table.h",
         "src/core/transport/chttp2/http2_errors.h",
         "src/core/transport/chttp2/huffsyms.h",
+        "src/core/transport/chttp2/incoming_metadata.h",
+        "src/core/transport/chttp2/internal.h",
         "src/core/transport/chttp2/status_conversion.h",
         "src/core/transport/chttp2/stream_encoder.h",
         "src/core/transport/chttp2/stream_map.h",
         "src/core/transport/chttp2/timeout_encoding.h",
         "src/core/transport/chttp2/varint.h",
         "src/core/transport/chttp2_transport.h",
+        "src/core/transport/connectivity_state.h",
         "src/core/transport/metadata.h",
         "src/core/transport/stream_op.h",
         "src/core/transport/transport.h",
@@ -193,13 +211,24 @@
         "src/core/census/grpc_context.c",
         "src/core/channel/channel_args.c",
         "src/core/channel/channel_stack.c",
-        "src/core/channel/child_channel.c",
         "src/core/channel/client_channel.c",
-        "src/core/channel/client_setup.c",
+        "src/core/channel/compress_filter.c",
         "src/core/channel/connected_channel.c",
         "src/core/channel/http_client_filter.c",
         "src/core/channel/http_server_filter.c",
         "src/core/channel/noop_filter.c",
+        "src/core/client_config/client_config.c",
+        "src/core/client_config/connector.c",
+        "src/core/client_config/lb_policies/pick_first.c",
+        "src/core/client_config/lb_policy.c",
+        "src/core/client_config/resolver.c",
+        "src/core/client_config/resolver_factory.c",
+        "src/core/client_config/resolver_registry.c",
+        "src/core/client_config/resolvers/dns_resolver.c",
+        "src/core/client_config/resolvers/unix_resolver_posix.c",
+        "src/core/client_config/subchannel.c",
+        "src/core/client_config/subchannel_factory.c",
+        "src/core/client_config/uri_parser.c",
         "src/core/compression/algorithm.c",
         "src/core/compression/message_compress.c",
         "src/core/debug/trace.c",
@@ -213,10 +242,12 @@
         "src/core/iomgr/iomgr.c",
         "src/core/iomgr/iomgr_posix.c",
         "src/core/iomgr/iomgr_windows.c",
-        "src/core/iomgr/pollset_kick.c",
+        "src/core/iomgr/pollset_kick_posix.c",
         "src/core/iomgr/pollset_multipoller_with_epoll.c",
         "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
         "src/core/iomgr/pollset_posix.c",
+        "src/core/iomgr/pollset_set_posix.c",
+        "src/core/iomgr/pollset_set_windows.c",
         "src/core/iomgr/pollset_windows.c",
         "src/core/iomgr/resolve_address_posix.c",
         "src/core/iomgr/resolve_address_windows.c",
@@ -250,7 +281,6 @@
         "src/core/surface/call_log_batch.c",
         "src/core/surface/channel.c",
         "src/core/surface/channel_create.c",
-        "src/core/surface/client.c",
         "src/core/surface/completion_queue.c",
         "src/core/surface/event_string.c",
         "src/core/surface/init.c",
@@ -260,6 +290,7 @@
         "src/core/surface/server_chttp2.c",
         "src/core/surface/server_create.c",
         "src/core/surface/surface_trace.c",
+        "src/core/surface/version.c",
         "src/core/transport/chttp2/alpn.c",
         "src/core/transport/chttp2/bin_encoder.c",
         "src/core/transport/chttp2/frame_data.c",
@@ -271,12 +302,17 @@
         "src/core/transport/chttp2/hpack_parser.c",
         "src/core/transport/chttp2/hpack_table.c",
         "src/core/transport/chttp2/huffsyms.c",
+        "src/core/transport/chttp2/incoming_metadata.c",
+        "src/core/transport/chttp2/parsing.c",
         "src/core/transport/chttp2/status_conversion.c",
         "src/core/transport/chttp2/stream_encoder.c",
+        "src/core/transport/chttp2/stream_lists.c",
         "src/core/transport/chttp2/stream_map.c",
         "src/core/transport/chttp2/timeout_encoding.c",
         "src/core/transport/chttp2/varint.c",
+        "src/core/transport/chttp2/writing.c",
         "src/core/transport/chttp2_transport.c",
+        "src/core/transport/connectivity_state.c",
         "src/core/transport/metadata.c",
         "src/core/transport/stream_op.c",
         "src/core/transport/transport.c",
@@ -285,9 +321,19 @@
     },
     {
       "name": "grpc_test_util_base",
+      "headers": [
+        "test/core/end2end/cq_verifier.h",
+        "test/core/iomgr/endpoint_tests.h",
+        "test/core/security/oauth2_utils.h",
+        "test/core/util/grpc_profiler.h",
+        "test/core/util/parse_hexstring.h",
+        "test/core/util/port.h",
+        "test/core/util/slice_splitter.h"
+      ],
       "src": [
         "test/core/end2end/cq_verifier.c",
         "test/core/iomgr/endpoint_tests.c",
+        "test/core/security/oauth2_utils.c",
         "test/core/util/grpc_profiler.c",
         "test/core/util/parse_hexstring.c",
         "test/core/util/port_posix.c",
@@ -335,6 +381,7 @@
         "src/core/support/env.h",
         "src/core/support/file.h",
         "src/core/support/murmur_hash.h",
+        "src/core/support/stack_lockfree.h",
         "src/core/support/string.h",
         "src/core/support/string_win32.h",
         "src/core/support/thd_internal.h"
@@ -363,6 +410,7 @@
         "src/core/support/murmur_hash.c",
         "src/core/support/slice.c",
         "src/core/support/slice_buffer.c",
+        "src/core/support/stack_lockfree.c",
         "src/core/support/string.c",
         "src/core/support/string_posix.c",
         "src/core/support/string_win32.c",
@@ -413,6 +461,7 @@
         "src/core/security/base64.h",
         "src/core/security/credentials.h",
         "src/core/security/json_token.h",
+        "src/core/security/jwt_verifier.h",
         "src/core/security/secure_endpoint.h",
         "src/core/security/secure_transport_setup.h",
         "src/core/security/security_connector.h",
@@ -435,6 +484,7 @@
         "src/core/security/credentials_win32.c",
         "src/core/security/google_default_credentials.c",
         "src/core/security/json_token.c",
+        "src/core/security/jwt_verifier.c",
         "src/core/security/secure_endpoint.c",
         "src/core/security/secure_transport_setup.c",
         "src/core/security/security_connector.c",
@@ -462,6 +512,9 @@
       "name": "grpc_test_util",
       "build": "private",
       "language": "c",
+      "headers": [
+        "test/core/end2end/data/ssl_test_data.h"
+      ],
       "src": [
         "test/core/end2end/data/server1_cert.c",
         "test/core/end2end/data/server1_key.c",
@@ -516,10 +569,15 @@
       "language": "c++",
       "headers": [
         "src/cpp/client/secure_credentials.h",
+        "src/cpp/common/secure_auth_context.h",
         "src/cpp/server/secure_server_credentials.h"
       ],
       "src": [
+        "src/cpp/client/secure_channel_arguments.cc",
         "src/cpp/client/secure_credentials.cc",
+        "src/cpp/common/auth_property_iterator.cc",
+        "src/cpp/common/secure_auth_context.cc",
+        "src/cpp/common/secure_create_auth_context.cc",
         "src/cpp/server/secure_server_credentials.cc"
       ],
       "deps": [
@@ -534,19 +592,12 @@
       "vs_project_guid": "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}"
     },
     {
-      "name": "grpc++_benchmark_config",
-      "build": "private",
-      "language": "c++",
-      "src": [
-        "test/cpp/qps/qpstest.proto",
-        "test/cpp/qps/report.cc",
-        "test/cpp/util/benchmark_config.cc"
-      ]
-    },
-    {
       "name": "grpc++_test_config",
       "build": "private",
       "language": "c++",
+      "headers": [
+        "test/cpp/util/test_config.h"
+      ],
       "src": [
         "test/cpp/util/test_config.cc"
       ]
@@ -555,6 +606,12 @@
       "name": "grpc++_test_util",
       "build": "private",
       "language": "c++",
+      "headers": [
+        "test/cpp/util/cli_call.h",
+        "test/cpp/util/create_test_channel.h",
+        "test/cpp/util/fake_credentials.h",
+        "test/cpp/util/subprocess.h"
+      ],
       "src": [
         "test/cpp/util/messages.proto",
         "test/cpp/util/echo.proto",
@@ -563,12 +620,19 @@
         "test/cpp/util/create_test_channel.cc",
         "test/cpp/util/fake_credentials.cc",
         "test/cpp/util/subprocess.cc"
+      ],
+      "deps": [
+        "grpc++",
+        "grpc_test_util"
       ]
     },
     {
       "name": "grpc++_unsecure",
       "build": "all",
       "language": "c++",
+      "src": [
+        "src/cpp/common/insecure_create_auth_context.cc"
+      ],
       "deps": [
         "gpr",
         "grpc_unsecure"
@@ -585,6 +649,8 @@
       "build": "protoc",
       "language": "c++",
       "headers": [
+        "include/grpc++/config.h",
+        "include/grpc++/config_protobuf.h",
         "src/compiler/config.h",
         "src/compiler/cpp_generator.h",
         "src/compiler/cpp_generator_helpers.h",
@@ -614,6 +680,9 @@
       "name": "interop_client_helper",
       "build": "private",
       "language": "c++",
+      "headers": [
+        "test/cpp/interop/client_helper.h"
+      ],
       "src": [
         "test/cpp/interop/client_helper.cc"
       ],
@@ -629,6 +698,9 @@
       "name": "interop_client_main",
       "build": "private",
       "language": "c++",
+      "headers": [
+        "test/cpp/interop/interop_client.h"
+      ],
       "src": [
         "test/proto/empty.proto",
         "test/proto/messages.proto",
@@ -637,6 +709,7 @@
         "test/cpp/interop/interop_client.cc"
       ],
       "deps": [
+        "interop_client_helper",
         "grpc++_test_util",
         "grpc_test_util",
         "grpc++",
@@ -650,6 +723,9 @@
       "name": "interop_server_helper",
       "build": "private",
       "language": "c++",
+      "headers": [
+        "test/cpp/interop/server_helper.h"
+      ],
       "src": [
         "test/cpp/interop/server_helper.cc"
       ],
@@ -671,6 +747,7 @@
         "test/cpp/interop/server.cc"
       ],
       "deps": [
+        "interop_server_helper",
         "grpc++_test_util",
         "grpc_test_util",
         "grpc++",
@@ -684,6 +761,10 @@
       "name": "pubsub_client_lib",
       "build": "do_not_build",
       "language": "c++",
+      "headers": [
+        "examples/pubsub/publisher.h",
+        "examples/pubsub/subscriber.h"
+      ],
       "src": [
         "examples/pubsub/label.proto",
         "examples/pubsub/empty.proto",
@@ -702,25 +783,36 @@
       "build": "private",
       "language": "c++",
       "headers": [
+        "test/cpp/qps/client.h",
         "test/cpp/qps/driver.h",
+        "test/cpp/qps/histogram.h",
         "test/cpp/qps/interarrival.h",
+        "test/cpp/qps/perf_db_client.h",
         "test/cpp/qps/qps_worker.h",
         "test/cpp/qps/report.h",
-        "test/cpp/qps/timer.h"
+        "test/cpp/qps/server.h",
+        "test/cpp/qps/stats.h",
+        "test/cpp/qps/timer.h",
+        "test/cpp/util/benchmark_config.h"
       ],
       "src": [
         "test/cpp/qps/qpstest.proto",
+        "test/cpp/qps/perf_db.proto",
         "test/cpp/qps/client_async.cc",
         "test/cpp/qps/client_sync.cc",
         "test/cpp/qps/driver.cc",
+        "test/cpp/qps/perf_db_client.cc",
         "test/cpp/qps/qps_worker.cc",
+        "test/cpp/qps/report.cc",
         "test/cpp/qps/server_async.cc",
         "test/cpp/qps/server_sync.cc",
-        "test/cpp/qps/timer.cc"
+        "test/cpp/qps/timer.cc",
+        "test/cpp/util/benchmark_config.cc"
       ],
       "deps": [
         "grpc_test_util",
-        "grpc++_test_util"
+        "grpc++_test_util",
+        "grpc++"
       ]
     },
     {
@@ -868,6 +960,23 @@
       ]
     },
     {
+      "name": "fd_conservation_posix_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/iomgr/fd_conservation_posix_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ],
+      "platforms": [
+        "posix"
+      ]
+    },
+    {
       "name": "fd_posix_test",
       "build": "test",
       "language": "c",
@@ -953,10 +1062,9 @@
       "build": "tool",
       "language": "c",
       "src": [
-        "src/core/transport/chttp2/gen_hpack_tables.c"
+        "tools/codegen/core/gen_hpack_tables.c"
       ],
       "deps": [
-        "grpc_test_util",
         "gpr",
         "grpc"
       ]
@@ -1070,6 +1178,18 @@
       ]
     },
     {
+      "name": "gpr_stack_lockfree_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/support/stack_lockfree_test.c"
+      ],
+      "deps": [
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "gpr_string_test",
       "build": "test",
       "language": "c",
@@ -1268,6 +1388,20 @@
       ]
     },
     {
+      "name": "grpc_jwt_verifier_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/security/jwt_verifier_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "grpc_print_google_default_creds_token",
       "build": "tool",
       "language": "c",
@@ -1282,6 +1416,20 @@
       ]
     },
     {
+      "name": "grpc_security_connector_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/security/security_connector_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "grpc_stream_op_test",
       "build": "test",
       "language": "c",
@@ -1296,6 +1444,20 @@
       ]
     },
     {
+      "name": "grpc_verify_jwt",
+      "build": "tool",
+      "language": "c",
+      "src": [
+        "test/core/security/verify_jwt.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "hpack_parser_test",
       "build": "test",
       "language": "c",
@@ -1466,6 +1628,20 @@
       ]
     },
     {
+      "name": "multiple_server_queues_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/end2end/multiple_server_queues_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "murmur_hash_test",
       "build": "test",
       "language": "c",
@@ -1616,20 +1792,6 @@
       ]
     },
     {
-      "name": "time_test",
-      "build": "test",
-      "language": "c",
-      "src": [
-        "test/core/support/time_test.c"
-      ],
-      "deps": [
-        "grpc_test_util",
-        "grpc",
-        "gpr_test_util",
-        "gpr"
-      ]
-    },
-    {
       "name": "timeout_encoding_test",
       "build": "test",
       "language": "c",
@@ -1686,6 +1848,20 @@
       ]
     },
     {
+      "name": "uri_parser_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/client_config/uri_parser_test.c"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "async_end2end_test",
       "build": "test",
       "language": "c++",
@@ -1711,7 +1887,6 @@
       "deps": [
         "qps",
         "grpc++_test_util",
-        "grpc++_benchmark_config",
         "grpc_test_util",
         "grpc++",
         "grpc",
@@ -1729,7 +1904,6 @@
       "deps": [
         "qps",
         "grpc++_test_util",
-        "grpc++_benchmark_config",
         "grpc_test_util",
         "grpc++",
         "grpc",
@@ -1738,6 +1912,19 @@
       ]
     },
     {
+      "name": "auth_property_iterator_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/common/auth_property_iterator_test.cc"
+      ],
+      "deps": [
+        "grpc++",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
       "name": "channel_arguments_test",
       "build": "test",
       "language": "c++",
@@ -1813,6 +2000,36 @@
       ]
     },
     {
+      "name": "cxx_byte_buffer_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/util/byte_buffer_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
+      "name": "cxx_slice_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/util/slice_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "cxx_time_test",
       "build": "test",
       "language": "c++",
@@ -1844,6 +2061,21 @@
       ]
     },
     {
+      "name": "fixed_size_thread_pool_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/server/fixed_size_thread_pool_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "generic_end2end_test",
       "build": "test",
       "language": "c++",
@@ -2075,8 +2307,7 @@
         "grpc",
         "gpr_test_util",
         "gpr",
-        "grpc++_test_config",
-        "grpc++_benchmark_config"
+        "grpc++_test_config"
       ]
     },
     {
@@ -2098,16 +2329,15 @@
       ]
     },
     {
-      "name": "qps_test",
+      "name": "qps_openloop_test",
       "build": "test",
       "language": "c++",
       "src": [
-        "test/cpp/qps/qps_test.cc"
+        "test/cpp/qps/qps_openloop_test.cc"
       ],
       "deps": [
         "qps",
         "grpc++_test_util",
-        "grpc++_benchmark_config",
         "grpc_test_util",
         "grpc++",
         "grpc",
@@ -2117,16 +2347,15 @@
       ]
     },
     {
-      "name": "qps_test_openloop",
+      "name": "qps_test",
       "build": "test",
       "language": "c++",
       "src": [
-        "test/cpp/qps/qps_test_openloop.cc"
+        "test/cpp/qps/qps_test.cc"
       ],
       "deps": [
         "qps",
         "grpc++_test_util",
-        "grpc++_benchmark_config",
         "grpc_test_util",
         "grpc++",
         "grpc",
@@ -2158,6 +2387,19 @@
       ]
     },
     {
+      "name": "secure_auth_context_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/common/secure_auth_context_test.cc"
+      ],
+      "deps": [
+        "grpc++",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
       "name": "server_crash_test",
       "build": "test",
       "language": "c++",
@@ -2215,7 +2457,6 @@
       "deps": [
         "qps",
         "grpc++_test_util",
-        "grpc++_benchmark_config",
         "grpc_test_util",
         "grpc++",
         "grpc",
@@ -2233,22 +2474,6 @@
       "deps": [
         "qps",
         "grpc++_test_util",
-        "grpc++_benchmark_config",
-        "grpc_test_util",
-        "grpc++",
-        "grpc",
-        "gpr_test_util",
-        "gpr"
-      ]
-    },
-    {
-      "name": "thread_pool_test",
-      "build": "test",
-      "language": "c++",
-      "src": [
-        "test/cpp/server/thread_pool_test.cc"
-      ],
-      "deps": [
         "grpc_test_util",
         "grpc++",
         "grpc",
diff --git a/doc/connection-backoff.md b/doc/connection-backoff.md
index 47b71f9..7094e73 100644
--- a/doc/connection-backoff.md
+++ b/doc/connection-backoff.md
@@ -8,58 +8,39 @@
 We have several parameters:
  1. INITIAL_BACKOFF (how long to wait after the first failure before retrying)
  2. MULTIPLIER (factor with which to multiply backoff after a failed retry)
- 3. MAX_BACKOFF (Upper bound on backoff)
- 4. MIN_CONNECTION_TIMEOUT
+ 3. MAX_BACKOFF (upper bound on backoff)
+ 4. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to
+    complete)
 
 ## Proposed Backoff Algorithm
 
 Exponentially back off the start time of connection attempts up to a limit of
-MAX_BACKOFF.
+MAX_BACKOFF, with jitter.
 
 ```
 ConnectWithBackoff()
   current_backoff = INITIAL_BACKOFF
   current_deadline = now() + INITIAL_BACKOFF
-  while (TryConnect(Max(current_deadline, MIN_CONNECT_TIMEOUT))
+  while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))
          != SUCCESS)
     SleepUntil(current_deadline)
     current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
-    current_deadline = now() + current_backoff
-```
-
-## Historical Algorithm in Stubby
-
-Exponentially increase up to a limit of MAX_BACKOFF the intervals between
-connection attempts. This is what stubby 2 uses, and is equivalent if
-TryConnect() fails instantly.
+    current_deadline = now() + current_backoff +
+      UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
 
 ```
-LegacyConnectWithBackoff()
-  current_backoff = INITIAL_BACKOFF
-  while (TryConnect(MIN_CONNECT_TIMEOUT) != SUCCESS)
-    SleepFor(current_backoff)
-    current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
-```
 
-The grpc C implementation currently uses this approach with an initial backoff
-of 1 second, multiplier of 2, and maximum backoff of 120 seconds. (This will
-change)
+With specific parameters of
+MIN_CONNECT_TIMEOUT = 20 seconds
+INITIAL_BACKOFF = 1 second
+MULTIPLIER = 1.6
+MAX_BACKOFF = 120 seconds
+JITTER = 0.2
 
-Stubby, or at least rpc2, uses exactly this algorithm with an initial backoff
-of 1 second, multiplier of 1.2, and a maximum backoff of 120 seconds.
+Implementations with pressing concerns (such as minimizing the number of wakeups
+on a mobile phone) may wish to use a different algorithm, and in particular
+different jitter logic.
 
-## Use Cases to Consider
-
-* Client tries to connect to a server which is down for multiple hours, eg for
-  maintenance
-* Client tries to connect to a server which is overloaded
-* User is bringing up both a client and a server at the same time
-    * In particular, we would like to avoid a large unnecessary delay if the
-      client connects to a server which is about to come up
-* Client/server are misconfigured such that connection attempts always fail
-    * We want to make sure these don’t put too much load on the server by
-      default.
-* Server is overloaded and wants to transiently make clients back off
-* Application has out of band reason to believe a server is back
-    * We should consider an out of band mechanism for the client to hint that
-      we should short circuit the backoff.
+Alternate implementations must ensure that connection backoffs started at the
+same time disperse, and must not attempt connections substantially more often
+than the above algorithm.
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 41ebc6b..6115fe1 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -392,6 +392,97 @@
 * clients are free to assert that the response payload body contents are zero
   and comparing the entire response message against a golden response
 
+### oauth2_auth_token
+
+Similar to the other auth tests, this test is only for cloud-to-prod path.
+
+This test verifies unary calls succeed in sending messages using an OAuth2 token
+that is obtained out of band. For the purpose of the test, the OAuth2 token is
+actually obtained from the service account credentials via the
+language-specific authorization library.
+
+The difference between this test and the other auth tests is that rather than
+configuring the test client with ServiceAccountCredentials directly, the test
+first uses the authorization library to obtain an authorization token.
+
+The test
+- uses the flag `--service_account_key_file` with the path to a json key file
+downloaded from https://console.developers.google.com. Alternately, if using a
+usable auth implementation, it may specify the file location in the environment
+variable GOOGLE_APPLICATION_CREDENTIALS
+- uses the flag `--oauth_scope` for the oauth scope.  For testing against
+grpc-test.sandbox.google.com, "https://www.googleapis.com/auth/xapi.zoo" should
+be passed as the `--oauth_scope`.
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+* [Echo Authenticated Username][]
+* [Echo OAuth Scope][]
+
+Procedure:
+ 1. Client uses the auth library to obtain an authorization token
+ 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1.
+ 3. Client calls UnaryCall with the following message
+
+    ```
+    {
+      fill_username: true
+      fill_oauth_scope: true
+    }
+    ```
+    
+Asserts:
+* call was successful
+* received SimpleResponse.username is in the json key file used by the auth
+library to obtain the authorization token
+* received SimpleResponse.oauth_scope is in `--oauth_scope`
+
+### per_rpc_creds
+
+Similar to the other auth tests, this test is only for cloud-to-prod path.
+
+This test verifies unary calls succeed in sending messages using an OAuth2 token
+that is obtained out of band. For the purpose of the test, the OAuth2 token is
+actually obtained from the service account credentials via the
+language-specific authorization library.
+
+The test
+- uses the flag `--service_account_key_file` with the path to a json key file
+downloaded from https://console.developers.google.com. Alternately, if using a
+usable auth implementation, it may specify the file location in the environment
+variable GOOGLE_APPLICATION_CREDENTIALS
+- uses the flag `--oauth_scope` for the oauth scope.  For testing against
+grpc-test.sandbox.google.com, "https://www.googleapis.com/auth/xapi.zoo" should
+be passed as the `--oauth_scope`.
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+* [Echo Authenticated Username][]
+* [Echo OAuth Scope][]
+
+Procedure:
+ 1. Client uses the auth library to obtain an authorization token
+ 2. Client configures the channel with just SSL credentials.
+ 3. Client calls UnaryCall, setting per-call credentials to
+ AccessTokenCredentials with the access token obtained in step 1. The request is
+ the following message
+
+    ```
+    {
+      fill_username: true
+      fill_oauth_scope: true
+    }
+    ```
+    
+Asserts:
+* call was successful
+* received SimpleResponse.username is in the json key file used by the auth
+library to obtain the authorization token
+* received SimpleResponse.oauth_scope is in `--oauth_scope`
+
+
 ### custom_metadata
 
 This test verifies that custom metadata in either binary or ascii format can be
@@ -563,11 +654,6 @@
 
 Multiple thousand simultaneous calls on same Channel (ctiller)
 
-OAuth2 tokens + Service Credentials from GCE metadata server (GCE->prod only)
-(abhishek)
-
-OAuth2 tokens + JWT signing key (GCE->prod only) (abhishek)
-
 Metadata: client headers, server headers + trailers, binary+ascii
 
 #### Normal priority:
diff --git a/gRPC.podspec b/gRPC.podspec
index 5e98a09..28d9ac4 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -1,45 +1,525 @@
+# GRPC CocoaPods podspec
+# This file has been automatically generated from a template file.
+# Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
+
+# 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.
 
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  s.version  = '0.6.0'
+  s.version  = '0.7.0'
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'http://www.grpc.io'
   s.license  = 'New BSD'
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
 
   # s.source = { :git => 'https://github.com/grpc/grpc.git',
-  #              :tag => 'release-0_9_1-objectivec-0.5.1' }
+  #              :tag => 'release-0_10_0-objectivec-0.6.0' }
 
   s.ios.deployment_target = '6.0'
   s.osx.deployment_target = '10.8'
   s.requires_arc = true
 
+  objc_dir = 'src/objective-c'
+
   # Reactive Extensions library for iOS.
-  s.subspec 'RxLibrary' do |rs|
-    rs.source_files = 'src/objective-c/RxLibrary/*.{h,m}',
-                      'src/objective-c/RxLibrary/transformations/*.{h,m}',
-                      'src/objective-c/RxLibrary/private/*.{h,m}'
-    rs.private_header_files = 'src/objective-c/RxLibrary/private/*.h'
+  s.subspec 'RxLibrary' do |ss|
+    src_dir = "#{objc_dir}/RxLibrary"
+    ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
+    ss.private_header_files = "#{src_dir}/private/*.h"
+    ss.header_mappings_dir = "#{objc_dir}"
   end
 
   # Core cross-platform gRPC library, written in C.
-  s.subspec 'C-Core' do |cs|
-    cs.source_files = 'src/core/support/env.h', 'src/core/support/file.h', 'src/core/support/murmur_hash.h', 'src/core/support/grpc_string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', 'include/grpc/support/alloc.h', 'include/grpc/support/atm.h', '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', 'include/grpc/support/host_port.h', 'include/grpc/support/log.h', 'include/grpc/support/log_win32.h', 'include/grpc/support/port_platform.h', 'include/grpc/support/slice.h', 'include/grpc/support/slice_buffer.h', 'include/grpc/support/string_util.h', 'include/grpc/support/subprocess.h', 'include/grpc/support/sync.h', 'include/grpc/support/sync_generic.h', 'include/grpc/support/sync_posix.h', 'include/grpc/support/sync_win32.h', 'include/grpc/support/thd.h', 'include/grpc/support/grpc_time.h', 'include/grpc/support/tls.h', 'include/grpc/support/tls_gcc.h', 'include/grpc/support/tls_msvc.h', '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', 'src/core/support/cpu_posix.c', 'src/core/support/cpu_windows.c', 'src/core/support/env_linux.c', 'src/core/support/env_posix.c', 'src/core/support/env_win32.c', 'src/core/support/file.c', 'src/core/support/file_posix.c', 'src/core/support/file_win32.c', 'src/core/support/histogram.c', 'src/core/support/host_port.c', 'src/core/support/log.c', 'src/core/support/log_android.c', 'src/core/support/log_linux.c', 'src/core/support/log_posix.c', 'src/core/support/log_win32.c', 'src/core/support/murmur_hash.c', 'src/core/support/slice.c', 'src/core/support/slice_buffer.c', 'src/core/support/string.c', 'src/core/support/string_posix.c', 'src/core/support/string_win32.c', 'src/core/support/subprocess_posix.c', 'src/core/support/sync.c', 'src/core/support/sync_posix.c', 'src/core/support/sync_win32.c', 'src/core/support/thd.c', 'src/core/support/thd_posix.c', 'src/core/support/thd_win32.c', 'src/core/support/time.c', 'src/core/support/time_posix.c', 'src/core/support/time_win32.c', 'src/core/support/tls_pthread.c', 'src/core/httpcli/format_request.h', 'src/core/httpcli/httpcli.h', 'src/core/httpcli/httpcli_security_connector.h', 'src/core/httpcli/parser.h', 'src/core/security/auth_filters.h', 'src/core/security/base64.h', 'src/core/security/credentials.h', 'src/core/security/json_token.h', 'src/core/security/secure_endpoint.h', 'src/core/security/secure_transport_setup.h', 'src/core/security/security_connector.h', 'src/core/security/security_context.h', 'src/core/tsi/fake_transport_security.h', 'src/core/tsi/ssl_transport_security.h', 'src/core/tsi/transport_security.h', 'src/core/tsi/transport_security_interface.h', 'src/core/census/grpc_context.h', 'src/core/channel/census_filter.h', 'src/core/channel/channel_args.h', 'src/core/channel/channel_stack.h', 'src/core/channel/child_channel.h', 'src/core/channel/client_channel.h', 'src/core/channel/client_setup.h', 'src/core/channel/connected_channel.h', 'src/core/channel/context.h', 'src/core/channel/http_client_filter.h', 'src/core/channel/http_server_filter.h', 'src/core/channel/noop_filter.h', 'src/core/compression/message_compress.h', 'src/core/debug/trace.h', 'src/core/iomgr/alarm.h', 'src/core/iomgr/alarm_heap.h', 'src/core/iomgr/alarm_internal.h', 'src/core/iomgr/endpoint.h', 'src/core/iomgr/endpoint_pair.h', 'src/core/iomgr/fd_posix.h', 'src/core/iomgr/iocp_windows.h', 'src/core/iomgr/iomgr.h', 'src/core/iomgr/iomgr_internal.h', 'src/core/iomgr/iomgr_posix.h', 'src/core/iomgr/pollset.h', 'src/core/iomgr/pollset_kick.h', 'src/core/iomgr/pollset_kick_posix.h', 'src/core/iomgr/pollset_kick_windows.h', 'src/core/iomgr/pollset_posix.h', 'src/core/iomgr/pollset_windows.h', 'src/core/iomgr/resolve_address.h', 'src/core/iomgr/sockaddr.h', 'src/core/iomgr/sockaddr_posix.h', 'src/core/iomgr/sockaddr_utils.h', 'src/core/iomgr/sockaddr_win32.h', 'src/core/iomgr/socket_utils_posix.h', 'src/core/iomgr/socket_windows.h', 'src/core/iomgr/tcp_client.h', 'src/core/iomgr/tcp_posix.h', 'src/core/iomgr/tcp_server.h', 'src/core/iomgr/tcp_windows.h', 'src/core/iomgr/time_averaged_stats.h', 'src/core/iomgr/wakeup_fd_pipe.h', 'src/core/iomgr/wakeup_fd_posix.h', 'src/core/json/json.h', 'src/core/json/json_common.h', 'src/core/json/json_reader.h', 'src/core/json/json_writer.h', 'src/core/profiling/timers.h', 'src/core/profiling/timers_preciseclock.h', 'src/core/surface/byte_buffer_queue.h', 'src/core/surface/call.h', 'src/core/surface/channel.h', 'src/core/surface/client.h', 'src/core/surface/completion_queue.h', 'src/core/surface/event_string.h', 'src/core/surface/init.h', 'src/core/surface/server.h', 'src/core/surface/surface_trace.h', 'src/core/transport/chttp2/alpn.h', 'src/core/transport/chttp2/bin_encoder.h', 'src/core/transport/chttp2/frame.h', 'src/core/transport/chttp2/frame_data.h', 'src/core/transport/chttp2/frame_goaway.h', 'src/core/transport/chttp2/frame_ping.h', 'src/core/transport/chttp2/frame_rst_stream.h', 'src/core/transport/chttp2/frame_settings.h', 'src/core/transport/chttp2/frame_window_update.h', 'src/core/transport/chttp2/hpack_parser.h', 'src/core/transport/chttp2/hpack_table.h', 'src/core/transport/chttp2/http2_errors.h', 'src/core/transport/chttp2/huffsyms.h', 'src/core/transport/chttp2/status_conversion.h', 'src/core/transport/chttp2/stream_encoder.h', 'src/core/transport/chttp2/stream_map.h', 'src/core/transport/chttp2/timeout_encoding.h', 'src/core/transport/chttp2/varint.h', 'src/core/transport/chttp2_transport.h', 'src/core/transport/metadata.h', 'src/core/transport/stream_op.h', 'src/core/transport/transport.h', 'src/core/transport/transport_impl.h', 'src/core/census/context.h', 'include/grpc/grpc_security.h', 'include/grpc/byte_buffer.h', 'include/grpc/byte_buffer_reader.h', 'include/grpc/compression.h', 'include/grpc/grpc.h', 'include/grpc/status.h', 'include/grpc/census.h', 'src/core/httpcli/format_request.c', 'src/core/httpcli/httpcli.c', 'src/core/httpcli/httpcli_security_connector.c', 'src/core/httpcli/parser.c', 'src/core/security/base64.c', 'src/core/security/client_auth_filter.c', 'src/core/security/credentials.c', 'src/core/security/credentials_metadata.c', 'src/core/security/credentials_posix.c', 'src/core/security/credentials_win32.c', 'src/core/security/google_default_credentials.c', 'src/core/security/json_token.c', 'src/core/security/secure_endpoint.c', 'src/core/security/secure_transport_setup.c', 'src/core/security/security_connector.c', 'src/core/security/security_context.c', 'src/core/security/server_auth_filter.c', 'src/core/security/server_secure_chttp2.c', 'src/core/surface/init_secure.c', 'src/core/surface/secure_channel_create.c', 'src/core/tsi/fake_transport_security.c', 'src/core/tsi/ssl_transport_security.c', 'src/core/tsi/transport_security.c', 'src/core/census/grpc_context.c', 'src/core/channel/channel_args.c', 'src/core/channel/channel_stack.c', 'src/core/channel/child_channel.c', 'src/core/channel/client_channel.c', 'src/core/channel/client_setup.c', 'src/core/channel/connected_channel.c', 'src/core/channel/http_client_filter.c', 'src/core/channel/http_server_filter.c', 'src/core/channel/noop_filter.c', 'src/core/compression/algorithm.c', 'src/core/compression/message_compress.c', 'src/core/debug/trace.c', 'src/core/iomgr/alarm.c', 'src/core/iomgr/alarm_heap.c', 'src/core/iomgr/endpoint.c', 'src/core/iomgr/endpoint_pair_posix.c', 'src/core/iomgr/endpoint_pair_windows.c', 'src/core/iomgr/fd_posix.c', 'src/core/iomgr/iocp_windows.c', 'src/core/iomgr/iomgr.c', 'src/core/iomgr/iomgr_posix.c', 'src/core/iomgr/iomgr_windows.c', 'src/core/iomgr/pollset_kick.c', 'src/core/iomgr/pollset_multipoller_with_epoll.c', 'src/core/iomgr/pollset_multipoller_with_poll_posix.c', 'src/core/iomgr/pollset_posix.c', 'src/core/iomgr/pollset_windows.c', 'src/core/iomgr/resolve_address_posix.c', 'src/core/iomgr/resolve_address_windows.c', 'src/core/iomgr/sockaddr_utils.c', 'src/core/iomgr/socket_utils_common_posix.c', 'src/core/iomgr/socket_utils_linux.c', 'src/core/iomgr/socket_utils_posix.c', 'src/core/iomgr/socket_windows.c', 'src/core/iomgr/tcp_client_posix.c', 'src/core/iomgr/tcp_client_windows.c', 'src/core/iomgr/tcp_posix.c', 'src/core/iomgr/tcp_server_posix.c', 'src/core/iomgr/tcp_server_windows.c', 'src/core/iomgr/tcp_windows.c', 'src/core/iomgr/time_averaged_stats.c', 'src/core/iomgr/wakeup_fd_eventfd.c', 'src/core/iomgr/wakeup_fd_nospecial.c', 'src/core/iomgr/wakeup_fd_pipe.c', 'src/core/iomgr/wakeup_fd_posix.c', 'src/core/json/json.c', 'src/core/json/json_reader.c', 'src/core/json/json_string.c', 'src/core/json/json_writer.c', 'src/core/profiling/basic_timers.c', 'src/core/profiling/stap_timers.c', 'src/core/surface/byte_buffer.c', 'src/core/surface/byte_buffer_queue.c', 'src/core/surface/byte_buffer_reader.c', 'src/core/surface/call.c', 'src/core/surface/call_details.c', 'src/core/surface/call_log_batch.c', 'src/core/surface/channel.c', 'src/core/surface/channel_create.c', 'src/core/surface/client.c', 'src/core/surface/completion_queue.c', 'src/core/surface/event_string.c', 'src/core/surface/init.c', 'src/core/surface/lame_client.c', 'src/core/surface/metadata_array.c', 'src/core/surface/server.c', 'src/core/surface/server_chttp2.c', 'src/core/surface/server_create.c', 'src/core/surface/surface_trace.c', 'src/core/transport/chttp2/alpn.c', 'src/core/transport/chttp2/bin_encoder.c', 'src/core/transport/chttp2/frame_data.c', 'src/core/transport/chttp2/frame_goaway.c', 'src/core/transport/chttp2/frame_ping.c', 'src/core/transport/chttp2/frame_rst_stream.c', 'src/core/transport/chttp2/frame_settings.c', 'src/core/transport/chttp2/frame_window_update.c', 'src/core/transport/chttp2/hpack_parser.c', 'src/core/transport/chttp2/hpack_table.c', 'src/core/transport/chttp2/huffsyms.c', 'src/core/transport/chttp2/status_conversion.c', 'src/core/transport/chttp2/stream_encoder.c', 'src/core/transport/chttp2/stream_map.c', 'src/core/transport/chttp2/timeout_encoding.c', 'src/core/transport/chttp2/varint.c', 'src/core/transport/chttp2_transport.c', 'src/core/transport/metadata.c', 'src/core/transport/stream_op.c', 'src/core/transport/transport.c', 'src/core/transport/transport_op_string.c', 'src/core/census/context.c', 'src/core/census/initialize.c', 
-    cs.private_header_files = 'src/core/support/env.h', 'src/core/support/file.h', 'src/core/support/murmur_hash.h', 'src/core/support/string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', 'src/core/httpcli/format_request.h', 'src/core/httpcli/httpcli.h', 'src/core/httpcli/httpcli_security_connector.h', 'src/core/httpcli/parser.h', 'src/core/security/auth_filters.h', 'src/core/security/base64.h', 'src/core/security/credentials.h', 'src/core/security/json_token.h', 'src/core/security/secure_endpoint.h', 'src/core/security/secure_transport_setup.h', 'src/core/security/security_connector.h', 'src/core/security/security_context.h', 'src/core/tsi/fake_transport_security.h', 'src/core/tsi/ssl_transport_security.h', 'src/core/tsi/transport_security.h', 'src/core/tsi/transport_security_interface.h', 'src/core/census/grpc_context.h', 'src/core/channel/census_filter.h', 'src/core/channel/channel_args.h', 'src/core/channel/channel_stack.h', 'src/core/channel/child_channel.h', 'src/core/channel/client_channel.h', 'src/core/channel/client_setup.h', 'src/core/channel/connected_channel.h', 'src/core/channel/context.h', 'src/core/channel/http_client_filter.h', 'src/core/channel/http_server_filter.h', 'src/core/channel/noop_filter.h', 'src/core/compression/message_compress.h', 'src/core/debug/trace.h', 'src/core/iomgr/alarm.h', 'src/core/iomgr/alarm_heap.h', 'src/core/iomgr/alarm_internal.h', 'src/core/iomgr/endpoint.h', 'src/core/iomgr/endpoint_pair.h', 'src/core/iomgr/fd_posix.h', 'src/core/iomgr/iocp_windows.h', 'src/core/iomgr/iomgr.h', 'src/core/iomgr/iomgr_internal.h', 'src/core/iomgr/iomgr_posix.h', 'src/core/iomgr/pollset.h', 'src/core/iomgr/pollset_kick.h', 'src/core/iomgr/pollset_kick_posix.h', 'src/core/iomgr/pollset_kick_windows.h', 'src/core/iomgr/pollset_posix.h', 'src/core/iomgr/pollset_windows.h', 'src/core/iomgr/resolve_address.h', 'src/core/iomgr/sockaddr.h', 'src/core/iomgr/sockaddr_posix.h', 'src/core/iomgr/sockaddr_utils.h', 'src/core/iomgr/sockaddr_win32.h', 'src/core/iomgr/socket_utils_posix.h', 'src/core/iomgr/socket_windows.h', 'src/core/iomgr/tcp_client.h', 'src/core/iomgr/tcp_posix.h', 'src/core/iomgr/tcp_server.h', 'src/core/iomgr/tcp_windows.h', 'src/core/iomgr/time_averaged_stats.h', 'src/core/iomgr/wakeup_fd_pipe.h', 'src/core/iomgr/wakeup_fd_posix.h', 'src/core/json/json.h', 'src/core/json/json_common.h', 'src/core/json/json_reader.h', 'src/core/json/json_writer.h', 'src/core/profiling/timers.h', 'src/core/profiling/timers_preciseclock.h', 'src/core/surface/byte_buffer_queue.h', 'src/core/surface/call.h', 'src/core/surface/channel.h', 'src/core/surface/client.h', 'src/core/surface/completion_queue.h', 'src/core/surface/event_string.h', 'src/core/surface/init.h', 'src/core/surface/server.h', 'src/core/surface/surface_trace.h', 'src/core/transport/chttp2/alpn.h', 'src/core/transport/chttp2/bin_encoder.h', 'src/core/transport/chttp2/frame.h', 'src/core/transport/chttp2/frame_data.h', 'src/core/transport/chttp2/frame_goaway.h', 'src/core/transport/chttp2/frame_ping.h', 'src/core/transport/chttp2/frame_rst_stream.h', 'src/core/transport/chttp2/frame_settings.h', 'src/core/transport/chttp2/frame_window_update.h', 'src/core/transport/chttp2/hpack_parser.h', 'src/core/transport/chttp2/hpack_table.h', 'src/core/transport/chttp2/http2_errors.h', 'src/core/transport/chttp2/huffsyms.h', 'src/core/transport/chttp2/status_conversion.h', 'src/core/transport/chttp2/stream_encoder.h', 'src/core/transport/chttp2/stream_map.h', 'src/core/transport/chttp2/timeout_encoding.h', 'src/core/transport/chttp2/varint.h', 'src/core/transport/chttp2_transport.h', 'src/core/transport/metadata.h', 'src/core/transport/stream_op.h', 'src/core/transport/transport.h', 'src/core/transport/transport_impl.h', 'src/core/census/context.h', 
-    cs.header_mappings_dir = '.'
-    # The core library includes its headers as either "src/core/..." or "grpc/...", meaning we have
-    # to tell XCode to look for headers under the "include" subdirectory too.
-    #
-    # TODO(jcanizales): Instead of doing this, during installation move everything under
-    # "include/grpc" one directory up. The directory names under PODS_ROOT are implementation
-    # details of Cocoapods, and have changed in the past, breaking this podspec.
-    cs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC" ' +
-                                             '"$(PODS_ROOT)/Headers/Private/gRPC/include"' }
+  s.subspec 'C-Core' do |ss|
+    ss.source_files = 'src/core/support/env.h',
+                      'src/core/support/file.h',
+                      'src/core/support/murmur_hash.h',
+                      'src/core/support/stack_lockfree.h',
+                      'src/core/support/grpc_string.h',
+                      'src/core/support/string_win32.h',
+                      'src/core/support/thd_internal.h',
+                      'grpc/support/alloc.h',
+                      'grpc/support/atm.h',
+                      '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',
+                      'grpc/support/host_port.h',
+                      'grpc/support/log.h',
+                      'grpc/support/log_win32.h',
+                      'grpc/support/port_platform.h',
+                      'grpc/support/slice.h',
+                      'grpc/support/slice_buffer.h',
+                      'grpc/support/string_util.h',
+                      'grpc/support/subprocess.h',
+                      'grpc/support/sync.h',
+                      'grpc/support/sync_generic.h',
+                      'grpc/support/sync_posix.h',
+                      'grpc/support/sync_win32.h',
+                      'grpc/support/thd.h',
+                      'grpc/support/grpc_time.h',
+                      'grpc/support/tls.h',
+                      'grpc/support/tls_gcc.h',
+                      'grpc/support/tls_msvc.h',
+                      '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',
+                      'src/core/support/cpu_posix.c',
+                      'src/core/support/cpu_windows.c',
+                      'src/core/support/env_linux.c',
+                      'src/core/support/env_posix.c',
+                      'src/core/support/env_win32.c',
+                      'src/core/support/file.c',
+                      'src/core/support/file_posix.c',
+                      'src/core/support/file_win32.c',
+                      'src/core/support/histogram.c',
+                      'src/core/support/host_port.c',
+                      'src/core/support/log.c',
+                      'src/core/support/log_android.c',
+                      'src/core/support/log_linux.c',
+                      'src/core/support/log_posix.c',
+                      'src/core/support/log_win32.c',
+                      'src/core/support/murmur_hash.c',
+                      'src/core/support/slice.c',
+                      'src/core/support/slice_buffer.c',
+                      'src/core/support/stack_lockfree.c',
+                      'src/core/support/string.c',
+                      'src/core/support/string_posix.c',
+                      'src/core/support/string_win32.c',
+                      'src/core/support/subprocess_posix.c',
+                      'src/core/support/sync.c',
+                      'src/core/support/sync_posix.c',
+                      'src/core/support/sync_win32.c',
+                      'src/core/support/thd.c',
+                      'src/core/support/thd_posix.c',
+                      'src/core/support/thd_win32.c',
+                      'src/core/support/time.c',
+                      'src/core/support/time_posix.c',
+                      'src/core/support/time_win32.c',
+                      'src/core/support/tls_pthread.c',
+                      'src/core/httpcli/format_request.h',
+                      'src/core/httpcli/httpcli.h',
+                      'src/core/httpcli/httpcli_security_connector.h',
+                      'src/core/httpcli/parser.h',
+                      'src/core/security/auth_filters.h',
+                      'src/core/security/base64.h',
+                      'src/core/security/credentials.h',
+                      'src/core/security/json_token.h',
+                      'src/core/security/jwt_verifier.h',
+                      'src/core/security/secure_endpoint.h',
+                      'src/core/security/secure_transport_setup.h',
+                      'src/core/security/security_connector.h',
+                      'src/core/security/security_context.h',
+                      'src/core/tsi/fake_transport_security.h',
+                      'src/core/tsi/ssl_transport_security.h',
+                      'src/core/tsi/transport_security.h',
+                      'src/core/tsi/transport_security_interface.h',
+                      'src/core/census/grpc_context.h',
+                      'src/core/channel/census_filter.h',
+                      'src/core/channel/channel_args.h',
+                      'src/core/channel/channel_stack.h',
+                      'src/core/channel/client_channel.h',
+                      'src/core/channel/compress_filter.h',
+                      'src/core/channel/connected_channel.h',
+                      'src/core/channel/context.h',
+                      'src/core/channel/http_client_filter.h',
+                      'src/core/channel/http_server_filter.h',
+                      'src/core/channel/noop_filter.h',
+                      'src/core/client_config/client_config.h',
+                      'src/core/client_config/connector.h',
+                      'src/core/client_config/lb_policies/pick_first.h',
+                      'src/core/client_config/lb_policy.h',
+                      'src/core/client_config/resolver.h',
+                      'src/core/client_config/resolver_factory.h',
+                      'src/core/client_config/resolver_registry.h',
+                      'src/core/client_config/resolvers/dns_resolver.h',
+                      'src/core/client_config/resolvers/unix_resolver_posix.h',
+                      'src/core/client_config/subchannel.h',
+                      'src/core/client_config/subchannel_factory.h',
+                      'src/core/client_config/uri_parser.h',
+                      'src/core/compression/message_compress.h',
+                      'src/core/debug/trace.h',
+                      'src/core/iomgr/alarm.h',
+                      'src/core/iomgr/alarm_heap.h',
+                      'src/core/iomgr/alarm_internal.h',
+                      'src/core/iomgr/endpoint.h',
+                      'src/core/iomgr/endpoint_pair.h',
+                      'src/core/iomgr/fd_posix.h',
+                      'src/core/iomgr/iocp_windows.h',
+                      'src/core/iomgr/iomgr.h',
+                      'src/core/iomgr/iomgr_internal.h',
+                      'src/core/iomgr/iomgr_posix.h',
+                      'src/core/iomgr/pollset.h',
+                      'src/core/iomgr/pollset_kick_posix.h',
+                      'src/core/iomgr/pollset_posix.h',
+                      'src/core/iomgr/pollset_set.h',
+                      'src/core/iomgr/pollset_set_posix.h',
+                      'src/core/iomgr/pollset_set_windows.h',
+                      'src/core/iomgr/pollset_windows.h',
+                      'src/core/iomgr/resolve_address.h',
+                      'src/core/iomgr/sockaddr.h',
+                      'src/core/iomgr/sockaddr_posix.h',
+                      'src/core/iomgr/sockaddr_utils.h',
+                      'src/core/iomgr/sockaddr_win32.h',
+                      'src/core/iomgr/socket_utils_posix.h',
+                      'src/core/iomgr/socket_windows.h',
+                      'src/core/iomgr/tcp_client.h',
+                      'src/core/iomgr/tcp_posix.h',
+                      'src/core/iomgr/tcp_server.h',
+                      'src/core/iomgr/tcp_windows.h',
+                      'src/core/iomgr/time_averaged_stats.h',
+                      'src/core/iomgr/wakeup_fd_pipe.h',
+                      'src/core/iomgr/wakeup_fd_posix.h',
+                      'src/core/json/json.h',
+                      'src/core/json/json_common.h',
+                      'src/core/json/json_reader.h',
+                      'src/core/json/json_writer.h',
+                      'src/core/profiling/timers.h',
+                      'src/core/profiling/timers_preciseclock.h',
+                      'src/core/surface/byte_buffer_queue.h',
+                      'src/core/surface/call.h',
+                      'src/core/surface/channel.h',
+                      'src/core/surface/completion_queue.h',
+                      'src/core/surface/event_string.h',
+                      'src/core/surface/init.h',
+                      'src/core/surface/server.h',
+                      'src/core/surface/surface_trace.h',
+                      'src/core/transport/chttp2/alpn.h',
+                      'src/core/transport/chttp2/bin_encoder.h',
+                      'src/core/transport/chttp2/frame.h',
+                      'src/core/transport/chttp2/frame_data.h',
+                      'src/core/transport/chttp2/frame_goaway.h',
+                      'src/core/transport/chttp2/frame_ping.h',
+                      'src/core/transport/chttp2/frame_rst_stream.h',
+                      'src/core/transport/chttp2/frame_settings.h',
+                      'src/core/transport/chttp2/frame_window_update.h',
+                      'src/core/transport/chttp2/hpack_parser.h',
+                      'src/core/transport/chttp2/hpack_table.h',
+                      'src/core/transport/chttp2/http2_errors.h',
+                      'src/core/transport/chttp2/huffsyms.h',
+                      'src/core/transport/chttp2/incoming_metadata.h',
+                      'src/core/transport/chttp2/internal.h',
+                      'src/core/transport/chttp2/status_conversion.h',
+                      'src/core/transport/chttp2/stream_encoder.h',
+                      'src/core/transport/chttp2/stream_map.h',
+                      'src/core/transport/chttp2/timeout_encoding.h',
+                      'src/core/transport/chttp2/varint.h',
+                      'src/core/transport/chttp2_transport.h',
+                      'src/core/transport/connectivity_state.h',
+                      'src/core/transport/metadata.h',
+                      'src/core/transport/stream_op.h',
+                      'src/core/transport/transport.h',
+                      'src/core/transport/transport_impl.h',
+                      'src/core/census/context.h',
+                      'grpc/grpc_security.h',
+                      'grpc/byte_buffer.h',
+                      'grpc/byte_buffer_reader.h',
+                      'grpc/compression.h',
+                      'grpc/grpc.h',
+                      'grpc/status.h',
+                      'grpc/census.h',
+                      'src/core/httpcli/format_request.c',
+                      'src/core/httpcli/httpcli.c',
+                      'src/core/httpcli/httpcli_security_connector.c',
+                      'src/core/httpcli/parser.c',
+                      'src/core/security/base64.c',
+                      'src/core/security/client_auth_filter.c',
+                      'src/core/security/credentials.c',
+                      'src/core/security/credentials_metadata.c',
+                      'src/core/security/credentials_posix.c',
+                      'src/core/security/credentials_win32.c',
+                      'src/core/security/google_default_credentials.c',
+                      'src/core/security/json_token.c',
+                      'src/core/security/jwt_verifier.c',
+                      'src/core/security/secure_endpoint.c',
+                      'src/core/security/secure_transport_setup.c',
+                      'src/core/security/security_connector.c',
+                      'src/core/security/security_context.c',
+                      'src/core/security/server_auth_filter.c',
+                      'src/core/security/server_secure_chttp2.c',
+                      'src/core/surface/init_secure.c',
+                      'src/core/surface/secure_channel_create.c',
+                      'src/core/tsi/fake_transport_security.c',
+                      'src/core/tsi/ssl_transport_security.c',
+                      'src/core/tsi/transport_security.c',
+                      'src/core/census/grpc_context.c',
+                      'src/core/channel/channel_args.c',
+                      'src/core/channel/channel_stack.c',
+                      'src/core/channel/client_channel.c',
+                      'src/core/channel/compress_filter.c',
+                      'src/core/channel/connected_channel.c',
+                      'src/core/channel/http_client_filter.c',
+                      'src/core/channel/http_server_filter.c',
+                      'src/core/channel/noop_filter.c',
+                      'src/core/client_config/client_config.c',
+                      'src/core/client_config/connector.c',
+                      'src/core/client_config/lb_policies/pick_first.c',
+                      'src/core/client_config/lb_policy.c',
+                      'src/core/client_config/resolver.c',
+                      'src/core/client_config/resolver_factory.c',
+                      'src/core/client_config/resolver_registry.c',
+                      'src/core/client_config/resolvers/dns_resolver.c',
+                      'src/core/client_config/resolvers/unix_resolver_posix.c',
+                      'src/core/client_config/subchannel.c',
+                      'src/core/client_config/subchannel_factory.c',
+                      'src/core/client_config/uri_parser.c',
+                      'src/core/compression/algorithm.c',
+                      'src/core/compression/message_compress.c',
+                      'src/core/debug/trace.c',
+                      'src/core/iomgr/alarm.c',
+                      'src/core/iomgr/alarm_heap.c',
+                      'src/core/iomgr/endpoint.c',
+                      'src/core/iomgr/endpoint_pair_posix.c',
+                      'src/core/iomgr/endpoint_pair_windows.c',
+                      'src/core/iomgr/fd_posix.c',
+                      'src/core/iomgr/iocp_windows.c',
+                      'src/core/iomgr/iomgr.c',
+                      'src/core/iomgr/iomgr_posix.c',
+                      'src/core/iomgr/iomgr_windows.c',
+                      'src/core/iomgr/pollset_kick_posix.c',
+                      'src/core/iomgr/pollset_multipoller_with_epoll.c',
+                      'src/core/iomgr/pollset_multipoller_with_poll_posix.c',
+                      'src/core/iomgr/pollset_posix.c',
+                      'src/core/iomgr/pollset_set_posix.c',
+                      'src/core/iomgr/pollset_set_windows.c',
+                      'src/core/iomgr/pollset_windows.c',
+                      'src/core/iomgr/resolve_address_posix.c',
+                      'src/core/iomgr/resolve_address_windows.c',
+                      'src/core/iomgr/sockaddr_utils.c',
+                      'src/core/iomgr/socket_utils_common_posix.c',
+                      'src/core/iomgr/socket_utils_linux.c',
+                      'src/core/iomgr/socket_utils_posix.c',
+                      'src/core/iomgr/socket_windows.c',
+                      'src/core/iomgr/tcp_client_posix.c',
+                      'src/core/iomgr/tcp_client_windows.c',
+                      'src/core/iomgr/tcp_posix.c',
+                      'src/core/iomgr/tcp_server_posix.c',
+                      'src/core/iomgr/tcp_server_windows.c',
+                      'src/core/iomgr/tcp_windows.c',
+                      'src/core/iomgr/time_averaged_stats.c',
+                      'src/core/iomgr/wakeup_fd_eventfd.c',
+                      'src/core/iomgr/wakeup_fd_nospecial.c',
+                      'src/core/iomgr/wakeup_fd_pipe.c',
+                      'src/core/iomgr/wakeup_fd_posix.c',
+                      'src/core/json/json.c',
+                      'src/core/json/json_reader.c',
+                      'src/core/json/json_string.c',
+                      'src/core/json/json_writer.c',
+                      'src/core/profiling/basic_timers.c',
+                      'src/core/profiling/stap_timers.c',
+                      'src/core/surface/byte_buffer.c',
+                      'src/core/surface/byte_buffer_queue.c',
+                      'src/core/surface/byte_buffer_reader.c',
+                      'src/core/surface/call.c',
+                      'src/core/surface/call_details.c',
+                      'src/core/surface/call_log_batch.c',
+                      'src/core/surface/channel.c',
+                      'src/core/surface/channel_create.c',
+                      'src/core/surface/completion_queue.c',
+                      'src/core/surface/event_string.c',
+                      'src/core/surface/init.c',
+                      'src/core/surface/lame_client.c',
+                      'src/core/surface/metadata_array.c',
+                      'src/core/surface/server.c',
+                      'src/core/surface/server_chttp2.c',
+                      'src/core/surface/server_create.c',
+                      'src/core/surface/surface_trace.c',
+                      'src/core/surface/version.c',
+                      'src/core/transport/chttp2/alpn.c',
+                      'src/core/transport/chttp2/bin_encoder.c',
+                      'src/core/transport/chttp2/frame_data.c',
+                      'src/core/transport/chttp2/frame_goaway.c',
+                      'src/core/transport/chttp2/frame_ping.c',
+                      'src/core/transport/chttp2/frame_rst_stream.c',
+                      'src/core/transport/chttp2/frame_settings.c',
+                      'src/core/transport/chttp2/frame_window_update.c',
+                      'src/core/transport/chttp2/hpack_parser.c',
+                      'src/core/transport/chttp2/hpack_table.c',
+                      'src/core/transport/chttp2/huffsyms.c',
+                      'src/core/transport/chttp2/incoming_metadata.c',
+                      'src/core/transport/chttp2/parsing.c',
+                      'src/core/transport/chttp2/status_conversion.c',
+                      'src/core/transport/chttp2/stream_encoder.c',
+                      'src/core/transport/chttp2/stream_lists.c',
+                      'src/core/transport/chttp2/stream_map.c',
+                      'src/core/transport/chttp2/timeout_encoding.c',
+                      'src/core/transport/chttp2/varint.c',
+                      'src/core/transport/chttp2/writing.c',
+                      'src/core/transport/chttp2_transport.c',
+                      'src/core/transport/connectivity_state.c',
+                      'src/core/transport/metadata.c',
+                      'src/core/transport/stream_op.c',
+                      'src/core/transport/transport.c',
+                      'src/core/transport/transport_op_string.c',
+                      'src/core/census/context.c',
+                      'src/core/census/initialize.c'
 
-    cs.requires_arc = false
-    cs.libraries = 'z'
-    cs.dependency 'OpenSSL', '~> 1.0.200'
+    ss.private_header_files = 'src/core/support/env.h',
+                              'src/core/support/file.h',
+                              'src/core/support/murmur_hash.h',
+                              'src/core/support/stack_lockfree.h',
+                              'src/core/support/string.h',
+                              'src/core/support/string_win32.h',
+                              'src/core/support/thd_internal.h',
+                              'src/core/httpcli/format_request.h',
+                              'src/core/httpcli/httpcli.h',
+                              'src/core/httpcli/httpcli_security_connector.h',
+                              'src/core/httpcli/parser.h',
+                              'src/core/security/auth_filters.h',
+                              'src/core/security/base64.h',
+                              'src/core/security/credentials.h',
+                              'src/core/security/json_token.h',
+                              'src/core/security/jwt_verifier.h',
+                              'src/core/security/secure_endpoint.h',
+                              'src/core/security/secure_transport_setup.h',
+                              'src/core/security/security_connector.h',
+                              'src/core/security/security_context.h',
+                              'src/core/tsi/fake_transport_security.h',
+                              'src/core/tsi/ssl_transport_security.h',
+                              'src/core/tsi/transport_security.h',
+                              'src/core/tsi/transport_security_interface.h',
+                              'src/core/census/grpc_context.h',
+                              'src/core/channel/census_filter.h',
+                              'src/core/channel/channel_args.h',
+                              'src/core/channel/channel_stack.h',
+                              'src/core/channel/client_channel.h',
+                              'src/core/channel/compress_filter.h',
+                              'src/core/channel/connected_channel.h',
+                              'src/core/channel/context.h',
+                              'src/core/channel/http_client_filter.h',
+                              'src/core/channel/http_server_filter.h',
+                              'src/core/channel/noop_filter.h',
+                              'src/core/client_config/client_config.h',
+                              'src/core/client_config/connector.h',
+                              'src/core/client_config/lb_policies/pick_first.h',
+                              'src/core/client_config/lb_policy.h',
+                              'src/core/client_config/resolver.h',
+                              'src/core/client_config/resolver_factory.h',
+                              'src/core/client_config/resolver_registry.h',
+                              'src/core/client_config/resolvers/dns_resolver.h',
+                              'src/core/client_config/resolvers/unix_resolver_posix.h',
+                              'src/core/client_config/subchannel.h',
+                              'src/core/client_config/subchannel_factory.h',
+                              'src/core/client_config/uri_parser.h',
+                              'src/core/compression/message_compress.h',
+                              'src/core/debug/trace.h',
+                              'src/core/iomgr/alarm.h',
+                              'src/core/iomgr/alarm_heap.h',
+                              'src/core/iomgr/alarm_internal.h',
+                              'src/core/iomgr/endpoint.h',
+                              'src/core/iomgr/endpoint_pair.h',
+                              'src/core/iomgr/fd_posix.h',
+                              'src/core/iomgr/iocp_windows.h',
+                              'src/core/iomgr/iomgr.h',
+                              'src/core/iomgr/iomgr_internal.h',
+                              'src/core/iomgr/iomgr_posix.h',
+                              'src/core/iomgr/pollset.h',
+                              'src/core/iomgr/pollset_kick_posix.h',
+                              'src/core/iomgr/pollset_posix.h',
+                              'src/core/iomgr/pollset_set.h',
+                              'src/core/iomgr/pollset_set_posix.h',
+                              'src/core/iomgr/pollset_set_windows.h',
+                              'src/core/iomgr/pollset_windows.h',
+                              'src/core/iomgr/resolve_address.h',
+                              'src/core/iomgr/sockaddr.h',
+                              'src/core/iomgr/sockaddr_posix.h',
+                              'src/core/iomgr/sockaddr_utils.h',
+                              'src/core/iomgr/sockaddr_win32.h',
+                              'src/core/iomgr/socket_utils_posix.h',
+                              'src/core/iomgr/socket_windows.h',
+                              'src/core/iomgr/tcp_client.h',
+                              'src/core/iomgr/tcp_posix.h',
+                              'src/core/iomgr/tcp_server.h',
+                              'src/core/iomgr/tcp_windows.h',
+                              'src/core/iomgr/time_averaged_stats.h',
+                              'src/core/iomgr/wakeup_fd_pipe.h',
+                              'src/core/iomgr/wakeup_fd_posix.h',
+                              'src/core/json/json.h',
+                              'src/core/json/json_common.h',
+                              'src/core/json/json_reader.h',
+                              'src/core/json/json_writer.h',
+                              'src/core/profiling/timers.h',
+                              'src/core/profiling/timers_preciseclock.h',
+                              'src/core/surface/byte_buffer_queue.h',
+                              'src/core/surface/call.h',
+                              'src/core/surface/channel.h',
+                              'src/core/surface/completion_queue.h',
+                              'src/core/surface/event_string.h',
+                              'src/core/surface/init.h',
+                              'src/core/surface/server.h',
+                              'src/core/surface/surface_trace.h',
+                              'src/core/transport/chttp2/alpn.h',
+                              'src/core/transport/chttp2/bin_encoder.h',
+                              'src/core/transport/chttp2/frame.h',
+                              'src/core/transport/chttp2/frame_data.h',
+                              'src/core/transport/chttp2/frame_goaway.h',
+                              'src/core/transport/chttp2/frame_ping.h',
+                              'src/core/transport/chttp2/frame_rst_stream.h',
+                              'src/core/transport/chttp2/frame_settings.h',
+                              'src/core/transport/chttp2/frame_window_update.h',
+                              'src/core/transport/chttp2/hpack_parser.h',
+                              'src/core/transport/chttp2/hpack_table.h',
+                              'src/core/transport/chttp2/http2_errors.h',
+                              'src/core/transport/chttp2/huffsyms.h',
+                              'src/core/transport/chttp2/incoming_metadata.h',
+                              'src/core/transport/chttp2/internal.h',
+                              'src/core/transport/chttp2/status_conversion.h',
+                              'src/core/transport/chttp2/stream_encoder.h',
+                              'src/core/transport/chttp2/stream_map.h',
+                              'src/core/transport/chttp2/timeout_encoding.h',
+                              'src/core/transport/chttp2/varint.h',
+                              'src/core/transport/chttp2_transport.h',
+                              'src/core/transport/connectivity_state.h',
+                              'src/core/transport/metadata.h',
+                              'src/core/transport/stream_op.h',
+                              'src/core/transport/transport.h',
+                              'src/core/transport/transport_impl.h',
+                              'src/core/census/context.h'
+
+    ss.header_mappings_dir = '.'
+
+    ss.requires_arc = false
+    ss.libraries = 'z'
+    ss.dependency 'OpenSSL', '~> 1.0.200'
+
+    # ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
   end
 
   # This is a workaround for Cocoapods Issue #1437.
@@ -47,21 +527,24 @@
   # It needs to be here (top-level) instead of in the C-Core subspec because Cocoapods doesn't run
   # prepare_command's of subspecs.
   #
-  # TODO(jcanizales): Try out Todd Reed's solution at Issue #1437.
+  # TODO(jcanizales): Try out others' solutions at Issue #1437.
   s.prepare_command = <<-CMD
+    # Move contents of include up a level to avoid manually specifying include paths
+    cp -r "include/grpc" "."
+
     DIR_TIME="grpc/support"
     BAD_TIME="$DIR_TIME/time.h"
     GOOD_TIME="$DIR_TIME/grpc_time.h"
-    grep -rl "$BAD_TIME" include/grpc src/core | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
-    if [ -f "include/$BAD_TIME" ];
+    grep -rl "$BAD_TIME" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
+    if [ -f "$BAD_TIME" ];
     then
-      mv -f "include/$BAD_TIME" "include/$GOOD_TIME"
+      mv -f "$BAD_TIME" "$GOOD_TIME"
     fi
 
     DIR_STRING="src/core/support"
     BAD_STRING="$DIR_STRING/string.h"
     GOOD_STRING="$DIR_STRING/grpc_string.h"
-    grep -rl "$BAD_STRING" include/grpc src/core | xargs sed -i '' -e s@$BAD_STRING@$GOOD_STRING@g
+    grep -rl "$BAD_STRING" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_STRING@$GOOD_STRING@g
     if [ -f "$BAD_STRING" ];
     then
       mv -f "$BAD_STRING" "$GOOD_STRING"
@@ -69,28 +552,27 @@
   CMD
 
   # Objective-C wrapper around the core gRPC library.
-  s.subspec 'GRPCClient' do |gs|
-    gs.source_files = 'src/objective-c/GRPCClient/*.{h,m}',
-                      'src/objective-c/GRPCClient/private/*.{h,m}'
-    gs.private_header_files = 'src/objective-c/GRPCClient/private/*.h'
-    gs.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
+  s.subspec 'GRPCClient' do |ss|
+    src_dir = "#{objc_dir}/GRPCClient"
+    ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
+    ss.private_header_files = "#{src_dir}/private/*.h"
+    ss.header_mappings_dir = "#{objc_dir}"
 
-    gs.dependency 'gRPC/C-Core'
-    # TODO(jcanizales): Remove this when the prepare_command moves everything under "include/grpc"
-    # one directory up.
-    gs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Public/gRPC/include"' }
-    gs.dependency 'gRPC/RxLibrary'
+    ss.dependency 'gRPC/C-Core'
+    ss.dependency 'gRPC/RxLibrary'
 
     # Certificates, to be able to establish TLS connections:
-    gs.resource_bundles = { 'gRPC' => ['etc/roots.pem'] }
+    ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
   end
 
   # RPC library for ProtocolBuffers, based on gRPC
-  s.subspec 'ProtoRPC' do |ps|
-    ps.source_files = 'src/objective-c/ProtoRPC/*.{h,m}'
+  s.subspec 'ProtoRPC' do |ss|
+    src_dir = "#{objc_dir}/ProtoRPC"
+    ss.source_files = "#{src_dir}/*.{h,m}"
+    ss.header_mappings_dir = "#{objc_dir}"
 
-    ps.dependency 'gRPC/GRPCClient'
-    ps.dependency 'gRPC/RxLibrary'
-    ps.dependency 'Protobuf', '~> 3.0.0-alpha-3'
+    ss.dependency 'gRPC/GRPCClient'
+    ss.dependency 'gRPC/RxLibrary'
+    ss.dependency 'Protobuf', '~> 3.0.0-alpha-3'
   end
 end
diff --git a/grpc.bzl b/grpc.bzl
new file mode 100644
index 0000000..9f26931
--- /dev/null
+++ b/grpc.bzl
@@ -0,0 +1,128 @@
+# 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.
+
+"""
+Bazel macros to declare gRPC libraries automatically generated from proto files.
+
+This file declares two macros:
+- objc_proto_library
+- objc_grpc_library
+"""
+
+def _lower_underscore_to_upper_camel(str):
+  humps = []
+  for hump in str.split('_'):
+    humps += [hump[0].upper() + hump[1:]]
+  return "".join(humps)
+
+def _file_to_upper_camel(src):
+  elements = src.rpartition('/')
+  upper_camel = _lower_underscore_to_upper_camel(elements[-1])
+  return "".join(elements[:-1] + [upper_camel])
+
+def _file_with_extension(src, ext):
+  elements = src.rpartition('/')
+  basename = elements[-1].partition('.')[0]
+  return "".join(elements[:-1] + [basename, ext])
+
+def _protoc_invocation(srcs, flags):
+  """Returns a command line to invoke protoc from a genrule, on the given
+  sources, using the given flags.
+  """
+  protoc_command = "$(location //external:protoc) -I . "
+  srcs_params = ""
+  for src in srcs:
+    srcs_params += " $(location %s)" % (src)
+  return protoc_command + flags + srcs_params
+
+def objc_proto_library(name, srcs, visibility=None):
+  """Declares an objc_library for the code generated by protoc from the given
+  proto sources. This generated code doesn't include proto services.
+  """
+  h_files = []
+  m_files = []
+  for src in srcs:
+    src = _file_to_upper_camel(src)
+    h_files += [_file_with_extension(src, ".pbobjc.h")]
+    m_files += [_file_with_extension(src, ".pbobjc.m")]
+
+  protoc_flags = "--objc_out=$(GENDIR)"
+
+  native.genrule(
+    name = name + "_codegen",
+    srcs = srcs + ["//external:protoc"],
+    outs = h_files + m_files,
+    cmd = _protoc_invocation(srcs, protoc_flags),
+  )
+  native.objc_library(
+    name = name,
+    hdrs = h_files,
+    includes = ["."],
+    non_arc_srcs = m_files,
+    deps = ["//external:protobuf_objc"],
+    visibility = visibility,
+  )
+
+def objc_grpc_library(name, services, other_messages, visibility=None):
+  """Declares an objc_library for the code generated by gRPC and protoc from the
+  given proto sources (services and other_messages). The generated code doesn't
+  include proto services of the files passed as other_messages.
+  """
+  objc_proto_library(name + "_messages", services + other_messages)
+
+  h_files = []
+  m_files = []
+  for src in services:
+    src = _file_to_upper_camel(src)
+    h_files += [_file_with_extension(src, ".pbrpc.h")]
+    m_files += [_file_with_extension(src, ".pbrpc.m")]
+
+  protoc_flags = ("--grpc_out=$(GENDIR) --plugin=" +
+      "protoc-gen-grpc=$(location //external:grpc_protoc_plugin_objc)")
+
+  native.genrule(
+    name = name + "_codegen",
+    srcs = services + [
+      "//external:grpc_protoc_plugin_objc",
+      "//external:protoc",
+    ],
+    outs = h_files + m_files,
+    cmd = _protoc_invocation(services, protoc_flags),
+  )
+  native.objc_library(
+    name = name,
+    hdrs = h_files,
+    includes = ["."],
+    srcs = m_files,
+    deps = [
+      ":" + name + "_messages",
+      "//external:proto_objc_rpc",
+    ],
+    visibility = visibility,
+  )
diff --git a/include/grpc++/async_unary_call.h b/include/grpc++/async_unary_call.h
index abb6308..d631ccd 100644
--- a/include/grpc++/async_unary_call.h
+++ b/include/grpc++/async_unary_call.h
@@ -51,47 +51,50 @@
   virtual ~ClientAsyncResponseReaderInterface() {}
   virtual void ReadInitialMetadata(void* tag) = 0;
   virtual void Finish(R* msg, Status* status, void* tag) = 0;
-
 };
 
 template <class R>
 class ClientAsyncResponseReader GRPC_FINAL
     : public ClientAsyncResponseReaderInterface<R> {
  public:
+  template <class W>
   ClientAsyncResponseReader(ChannelInterface* channel, CompletionQueue* cq,
                             const RpcMethod& method, ClientContext* context,
-                            const grpc::protobuf::Message& request)
+                            const W& request)
       : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
-    init_buf_.AddSendMessage(request);
-    init_buf_.AddClientSendClose();
+    init_buf_.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(init_buf_.SendMessage(request).ok());
+    init_buf_.ClientSendClose();
     call_.PerformOps(&init_buf_);
   }
 
   void ReadInitialMetadata(void* tag) {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddRecvInitialMetadata(context_);
+    meta_buf_.set_output_tag(tag);
+    meta_buf_.RecvInitialMetadata(context_);
     call_.PerformOps(&meta_buf_);
   }
 
   void Finish(R* msg, Status* status, void* tag) {
-    finish_buf_.Reset(tag);
+    finish_buf_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      finish_buf_.AddRecvInitialMetadata(context_);
+      finish_buf_.RecvInitialMetadata(context_);
     }
-    finish_buf_.AddRecvMessage(msg);
-    finish_buf_.AddClientRecvStatus(context_, status);
+    finish_buf_.RecvMessage(msg);
+    finish_buf_.ClientRecvStatus(context_, status);
     call_.PerformOps(&finish_buf_);
   }
 
  private:
   ClientContext* context_;
   Call call_;
-  SneakyCallOpBuffer init_buf_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer finish_buf_;
+  SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+                  CallOpClientSendClose> init_buf_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_buf_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>,
+            CallOpClientRecvStatus> finish_buf_;
 };
 
 template <class W>
@@ -104,34 +107,36 @@
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    meta_buf_.set_output_tag(tag);
+    meta_buf_.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_buf_);
   }
 
   void Finish(const W& msg, const Status& status, void* tag) {
-    finish_buf_.Reset(tag);
+    finish_buf_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
     // The response is dropped if the status is not OK.
     if (status.ok()) {
-      finish_buf_.AddSendMessage(msg);
+      finish_buf_.ServerSendStatus(
+          ctx_->trailing_metadata_, finish_buf_.SendMessage(msg));
+    } else {
+      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
     }
-    finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
     call_.PerformOps(&finish_buf_);
   }
 
   void FinishWithError(const Status& status, void* tag) {
     GPR_ASSERT(!status.ok());
-    finish_buf_.Reset(tag);
+    finish_buf_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+    finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
     call_.PerformOps(&finish_buf_);
   }
 
@@ -140,8 +145,9 @@
 
   Call call_;
   ServerContext* ctx_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata> meta_buf_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpServerSendStatus> finish_buf_;
 };
 
 }  // namespace grpc
diff --git a/src/cpp/server/thread_pool.h b/include/grpc++/auth_context.h
similarity index 69%
copy from src/cpp/server/thread_pool.h
copy to include/grpc++/auth_context.h
index 3b70249..c42105b 100644
--- a/src/cpp/server/thread_pool.h
+++ b/include/grpc++/auth_context.h
@@ -31,39 +31,35 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
-#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#ifndef GRPCXX_AUTH_CONTEXT_H
+#define GRPCXX_AUTH_CONTEXT_H
 
-#include <grpc++/config.h>
-
-#include <grpc++/impl/sync.h>
-#include <grpc++/impl/thd.h>
-#include <grpc++/thread_pool_interface.h>
-
-#include <queue>
 #include <vector>
 
+#include <grpc++/auth_property_iterator.h>
+#include <grpc++/config.h>
+
 namespace grpc {
 
-class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
+class AuthContext {
  public:
-  explicit ThreadPool(int num_threads);
-  ~ThreadPool();
+  virtual ~AuthContext() {}
 
-  void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
+  // A peer identity, in general is one or more properties (in which case they
+  // have the same name).
+  virtual std::vector<grpc::string> GetPeerIdentity() const = 0;
+  virtual grpc::string GetPeerIdentityPropertyName() const = 0;
 
- private:
-  grpc::mutex mu_;
-  grpc::condition_variable cv_;
-  bool shutdown_;
-  std::queue<std::function<void()>> callbacks_;
-  std::vector<grpc::thread*> threads_;
+  // Returns all the property values with the given name.
+  virtual std::vector<grpc::string> FindPropertyValues(
+      const grpc::string& name) const = 0;
 
-  void ThreadFunc();
+  // Iteration over all the properties.
+  virtual AuthPropertyIterator begin() const = 0;
+  virtual AuthPropertyIterator end() const = 0;
 };
 
-ThreadPoolInterface* CreateDefaultThreadPool();
-
 }  // namespace grpc
 
-#endif  // GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#endif  // GRPCXX_AUTH_CONTEXT_H
+
diff --git a/src/cpp/server/thread_pool.h b/include/grpc++/auth_property_iterator.h
similarity index 61%
copy from src/cpp/server/thread_pool.h
copy to include/grpc++/auth_property_iterator.h
index 3b70249..c7870c4 100644
--- a/src/cpp/server/thread_pool.h
+++ b/include/grpc++/auth_property_iterator.h
@@ -31,39 +31,47 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
-#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#ifndef GRPCXX_AUTH_PROPERTY_ITERATOR_H
+#define GRPCXX_AUTH_PROPERTY_ITERATOR_H
+
+#include <iterator>
+#include <vector>
 
 #include <grpc++/config.h>
 
-#include <grpc++/impl/sync.h>
-#include <grpc++/impl/thd.h>
-#include <grpc++/thread_pool_interface.h>
-
-#include <queue>
-#include <vector>
+struct grpc_auth_context;
+struct grpc_auth_property;
+struct grpc_auth_property_iterator;
 
 namespace grpc {
+class SecureAuthContext;
 
-class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
+typedef std::pair<grpc::string, grpc::string> AuthProperty;
+
+class AuthPropertyIterator
+    : public std::iterator<std::input_iterator_tag, const AuthProperty> {
  public:
-  explicit ThreadPool(int num_threads);
-  ~ThreadPool();
+  ~AuthPropertyIterator();
+  AuthPropertyIterator& operator++();
+  AuthPropertyIterator operator++(int);
+  bool operator==(const AuthPropertyIterator& rhs) const;
+  bool operator!=(const AuthPropertyIterator& rhs) const;
+  const AuthProperty operator*();
 
-  void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
-
+ protected:
+  AuthPropertyIterator();
+  AuthPropertyIterator(const grpc_auth_property* property,
+                       const grpc_auth_property_iterator* iter);
  private:
-  grpc::mutex mu_;
-  grpc::condition_variable cv_;
-  bool shutdown_;
-  std::queue<std::function<void()>> callbacks_;
-  std::vector<grpc::thread*> threads_;
-
-  void ThreadFunc();
+  friend class SecureAuthContext;
+  const grpc_auth_property* property_;
+  // The following items form a grpc_auth_property_iterator.
+  const grpc_auth_context* ctx_;
+  size_t index_;
+  const char* name_;
 };
 
-ThreadPoolInterface* CreateDefaultThreadPool();
-
 }  // namespace grpc
 
-#endif  // GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+ #endif  // GRPCXX_AUTH_PROPERTY_ITERATOR_H
+
diff --git a/include/grpc++/byte_buffer.h b/include/grpc++/byte_buffer.h
index 3e40eae..cb3c6a1 100644
--- a/include/grpc++/byte_buffer.h
+++ b/include/grpc++/byte_buffer.h
@@ -39,6 +39,8 @@
 #include <grpc/support/log.h>
 #include <grpc++/config.h>
 #include <grpc++/slice.h>
+#include <grpc++/status.h>
+#include <grpc++/impl/serialization_traits.h>
 
 #include <vector>
 
@@ -48,7 +50,7 @@
  public:
   ByteBuffer() : buffer_(nullptr) {}
 
-  ByteBuffer(Slice* slices, size_t nslices);
+  ByteBuffer(const Slice* slices, size_t nslices);
 
   ~ByteBuffer() {
     if (buffer_) {
@@ -56,13 +58,16 @@
     }
   }
 
-  void Dump(std::vector<Slice>* slices);
+  void Dump(std::vector<Slice>* slices) const;
 
   void Clear();
-  size_t Length();
+  size_t Length() const;
 
  private:
-  friend class CallOpBuffer;
+  friend class SerializationTraits<ByteBuffer, void>;
+
+  ByteBuffer(const ByteBuffer&);
+  ByteBuffer& operator=(const ByteBuffer&);
 
   // takes ownership
   void set_buffer(grpc_byte_buffer* buf) {
@@ -78,6 +83,22 @@
   grpc_byte_buffer* buffer_;
 };
 
+template <>
+class SerializationTraits<ByteBuffer, void> {
+ public:
+  static Status Deserialize(grpc_byte_buffer* byte_buffer, ByteBuffer* dest,
+                            int max_message_size) {
+    dest->set_buffer(byte_buffer);
+    return Status::OK;
+  }
+  static Status Serialize(const ByteBuffer& source, grpc_byte_buffer** buffer, 
+                        bool* own_buffer) {
+    *buffer = source.buffer();
+    *own_buffer = false;
+    return Status::OK;
+  }
+};
+
 }  // namespace grpc
 
 #endif  // GRPCXX_BYTE_BUFFER_H
diff --git a/include/grpc++/channel_arguments.h b/include/grpc++/channel_arguments.h
index 68f24cd..d726b9f 100644
--- a/include/grpc++/channel_arguments.h
+++ b/include/grpc++/channel_arguments.h
@@ -59,8 +59,8 @@
   void SetSslTargetNameOverride(const grpc::string& name);
   // TODO(yangg) add flow control options
 
-  // Set the compression level for the channel.
-  void SetCompressionLevel(grpc_compression_level level);
+  // Set the compression algorithm for the channel.
+  void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
 
   // Generic channel argument setters. Only for advanced use cases.
   void SetInt(const grpc::string& key, int value);
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index ecf4cc7..9df7669 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -38,18 +38,20 @@
 #include <memory>
 #include <string>
 
+#include <grpc/compression.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include <grpc++/auth_context.h>
 #include <grpc++/config.h>
 #include <grpc++/status.h>
 #include <grpc++/time.h>
 
 struct grpc_call;
 struct grpc_completion_queue;
+struct census_context;
 
 namespace grpc {
 
-class CallOpBuffer;
 class ChannelInterface;
 class CompletionQueue;
 class Credentials;
@@ -108,6 +110,18 @@
     creds_ = creds;
   }
 
+  grpc_compression_algorithm get_compression_algorithm() const {
+    return compression_algorithm_;
+  }
+
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  std::shared_ptr<const AuthContext> auth_context() const;
+
+  // Get and set census context
+  void set_census_context(census_context* ccp) { census_context_ = ccp; }
+  census_context* get_census_context() const { return census_context_; }
+
   void TryCancel();
 
  private:
@@ -115,7 +129,8 @@
   ClientContext(const ClientContext&);
   ClientContext& operator=(const ClientContext&);
 
-  friend class CallOpBuffer;
+  friend class CallOpClientRecvStatus;
+  friend class CallOpRecvInitialMetadata;
   friend class Channel;
   template <class R>
   friend class ::grpc::ClientReader;
@@ -131,6 +146,12 @@
   friend class ::grpc::ClientAsyncReaderWriter;
   template <class R>
   friend class ::grpc::ClientAsyncResponseReader;
+  template <class InputMessage, class OutputMessage>
+  friend Status BlockingUnaryCall(ChannelInterface* channel,
+                                  const RpcMethod& method,
+                                  ClientContext* context,
+                                  const InputMessage& request,
+                                  OutputMessage* result);
 
   grpc_call* call() { return call_; }
   void set_call(grpc_call* call,
@@ -148,9 +169,13 @@
   gpr_timespec deadline_;
   grpc::string authority_;
   std::shared_ptr<Credentials> creds_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
+  census_context* census_context_;
   std::multimap<grpc::string, grpc::string> send_initial_metadata_;
   std::multimap<grpc::string, grpc::string> recv_initial_metadata_;
   std::multimap<grpc::string, grpc::string> trailing_metadata_;
+
+  grpc_compression_algorithm compression_algorithm_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index e8429c8..0523ab6 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -35,8 +35,8 @@
 #define GRPCXX_COMPLETION_QUEUE_H
 
 #include <grpc/support/time.h>
-#include <grpc++/impl/client_unary_call.h>
 #include <grpc++/impl/grpc_library.h>
+#include <grpc++/status.h>
 #include <grpc++/time.h>
 
 struct grpc_completion_queue;
@@ -55,8 +55,19 @@
 class ServerWriter;
 template <class R, class W>
 class ServerReaderWriter;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler;
 
+class ChannelInterface;
+class ClientContext;
 class CompletionQueue;
+class RpcMethod;
 class Server;
 class ServerBuilder;
 class ServerContext;
@@ -84,7 +95,7 @@
 
   // Nonblocking (until deadline) read from queue.
   // Cannot rely on result of tag or ok if return is TIMEOUT
-  template<typename T>
+  template <typename T>
   NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
     TimePoint<T> deadline_tp(deadline);
     return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
@@ -94,7 +105,8 @@
   // Returns false if the queue is ready for destruction, true if event
 
   bool Next(void** tag, bool* ok) {
-    return (AsyncNextInternal(tag, ok, gpr_inf_future) != SHUTDOWN);
+    return (AsyncNextInternal(tag, ok, gpr_inf_future(GPR_CLOCK_REALTIME)) !=
+            SHUTDOWN);
   }
 
   // Shutdown has to be called, and the CompletionQueue can only be
@@ -118,13 +130,22 @@
   friend class ::grpc::ServerWriter;
   template <class R, class W>
   friend class ::grpc::ServerReaderWriter;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ServerStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class BidiStreamingHandler;
   friend class ::grpc::Server;
   friend class ::grpc::ServerContext;
+  template <class InputMessage, class OutputMessage>
   friend Status BlockingUnaryCall(ChannelInterface* channel,
                                   const RpcMethod& method,
                                   ClientContext* context,
-                                  const grpc::protobuf::Message& request,
-                                  grpc::protobuf::Message* result);
+                                  const InputMessage& request,
+                                  OutputMessage* result);
 
   NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
 
diff --git a/include/grpc++/config.h b/include/grpc++/config.h
index ca74064..1362c0a 100644
--- a/include/grpc++/config.h
+++ b/include/grpc++/config.h
@@ -77,31 +77,6 @@
 #define GRPC_OVERRIDE override
 #endif
 
-#ifndef GRPC_CUSTOM_PROTOBUF_INT64
-#include <google/protobuf/stubs/common.h>
-#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64
-#endif
-
-#ifndef GRPC_CUSTOM_MESSAGE
-#include <google/protobuf/message.h>
-#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
-#endif
-
-#ifndef GRPC_CUSTOM_STRING
-#include <string>
-#define GRPC_CUSTOM_STRING std::string
-#endif
-
-#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \
-  ::google::protobuf::io::ZeroCopyOutputStream
-#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \
-  ::google::protobuf::io::ZeroCopyInputStream
-#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
-#endif
-
 #ifdef GRPC_CXX0X_NO_NULLPTR
 #include <memory>
 const class {
@@ -125,23 +100,15 @@
 } nullptr = {};
 #endif
 
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
 namespace grpc {
 
 typedef GRPC_CUSTOM_STRING string;
 
-namespace protobuf {
-
-typedef GRPC_CUSTOM_MESSAGE Message;
-typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
-
-namespace io {
-typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
-typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
-typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream;
-}  // namespace io
-
-}  // namespace protobuf
-
 }  // namespace grpc
 
 #endif  // GRPCXX_CONFIG_H
diff --git a/include/grpc++/config_protobuf.h b/include/grpc++/config_protobuf.h
new file mode 100644
index 0000000..3afc7a5
--- /dev/null
+++ b/include/grpc++/config_protobuf.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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 GRPCXX_CONFIG_PROTOBUF_H
+#define GRPCXX_CONFIG_PROTOBUF_H
+
+#ifndef GRPC_CUSTOM_PROTOBUF_INT64
+#include <google/protobuf/stubs/common.h>
+#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64
+#endif
+
+#ifndef GRPC_CUSTOM_MESSAGE
+#include <google/protobuf/message.h>
+#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
+#endif
+
+#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \
+  ::google::protobuf::io::ZeroCopyOutputStream
+#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \
+  ::google::protobuf::io::ZeroCopyInputStream
+#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
+#endif
+
+namespace grpc {
+namespace protobuf {
+
+typedef GRPC_CUSTOM_MESSAGE Message;
+typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
+
+namespace io {
+typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
+typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
+typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream;
+}  // namespace io
+
+}  // namespace protobuf
+}  // namespace grpc
+
+#endif  // GRPCXX_CONFIG_PROTOBUF_H
diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h
index 7a40cd1..0eaaefc 100644
--- a/include/grpc++/credentials.h
+++ b/include/grpc++/credentials.h
@@ -120,6 +120,12 @@
 std::shared_ptr<Credentials> RefreshTokenCredentials(
     const grpc::string& json_refresh_token);
 
+// Builds access token credentials.
+// access_token is an oauth2 access token that was fetched using an out of band
+// mechanism.
+std::shared_ptr<Credentials> AccessTokenCredentials(
+    const grpc::string& access_token);
+
 // Builds IAM credentials.
 std::shared_ptr<Credentials> IAMCredentials(
     const grpc::string& authorization_token,
diff --git a/src/cpp/server/thread_pool.h b/include/grpc++/fixed_size_thread_pool.h
similarity index 83%
rename from src/cpp/server/thread_pool.h
rename to include/grpc++/fixed_size_thread_pool.h
index 3b70249..307e166 100644
--- a/src/cpp/server/thread_pool.h
+++ b/include/grpc++/fixed_size_thread_pool.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
-#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#ifndef GRPCXX_FIXED_SIZE_THREAD_POOL_H
+#define GRPCXX_FIXED_SIZE_THREAD_POOL_H
 
 #include <grpc++/config.h>
 
@@ -45,12 +45,12 @@
 
 namespace grpc {
 
-class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
+class FixedSizeThreadPool GRPC_FINAL : public ThreadPoolInterface {
  public:
-  explicit ThreadPool(int num_threads);
-  ~ThreadPool();
+  explicit FixedSizeThreadPool(int num_threads);
+  ~FixedSizeThreadPool();
 
-  void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
+  void Add(const std::function<void()>& callback) GRPC_OVERRIDE;
 
  private:
   grpc::mutex mu_;
@@ -62,8 +62,6 @@
   void ThreadFunc();
 };
 
-ThreadPoolInterface* CreateDefaultThreadPool();
-
 }  // namespace grpc
 
-#endif  // GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#endif  // GRPCXX_FIXED_SIZE_THREAD_POOL_H
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index aae199d..1fa4490 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -34,14 +34,19 @@
 #ifndef GRPCXX_IMPL_CALL_H
 #define GRPCXX_IMPL_CALL_H
 
-#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc++/client_context.h>
 #include <grpc++/completion_queue.h>
 #include <grpc++/config.h>
 #include <grpc++/status.h>
+#include <grpc++/impl/serialization_traits.h>
 
+#include <functional>
 #include <memory>
 #include <map>
 
+#include <string.h>
+
 struct grpc_call;
 struct grpc_op;
 
@@ -50,84 +55,502 @@
 class ByteBuffer;
 class Call;
 
-class CallOpBuffer : public CompletionQueueTag {
+void FillMetadataMap(grpc_metadata_array* arr,
+                     std::multimap<grpc::string, grpc::string>* metadata);
+grpc_metadata* FillMetadataArray(
+    const std::multimap<grpc::string, grpc::string>& metadata);
+
+/// Per-message write options.
+class WriteOptions {
  public:
-  CallOpBuffer();
-  ~CallOpBuffer();
+  WriteOptions() : flags_(0) {}
+  WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
 
-  void Reset(void* next_return_tag);
+  /// Clear all flags.
+  inline void Clear() {
+    flags_ = 0;
+  }
 
-  // Does not take ownership.
-  void AddSendInitialMetadata(
-      std::multimap<grpc::string, grpc::string>* metadata);
-  void AddSendInitialMetadata(ClientContext* ctx);
-  void AddRecvInitialMetadata(ClientContext* ctx);
-  void AddSendMessage(const grpc::protobuf::Message& message);
-  void AddSendMessage(const ByteBuffer& message);
-  void AddRecvMessage(grpc::protobuf::Message* message);
-  void AddRecvMessage(ByteBuffer* message);
-  void AddClientSendClose();
-  void AddClientRecvStatus(ClientContext* ctx, Status* status);
-  void AddServerSendStatus(std::multimap<grpc::string, grpc::string>* metadata,
-                           const Status& status);
-  void AddServerRecvClose(bool* cancelled);
+  /// Returns raw flags bitset.
+  inline gpr_uint32 flags() const {
+    return flags_;
+  }
 
-  // INTERNAL API:
+  /// Sets flag for the disabling of compression for the next message write.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline WriteOptions& set_no_compression() {
+    SetBit(GRPC_WRITE_NO_COMPRESS);
+    return *this;
+  }
 
-  // Convert to an array of grpc_op elements
-  void FillOps(grpc_op* ops, size_t* nops);
+  /// Clears flag for the disabling of compression for the next message write.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline WriteOptions& clear_no_compression() {
+    ClearBit(GRPC_WRITE_NO_COMPRESS);
+    return *this;
+  }
 
-  // Called by completion queue just prior to returning from Next() or Pluck()
-  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
+  /// Get value for the flag indicating whether compression for the next
+  /// message write is forcefully disabled.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline bool get_no_compression() const {
+    return GetBit(GRPC_WRITE_NO_COMPRESS);
+  }
 
-  void set_max_message_size(int max_message_size) {
-    max_message_size_ = max_message_size;
+  /// Sets flag indicating that the write may be buffered and need not go out on
+  /// the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline WriteOptions& set_buffer_hint() {
+    SetBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  /// Clears flag indicating that the write may be buffered and need not go out
+  /// on the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline WriteOptions& clear_buffer_hint() {
+    ClearBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  /// Get value for the flag indicating that the write may be buffered and need
+  /// not go out on the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline bool get_buffer_hint() const {
+    return GetBit(GRPC_WRITE_BUFFER_HINT);
+  }
+
+  WriteOptions& operator=(const WriteOptions& rhs) {
+    flags_ = rhs.flags_;
+    return *this;
+  }
+
+ private:
+  void SetBit(const gpr_int32 mask) {
+    flags_ |= mask;
+  }
+
+  void ClearBit(const gpr_int32 mask) {
+    flags_ &= ~mask;
+  }
+
+  bool GetBit(const gpr_int32 mask) const {
+    return flags_ & mask;
+  }
+
+  gpr_uint32 flags_;
+};
+
+/// Default argument for CallOpSet. I is unused by the class, but can be
+/// used for generating multiple names for the same thing.
+template <int I>
+class CallNoOp {
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {}
+  void FinishOp(bool* status, int max_message_size) {}
+};
+
+class CallOpSendInitialMetadata {
+ public:
+  CallOpSendInitialMetadata() : send_(false) {}
+
+  void SendInitialMetadata(
+      const std::multimap<grpc::string, grpc::string>& metadata) {
+    send_ = true;
+    initial_metadata_count_ = metadata.size();
+    initial_metadata_ = FillMetadataArray(metadata);
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_INITIAL_METADATA;
+    op->flags = 0;
+    op->data.send_initial_metadata.count = initial_metadata_count_;
+    op->data.send_initial_metadata.metadata = initial_metadata_;
+  }
+  void FinishOp(bool* status, int max_message_size) {
+    if (!send_) return;
+    gpr_free(initial_metadata_);
+    send_ = false;
+  }
+
+  bool send_;
+  size_t initial_metadata_count_;
+  grpc_metadata* initial_metadata_;
+};
+
+class CallOpSendMessage {
+ public:
+  CallOpSendMessage() : send_buf_(nullptr), own_buf_(false) {}
+
+  /// Send \a message using \a options for the write. The \a options are cleared
+  /// after use.
+  template <class M>
+  Status SendMessage(const M& message,
+                     const WriteOptions& options) GRPC_MUST_USE_RESULT;
+
+  template <class M>
+  Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (send_buf_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->flags = write_options_.flags();
+    op->data.send_message = send_buf_;
+    // Flags are per-message: clear them after use.
+    write_options_.Clear();
+  }
+  void FinishOp(bool* status, int max_message_size) {
+    if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
+    send_buf_ = nullptr;
+  }
+
+ private:
+  grpc_byte_buffer* send_buf_;
+  WriteOptions write_options_;
+  bool own_buf_;
+};
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message,
+                                      const WriteOptions& options) {
+  write_options_ = options;
+  return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
+}
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message) {
+  return SendMessage(message, WriteOptions());
+}
+
+template <class R>
+class CallOpRecvMessage {
+ public:
+  CallOpRecvMessage() : got_message(false), message_(nullptr) {}
+
+  void RecvMessage(R* message) { message_ = message; }
+
+  bool got_message;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (message_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->flags = 0;
+    op->data.recv_message = &recv_buf_;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (message_ == nullptr) return;
+    if (recv_buf_) {
+      if (*status) {
+        got_message = true;
+        *status = SerializationTraits<R>::Deserialize(recv_buf_, message_,
+                                                      max_message_size)
+                      .ok();
+      } else {
+        got_message = false;
+        grpc_byte_buffer_destroy(recv_buf_);
+      }
+    } else {
+      got_message = false;
+      *status = false;
+    }
+    message_ = nullptr;
+  }
+
+ private:
+  R* message_;
+  grpc_byte_buffer* recv_buf_;
+};
+
+namespace CallOpGenericRecvMessageHelper {
+class DeserializeFunc {
+ public:
+  virtual Status Deserialize(grpc_byte_buffer* buf, int max_message_size) = 0;
+};
+
+template <class R>
+class DeserializeFuncType GRPC_FINAL : public DeserializeFunc {
+ public:
+  DeserializeFuncType(R* message) : message_(message) {}
+  Status Deserialize(grpc_byte_buffer* buf,
+                     int max_message_size) GRPC_OVERRIDE {
+    return SerializationTraits<R>::Deserialize(buf, message_, max_message_size);
+  }
+
+ private:
+  R* message_;  // Not a managed pointer because management is external to this
+};
+}  // namespace CallOpGenericRecvMessageHelper
+
+class CallOpGenericRecvMessage {
+ public:
+  CallOpGenericRecvMessage() : got_message(false) {}
+
+  template <class R>
+  void RecvMessage(R* message) {
+    deserialize_.reset(
+        new CallOpGenericRecvMessageHelper::DeserializeFuncType<R>(message));
   }
 
   bool got_message;
 
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!deserialize_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->flags = 0;
+    op->data.recv_message = &recv_buf_;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (!deserialize_) return;
+    if (recv_buf_) {
+      if (*status) {
+        got_message = true;
+        *status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
+      } else {
+        got_message = false;
+        grpc_byte_buffer_destroy(recv_buf_);
+      }
+    } else {
+      got_message = false;
+      *status = false;
+    }
+    deserialize_.reset();
+  }
+
  private:
-  void* return_tag_;
-  // Send initial metadata
-  bool send_initial_metadata_;
-  size_t initial_metadata_count_;
-  grpc_metadata* initial_metadata_;
-  // Recv initial metadta
+  std::unique_ptr<CallOpGenericRecvMessageHelper::DeserializeFunc> deserialize_;
+  grpc_byte_buffer* recv_buf_;
+};
+
+class CallOpClientSendClose {
+ public:
+  CallOpClientSendClose() : send_(false) {}
+
+  void ClientSendClose() { send_ = true; }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+    op->flags = 0;
+  }
+  void FinishOp(bool* status, int max_message_size) { send_ = false; }
+
+ private:
+  bool send_;
+};
+
+class CallOpServerSendStatus {
+ public:
+  CallOpServerSendStatus() : send_status_available_(false) {}
+
+  void ServerSendStatus(
+      const std::multimap<grpc::string, grpc::string>& trailing_metadata,
+      const Status& status) {
+    trailing_metadata_count_ = trailing_metadata.size();
+    trailing_metadata_ = FillMetadataArray(trailing_metadata);
+    send_status_available_ = true;
+    send_status_code_ = static_cast<grpc_status_code>(status.error_code());
+    send_status_details_ = status.error_message();
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_status_available_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+    op->data.send_status_from_server.trailing_metadata_count =
+        trailing_metadata_count_;
+    op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
+    op->data.send_status_from_server.status = send_status_code_;
+    op->data.send_status_from_server.status_details =
+        send_status_details_.empty() ? nullptr : send_status_details_.c_str();
+    op->flags = 0;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (!send_status_available_) return;
+    gpr_free(trailing_metadata_);
+    send_status_available_ = false;
+  }
+
+ private:
+  bool send_status_available_;
+  grpc_status_code send_status_code_;
+  grpc::string send_status_details_;
+  size_t trailing_metadata_count_;
+  grpc_metadata* trailing_metadata_;
+};
+
+class CallOpRecvInitialMetadata {
+ public:
+  CallOpRecvInitialMetadata() : recv_initial_metadata_(nullptr) {}
+
+  void RecvInitialMetadata(ClientContext* context) {
+    context->initial_metadata_received_ = true;
+    recv_initial_metadata_ = &context->recv_initial_metadata_;
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!recv_initial_metadata_) return;
+    memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_INITIAL_METADATA;
+    op->data.recv_initial_metadata = &recv_initial_metadata_arr_;
+    op->flags = 0;
+  }
+  void FinishOp(bool* status, int max_message_size) {
+    if (recv_initial_metadata_ == nullptr) return;
+    FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
+    recv_initial_metadata_ = nullptr;
+  }
+
+ private:
   std::multimap<grpc::string, grpc::string>* recv_initial_metadata_;
   grpc_metadata_array recv_initial_metadata_arr_;
-  // Send message
-  const grpc::protobuf::Message* send_message_;
-  const ByteBuffer* send_message_buffer_;
-  grpc_byte_buffer* send_buf_;
-  // Recv message
-  grpc::protobuf::Message* recv_message_;
-  ByteBuffer* recv_message_buffer_;
-  grpc_byte_buffer* recv_buf_;
-  int max_message_size_;
-  // Client send close
-  bool client_send_close_;
-  // Client recv status
+};
+
+class CallOpClientRecvStatus {
+ public:
+  CallOpClientRecvStatus() : recv_status_(nullptr) {}
+
+  void ClientRecvStatus(ClientContext* context, Status* status) {
+    recv_trailing_metadata_ = &context->trailing_metadata_;
+    recv_status_ = status;
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (recv_status_ == nullptr) return;
+    memset(&recv_trailing_metadata_arr_, 0,
+           sizeof(recv_trailing_metadata_arr_));
+    status_details_ = nullptr;
+    status_details_capacity_ = 0;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+    op->data.recv_status_on_client.trailing_metadata =
+        &recv_trailing_metadata_arr_;
+    op->data.recv_status_on_client.status = &status_code_;
+    op->data.recv_status_on_client.status_details = &status_details_;
+    op->data.recv_status_on_client.status_details_capacity =
+        &status_details_capacity_;
+    op->flags = 0;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (recv_status_ == nullptr) return;
+    FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
+    *recv_status_ = Status(
+        static_cast<StatusCode>(status_code_),
+        status_details_ ? grpc::string(status_details_) : grpc::string());
+    gpr_free(status_details_);
+    recv_status_ = nullptr;
+  }
+
+ private:
   std::multimap<grpc::string, grpc::string>* recv_trailing_metadata_;
   Status* recv_status_;
   grpc_metadata_array recv_trailing_metadata_arr_;
   grpc_status_code status_code_;
   char* status_details_;
   size_t status_details_capacity_;
-  // Server send status
-  bool send_status_available_;
-  grpc_status_code send_status_code_;
-  grpc::string send_status_details_;
-  size_t trailing_metadata_count_;
-  grpc_metadata* trailing_metadata_;
-  int cancelled_buf_;
-  bool* recv_closed_;
 };
 
-// SneakyCallOpBuffer does not post completions to the completion queue
-class SneakyCallOpBuffer GRPC_FINAL : public CallOpBuffer {
+/// An abstract collection of call ops, used to generate the
+/// grpc_call_op structure to pass down to the lower layers,
+/// and as it is-a CompletionQueueTag, also massages the final
+/// completion into the correct form for consumption in the C++
+/// API.
+class CallOpSetInterface : public CompletionQueueTag {
+ public:
+  CallOpSetInterface() : max_message_size_(0) {}
+  /// Fills in grpc_op, starting from ops[*nops] and moving
+  /// upwards.
+  virtual void FillOps(grpc_op* ops, size_t* nops) = 0;
+
+  void set_max_message_size(int max_message_size) {
+    max_message_size_ = max_message_size;
+  }
+
+ protected:
+  int max_message_size_;
+};
+
+/// Primary implementaiton of CallOpSetInterface.
+/// Since we cannot use variadic templates, we declare slots up to
+/// the maximum count of ops we'll need in a set. We leverage the
+/// empty base class optimization to slim this class (especially
+/// when there are many unused slots used). To avoid duplicate base classes,
+/// the template parmeter for CallNoOp is varied by argument position.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class CallOpSet : public CallOpSetInterface,
+                  public Op1,
+                  public Op2,
+                  public Op3,
+                  public Op4,
+                  public Op5,
+                  public Op6 {
+ public:
+  CallOpSet() : return_tag_(this) {}
+  void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE {
+    this->Op1::AddOp(ops, nops);
+    this->Op2::AddOp(ops, nops);
+    this->Op3::AddOp(ops, nops);
+    this->Op4::AddOp(ops, nops);
+    this->Op5::AddOp(ops, nops);
+    this->Op6::AddOp(ops, nops);
+  }
+
+  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
+    this->Op1::FinishOp(status, max_message_size_);
+    this->Op2::FinishOp(status, max_message_size_);
+    this->Op3::FinishOp(status, max_message_size_);
+    this->Op4::FinishOp(status, max_message_size_);
+    this->Op5::FinishOp(status, max_message_size_);
+    this->Op6::FinishOp(status, max_message_size_);
+    *tag = return_tag_;
+    return true;
+  }
+
+  void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
+
+ private:
+  void* return_tag_;
+};
+
+/// A CallOpSet that does not post completions to the completion queue.
+///
+/// Allows hiding some completions that the C core must generate from
+/// C++ users.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class SneakyCallOpSet GRPC_FINAL
+    : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
  public:
   bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
-    return CallOpBuffer::FinalizeResult(tag, status) && false;
+    typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
+    return Base::FinalizeResult(tag, status) && false;
   }
 };
 
@@ -135,7 +558,7 @@
 class CallHook {
  public:
   virtual ~CallHook() {}
-  virtual void PerformOpsOnCall(CallOpBuffer* ops, Call* call) = 0;
+  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
 };
 
 // Straightforward wrapping of the C call object
@@ -146,7 +569,7 @@
   Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq,
        int max_message_size);
 
-  void PerformOps(CallOpBuffer* buffer);
+  void PerformOps(CallOpSetInterface* ops);
 
   grpc_call* call() { return call_; }
   CompletionQueue* cq() { return cq_; }
diff --git a/include/grpc++/impl/client_unary_call.h b/include/grpc++/impl/client_unary_call.h
index 2f234fd..b77ce7d 100644
--- a/include/grpc++/impl/client_unary_call.h
+++ b/include/grpc++/impl/client_unary_call.h
@@ -37,6 +37,8 @@
 #include <grpc++/config.h>
 #include <grpc++/status.h>
 
+#include <grpc++/impl/call.h>
+
 namespace grpc {
 
 class ChannelInterface;
@@ -45,10 +47,28 @@
 class RpcMethod;
 
 // Wrapper that performs a blocking unary call
+template <class InputMessage, class OutputMessage>
 Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
-                         ClientContext* context,
-                         const grpc::protobuf::Message& request,
-                         grpc::protobuf::Message* result);
+                         ClientContext* context, const InputMessage& request,
+                         OutputMessage* result) {
+  CompletionQueue cq;
+  Call call(channel->CreateCall(method, context, &cq));
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
+            CallOpClientSendClose, CallOpClientRecvStatus> ops;
+  Status status = ops.SendMessage(request);
+  if (!status.ok()) {
+    return status;
+  }
+  ops.SendInitialMetadata(context->send_initial_metadata_);
+  ops.RecvInitialMetadata(context);
+  ops.RecvMessage(result);
+  ops.ClientSendClose();
+  ops.ClientRecvStatus(context, &status);
+  call.PerformOps(&ops);
+  GPR_ASSERT((cq.Pluck(&ops) && ops.got_message) || !status.ok());
+  return status;
+}
 
 }  // namespace grpc
 
diff --git a/src/cpp/proto/proto_utils.h b/include/grpc++/impl/proto_utils.h
similarity index 65%
rename from src/cpp/proto/proto_utils.h
rename to include/grpc++/impl/proto_utils.h
index 67a775b..ebefa3e 100644
--- a/src/cpp/proto/proto_utils.h
+++ b/include/grpc++/impl/proto_utils.h
@@ -34,21 +34,42 @@
 #ifndef GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
 #define GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
 
-#include <grpc++/config.h>
+#include <type_traits>
 
-struct grpc_byte_buffer;
+#include <grpc/grpc.h>
+#include <grpc++/impl/serialization_traits.h>
+#include <grpc++/config_protobuf.h>
+#include <grpc++/status.h>
 
 namespace grpc {
 
 // Serialize the msg into a buffer created inside the function. The caller
 // should destroy the returned buffer when done with it. If serialization fails,
 // false is returned and buffer is left unchanged.
-bool SerializeProto(const grpc::protobuf::Message& msg,
-                    grpc_byte_buffer** buffer);
+Status SerializeProto(const grpc::protobuf::Message& msg,
+                      grpc_byte_buffer** buffer);
 
 // The caller keeps ownership of buffer and msg.
-bool DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
-                      int max_message_size);
+Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
+                        int max_message_size);
+
+template <class T>
+class SerializationTraits<T, typename std::enable_if<std::is_base_of<
+                                 grpc::protobuf::Message, T>::value>::type> {
+ public:
+  static Status Serialize(const grpc::protobuf::Message& msg,
+                          grpc_byte_buffer** buffer, bool* own_buffer) {
+    *own_buffer = true;
+    return SerializeProto(msg, buffer);
+  }
+  static Status Deserialize(grpc_byte_buffer* buffer,
+                            grpc::protobuf::Message* msg,
+                            int max_message_size) {
+    auto status = DeserializeProto(buffer, msg, max_message_size);
+    grpc_byte_buffer_destroy(buffer);
+    return status;
+  }
+};
 
 }  // namespace grpc
 
diff --git a/include/grpc++/impl/rpc_service_method.h b/include/grpc++/impl/rpc_service_method.h
index 50204d2..3cfbef7 100644
--- a/include/grpc++/impl/rpc_service_method.h
+++ b/include/grpc++/impl/rpc_service_method.h
@@ -55,16 +55,19 @@
  public:
   virtual ~MethodHandler() {}
   struct HandlerParameter {
-    HandlerParameter(Call* c, ServerContext* context,
-                     const grpc::protobuf::Message* req,
-                     grpc::protobuf::Message* resp)
-        : call(c), server_context(context), request(req), response(resp) {}
+    HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req,
+                     int max_size)
+        : call(c),
+          server_context(context),
+          request(req),
+          max_message_size(max_size) {}
     Call* call;
     ServerContext* server_context;
-    const grpc::protobuf::Message* request;
-    grpc::protobuf::Message* response;
+    // Handler required to grpc_byte_buffer_destroy this
+    grpc_byte_buffer* request;
+    int max_message_size;
   };
-  virtual Status RunHandler(const HandlerParameter& param) = 0;
+  virtual void RunHandler(const HandlerParameter& param) = 0;
 };
 
 // A wrapper class of an application provided rpc method handler.
@@ -77,11 +80,25 @@
       ServiceType* service)
       : func_(func), service_(service) {}
 
-  Status RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    // Invoke application function, cast proto messages to their actual types.
-    return func_(service_, param.server_context,
-                 dynamic_cast<const RequestType*>(param.request),
-                 dynamic_cast<ResponseType*>(param.response));
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    RequestType req;
+    Status status = SerializationTraits<RequestType>::Deserialize(
+        param.request, &req, param.max_message_size);
+    ResponseType rsp;
+    if (status.ok()) {
+      status = func_(service_, param.server_context, &req, &rsp);
+    }
+
+    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpServerSendStatus> ops;
+    ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    if (status.ok()) {
+      status = ops.SendMessage(rsp);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
   }
 
  private:
@@ -102,10 +119,21 @@
       ServiceType* service)
       : func_(func), service_(service) {}
 
-  Status RunHandler(const HandlerParameter& param) GRPC_FINAL {
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
     ServerReader<RequestType> reader(param.call, param.server_context);
-    return func_(service_, param.server_context, &reader,
-                 dynamic_cast<ResponseType*>(param.response));
+    ResponseType rsp;
+    Status status = func_(service_, param.server_context, &reader, &rsp);
+
+    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpServerSendStatus> ops;
+    ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    if (status.ok()) {
+      status = ops.SendMessage(rsp);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
   }
 
  private:
@@ -124,10 +152,23 @@
       ServiceType* service)
       : func_(func), service_(service) {}
 
-  Status RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    ServerWriter<ResponseType> writer(param.call, param.server_context);
-    return func_(service_, param.server_context,
-                 dynamic_cast<const RequestType*>(param.request), &writer);
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    RequestType req;
+    Status status = SerializationTraits<RequestType>::Deserialize(
+        param.request, &req, param.max_message_size);
+
+    if (status.ok()) {
+      ServerWriter<ResponseType> writer(param.call, param.server_context);
+      status = func_(service_, param.server_context, &req, &writer);
+    }
+
+    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);
   }
 
  private:
@@ -147,10 +188,18 @@
       ServiceType* service)
       : func_(func), service_(service) {}
 
-  Status RunHandler(const HandlerParameter& param) GRPC_FINAL {
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
     ServerReaderWriter<ResponseType, RequestType> stream(param.call,
                                                          param.server_context);
-    return func_(service_, param.server_context, &stream);
+    Status status = func_(service_, param.server_context, &stream);
+
+    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);
   }
 
  private:
@@ -162,29 +211,15 @@
 // Server side rpc method class
 class RpcServiceMethod : public RpcMethod {
  public:
-  // Takes ownership of the handler and two prototype objects.
+  // Takes ownership of the handler
   RpcServiceMethod(const char* name, RpcMethod::RpcType type,
-                   MethodHandler* handler,
-                   grpc::protobuf::Message* request_prototype,
-                   grpc::protobuf::Message* response_prototype)
-      : RpcMethod(name, type, nullptr),
-        handler_(handler),
-        request_prototype_(request_prototype),
-        response_prototype_(response_prototype) {}
+                   MethodHandler* handler)
+      : RpcMethod(name, type, nullptr), handler_(handler) {}
 
   MethodHandler* handler() { return handler_.get(); }
 
-  grpc::protobuf::Message* AllocateRequestProto() {
-    return request_prototype_->New();
-  }
-  grpc::protobuf::Message* AllocateResponseProto() {
-    return response_prototype_->New();
-  }
-
  private:
   std::unique_ptr<MethodHandler> handler_;
-  std::unique_ptr<grpc::protobuf::Message> request_prototype_;
-  std::unique_ptr<grpc::protobuf::Message> response_prototype_;
 };
 
 // This class contains all the method information for an rpc service. It is
diff --git a/include/grpc++/impl/serialization_traits.h b/include/grpc++/impl/serialization_traits.h
new file mode 100644
index 0000000..1f5c674
--- /dev/null
+++ b/include/grpc++/impl/serialization_traits.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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 GRPCXX_IMPL_SERIALIZATION_TRAITS_H
+#define GRPCXX_IMPL_SERIALIZATION_TRAITS_H
+
+namespace grpc {
+
+/// Defines how to serialize and deserialize some type.
+/// 
+/// Used for hooking different message serialization API's into GRPC.
+/// Each SerializationTraits implementation must provide the following
+/// functions:
+///   static Status Serialize(const Message& msg,
+///                           grpc_byte_buffer** buffer, 
+//                            bool* own_buffer);
+///   static Status Deserialize(grpc_byte_buffer* buffer,
+///                             Message* msg,
+///                             int max_message_size);
+///
+/// Serialize is required to convert message to a grpc_byte_buffer, and
+/// to store a pointer to that byte buffer at *buffer. *own_buffer should
+/// be set to true if the caller owns said byte buffer, or false if
+/// ownership is retained elsewhere.
+///
+/// Deserialize is required to convert buffer into the message stored at
+/// msg. max_message_size is passed in as a bound on the maximum number of
+/// message bytes Deserialize should accept.
+///
+/// Both functions return a Status, allowing them to explain what went 
+/// wrong if required.
+template <class Message,
+          class UnusedButHereForPartialTemplateSpecialization = void>
+class SerializationTraits;
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_SERIALIZATION_TRAITS_H
diff --git a/include/grpc++/impl/service_type.h b/include/grpc++/impl/service_type.h
index 25e437e..c33a278 100644
--- a/include/grpc++/impl/service_type.h
+++ b/include/grpc++/impl/service_type.h
@@ -35,6 +35,8 @@
 #define GRPCXX_IMPL_SERVICE_TYPE_H
 
 #include <grpc++/config.h>
+#include <grpc++/impl/serialization_traits.h>
+#include <grpc++/server.h>
 #include <grpc++/status.h>
 
 namespace grpc {
@@ -65,20 +67,8 @@
 
 class AsynchronousService {
  public:
-  // this is Server, but in disguise to avoid a link dependency
-  class DispatchImpl {
-   public:
-    virtual void RequestAsyncCall(void* registered_method,
-                                  ServerContext* context,
-                                  ::grpc::protobuf::Message* request,
-                                  ServerAsyncStreamingInterface* stream,
-                                  CompletionQueue* call_cq,
-                                  ServerCompletionQueue* notification_cq,
-                                  void* tag) = 0;
-  };
-
   AsynchronousService(const char** method_names, size_t method_count)
-      : dispatch_impl_(nullptr),
+      : server_(nullptr),
         method_names_(method_names),
         method_count_(method_count),
         request_args_(nullptr) {}
@@ -86,42 +76,43 @@
   ~AsynchronousService() { delete[] request_args_; }
 
  protected:
-  void RequestAsyncUnary(int index, ServerContext* context,
-                         grpc::protobuf::Message* request,
+  template <class Message>
+  void RequestAsyncUnary(int index, ServerContext* context, Message* request,
                          ServerAsyncStreamingInterface* stream,
                          CompletionQueue* call_cq,
                          ServerCompletionQueue* notification_cq, void* tag) {
-    dispatch_impl_->RequestAsyncCall(request_args_[index], context, request,
-                                     stream, call_cq, notification_cq, tag);
+    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
+                              notification_cq, tag, request);
   }
   void RequestClientStreaming(int index, ServerContext* context,
                               ServerAsyncStreamingInterface* stream,
                               CompletionQueue* call_cq,
                               ServerCompletionQueue* notification_cq,
                               void* tag) {
-    dispatch_impl_->RequestAsyncCall(request_args_[index], context, nullptr,
-                                     stream, call_cq, notification_cq, tag);
+    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
+                              notification_cq, tag);
   }
+  template <class Message>
   void RequestServerStreaming(int index, ServerContext* context,
-                              grpc::protobuf::Message* request,
+                              Message* request,
                               ServerAsyncStreamingInterface* stream,
                               CompletionQueue* call_cq,
                               ServerCompletionQueue* notification_cq,
                               void* tag) {
-    dispatch_impl_->RequestAsyncCall(request_args_[index], context, request,
-                                     stream, call_cq, notification_cq, tag);
+    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
+                              notification_cq, tag, request);
   }
   void RequestBidiStreaming(int index, ServerContext* context,
                             ServerAsyncStreamingInterface* stream,
                             CompletionQueue* call_cq,
                             ServerCompletionQueue* notification_cq, void* tag) {
-    dispatch_impl_->RequestAsyncCall(request_args_[index], context, nullptr,
-                                     stream, call_cq, notification_cq, tag);
+    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
+                              notification_cq, tag);
   }
 
  private:
   friend class Server;
-  DispatchImpl* dispatch_impl_;
+  Server* server_;
   const char** const method_names_;
   size_t method_count_;
   void** request_args_;
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index 2cfeb35..94ee0b6 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -41,25 +41,24 @@
 #include <grpc++/config.h>
 #include <grpc++/impl/call.h>
 #include <grpc++/impl/grpc_library.h>
-#include <grpc++/impl/service_type.h>
 #include <grpc++/impl/sync.h>
 #include <grpc++/status.h>
 
 struct grpc_server;
 
 namespace grpc {
+
 class AsynchronousService;
 class GenericServerContext;
 class AsyncGenericService;
 class RpcService;
 class RpcServiceMethod;
+class ServerAsyncStreamingInterface;
 class ServerCredentials;
 class ThreadPoolInterface;
 
 // Currently it only supports handling rpcs in a single thread.
-class Server GRPC_FINAL : public GrpcLibrary,
-                          private CallHook,
-                          private AsynchronousService::DispatchImpl {
+class Server GRPC_FINAL : public GrpcLibrary, private CallHook {
  public:
   ~Server();
 
@@ -73,6 +72,7 @@
 
  private:
   friend class AsyncGenericService;
+  friend class AsynchronousService;
   friend class ServerBuilder;
 
   class SyncRequest;
@@ -84,8 +84,8 @@
          int max_message_size);
   // Register a service. This call does not take ownership of the service.
   // The service must exist for the lifetime of the Server instance.
-  bool RegisterService(RpcService* service);
-  bool RegisterAsyncService(AsynchronousService* service);
+  bool RegisterService(const grpc::string *host, RpcService* service);
+  bool RegisterAsyncService(const grpc::string *host, AsynchronousService* service);
   void RegisterAsyncGenericService(AsyncGenericService* service);
   // Add a listening port. Can be called multiple times.
   int AddListeningPort(const grpc::string& addr, ServerCredentials* creds);
@@ -96,21 +96,123 @@
   void RunRpc();
   void ScheduleCallback();
 
-  void PerformOpsOnCall(CallOpBuffer* ops, Call* call) GRPC_OVERRIDE;
+  void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE;
 
-  // DispatchImpl
-  void RequestAsyncCall(void* registered_method, ServerContext* context,
-                        grpc::protobuf::Message* request,
+  class BaseAsyncRequest : public CompletionQueueTag {
+   public:
+    BaseAsyncRequest(Server* server, ServerContext* context,
+                     ServerAsyncStreamingInterface* stream,
+                     CompletionQueue* call_cq, void* tag);
+    virtual ~BaseAsyncRequest();
+
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
+
+   protected:
+    Server* const server_;
+    ServerContext* const context_;
+    ServerAsyncStreamingInterface* const stream_;
+    CompletionQueue* const call_cq_;
+    void* const tag_;
+    grpc_call* call_;
+    grpc_metadata_array initial_metadata_array_;
+  };
+
+  class RegisteredAsyncRequest : public BaseAsyncRequest {
+   public:
+    RegisteredAsyncRequest(Server* server, ServerContext* context,
+                           ServerAsyncStreamingInterface* stream,
+                           CompletionQueue* call_cq, void* tag);
+
+    // uses BaseAsyncRequest::FinalizeResult
+
+   protected:
+    void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
+                      ServerCompletionQueue* notification_cq);
+  };
+
+  class NoPayloadAsyncRequest GRPC_FINAL : public RegisteredAsyncRequest {
+   public:
+    NoPayloadAsyncRequest(void* registered_method, Server* server,
+                          ServerContext* context,
+                          ServerAsyncStreamingInterface* stream,
+                          CompletionQueue* call_cq,
+                          ServerCompletionQueue* notification_cq, void* tag)
+        : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
+      IssueRequest(registered_method, nullptr, notification_cq);
+    }
+
+    // uses RegisteredAsyncRequest::FinalizeResult
+  };
+
+  template <class Message>
+  class PayloadAsyncRequest GRPC_FINAL : public RegisteredAsyncRequest {
+   public:
+    PayloadAsyncRequest(void* registered_method, Server* server,
+                        ServerContext* context,
                         ServerAsyncStreamingInterface* stream,
                         CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq,
-                        void* tag) GRPC_OVERRIDE;
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        Message* request)
+        : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
+          request_(request) {
+      IssueRequest(registered_method, &payload_, notification_cq);
+    }
+
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
+      bool serialization_status =
+          *status && payload_ &&
+          SerializationTraits<Message>::Deserialize(payload_, request_,
+                                                    server_->max_message_size_)
+              .ok();
+      bool ret = RegisteredAsyncRequest::FinalizeResult(tag, status);
+      *status = serialization_status && *status;
+      return ret;
+    }
+
+   private:
+    grpc_byte_buffer* payload_;
+    Message* const request_;
+  };
+
+  class GenericAsyncRequest GRPC_FINAL : public BaseAsyncRequest {
+   public:
+    GenericAsyncRequest(Server* server, GenericServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag);
+
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
+
+   private:
+    grpc_call_details call_details_;
+  };
+
+  template <class Message>
+  void RequestAsyncCall(void* registered_method, ServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        Message* message) {
+    new PayloadAsyncRequest<Message>(registered_method, this, context, stream,
+                                     call_cq, notification_cq, tag, message);
+  }
+
+  void RequestAsyncCall(void* registered_method, ServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag) {
+    new NoPayloadAsyncRequest(registered_method, this, context, stream, call_cq,
+                              notification_cq, tag);
+  }
 
   void RequestAsyncGenericCall(GenericServerContext* context,
                                ServerAsyncStreamingInterface* stream,
-                               CompletionQueue* cq,
+                               CompletionQueue* call_cq,
                                ServerCompletionQueue* notification_cq,
-                               void* tag);
+                               void* tag) {
+    new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
+                            tag);
+  }
 
   const int max_message_size_;
 
@@ -133,8 +235,6 @@
   ThreadPoolInterface* thread_pool_;
   // Whether the thread pool is created and owned by the server.
   bool thread_pool_owned_;
- private:
-  Server() : max_message_size_(-1), server_(NULL) { abort(); }
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index ecee475..44ee00e 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -58,17 +58,35 @@
   // Register a service. This call does not take ownership of the service.
   // The service must exist for the lifetime of the Server instance returned by
   // BuildAndStart().
+  // Matches requests with any :authority
   void RegisterService(SynchronousService* service);
 
-  // Register an asynchronous service. New calls will be delevered to cq.
+  // Register an asynchronous service.
   // This call does not take ownership of the service or completion queue.
   // The service and completion queuemust exist for the lifetime of the Server
   // instance returned by BuildAndStart().
+  // Matches requests with any :authority
   void RegisterAsyncService(AsynchronousService* service);
 
   // Register a generic service.
+  // Matches requests with any :authority
   void RegisterAsyncGenericService(AsyncGenericService* service);
 
+  // Register a service. This call does not take ownership of the service.
+  // The service must exist for the lifetime of the Server instance returned by
+  // BuildAndStart().
+  // Only matches requests with :authority \a host
+  void RegisterService(const grpc::string& host, 
+                       SynchronousService* service);
+
+  // Register an asynchronous service.
+  // This call does not take ownership of the service or completion queue.
+  // The service and completion queuemust exist for the lifetime of the Server
+  // instance returned by BuildAndStart().
+  // Only matches requests with :authority \a host
+  void RegisterAsyncService(const grpc::string& host, 
+                            AsynchronousService* service);
+
   // Set max message size in bytes.
   void SetMaxMessageSize(int max_message_size) {
     max_message_size_ = max_message_size;
@@ -98,9 +116,18 @@
     int* selected_port;
   };
 
+  typedef std::unique_ptr<grpc::string> HostString;
+  template <class T> struct NamedService {
+    explicit NamedService(T* s) : service(s) {}
+    NamedService(const grpc::string& h, T *s)
+        : host(new grpc::string(h)), service(s) {}
+    HostString host;
+    T* service;
+  };
+
   int max_message_size_;
-  std::vector<RpcService*> services_;
-  std::vector<AsynchronousService*> async_services_;
+  std::vector<std::unique_ptr<NamedService<RpcService>>> services_;
+  std::vector<std::unique_ptr<NamedService<AsynchronousService>>> async_services_;
   std::vector<Port> ports_;
   std::vector<ServerCompletionQueue*> cqs_;
   std::shared_ptr<ServerCredentials> creds_;
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index d88a3ae..3bfa48f 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -35,8 +35,11 @@
 #define GRPCXX_SERVER_CONTEXT_H
 
 #include <map>
+#include <memory>
 
+#include <grpc/compression.h>
 #include <grpc/support/time.h>
+#include <grpc++/auth_context.h>
 #include <grpc++/config.h>
 #include <grpc++/time.h>
 
@@ -60,12 +63,24 @@
 class ServerWriter;
 template <class R, class W>
 class ServerReaderWriter;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler;
 
 class Call;
 class CallOpBuffer;
 class CompletionQueue;
 class Server;
 
+namespace testing {
+class InteropContextInspector;
+}  // namespace testing
+
 // Interface of server side rpc context.
 class ServerContext {
  public:
@@ -83,13 +98,26 @@
   void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
   void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
 
-  bool IsCancelled();
+  bool IsCancelled() const;
 
   const std::multimap<grpc::string, grpc::string>& client_metadata() {
     return client_metadata_;
   }
 
+  grpc_compression_level get_compression_level() const {
+    return compression_level_;
+  }
+  void set_compression_level(grpc_compression_level level);
+
+  grpc_compression_algorithm get_compression_algorithm() const {
+    return compression_algorithm_;
+  }
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  std::shared_ptr<const AuthContext> auth_context() const;
+
  private:
+  friend class ::grpc::testing::InteropContextInspector;
   friend class ::grpc::Server;
   template <class W, class R>
   friend class ::grpc::ServerAsyncReader;
@@ -105,6 +133,14 @@
   friend class ::grpc::ServerWriter;
   template <class R, class W>
   friend class ::grpc::ServerReaderWriter;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ServerStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class BidiStreamingHandler;
 
   // Prevent copying.
   ServerContext(const ServerContext&);
@@ -117,15 +153,21 @@
   ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
                 size_t metadata_count);
 
+  void set_call(grpc_call* call);
+
   CompletionOp* completion_op_;
 
   gpr_timespec deadline_;
   grpc_call* call_;
   CompletionQueue* cq_;
   bool sent_initial_metadata_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
   std::multimap<grpc::string, grpc::string> client_metadata_;
   std::multimap<grpc::string, grpc::string> initial_metadata_;
   std::multimap<grpc::string, grpc::string> trailing_metadata_;
+
+  grpc_compression_level compression_level_;
+  grpc_compression_algorithm compression_algorithm_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/stream.h b/include/grpc++/stream.h
index 472911e..3903f2e 100644
--- a/include/grpc++/stream.h
+++ b/include/grpc++/stream.h
@@ -79,7 +79,11 @@
 
   // Blocking write msg to the stream. Returns true on success.
   // Returns false when the stream has been closed.
-  virtual bool Write(const W& msg) = 0;
+  virtual bool Write(const W& msg, const WriteOptions& options) = 0;
+
+  inline bool Write(const W& msg) {
+    return Write(msg, WriteOptions());
+  }
 };
 
 template <class R>
@@ -93,15 +97,18 @@
 class ClientReader GRPC_FINAL : public ClientReaderInterface<R> {
  public:
   // Blocking create a stream and write the first request out.
+  template <class W>
   ClientReader(ChannelInterface* channel, const RpcMethod& method,
-               ClientContext* context, const grpc::protobuf::Message& request)
+               ClientContext* context, const W& request)
       : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
-    CallOpBuffer buf;
-    buf.AddSendInitialMetadata(&context->send_initial_metadata_);
-    buf.AddSendMessage(request);
-    buf.AddClientSendClose();
-    call_.PerformOps(&buf);
-    cq_.Pluck(&buf);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpClientSendClose> ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(ops.SendMessage(request).ok());
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
   }
 
   // Blocking wait for initial metadata from server. The received metadata
@@ -111,28 +118,28 @@
   void WaitForInitialMetadata() {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    CallOpBuffer buf;
-    buf.AddRecvInitialMetadata(context_);
-    call_.PerformOps(&buf);
-    cq_.Pluck(&buf);  // status ignored
+    CallOpSet<CallOpRecvInitialMetadata> ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  // status ignored
   }
 
   bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
+    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops;
     if (!context_->initial_metadata_received_) {
-      buf.AddRecvInitialMetadata(context_);
+      ops.RecvInitialMetadata(context_);
     }
-    buf.AddRecvMessage(msg);
-    call_.PerformOps(&buf);
-    return cq_.Pluck(&buf) && buf.got_message;
+    ops.RecvMessage(msg);
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops) && ops.got_message;
   }
 
   Status Finish() GRPC_OVERRIDE {
-    CallOpBuffer buf;
+    CallOpSet<CallOpClientRecvStatus> ops;
     Status status;
-    buf.AddClientRecvStatus(context_, &status);
-    call_.PerformOps(&buf);
-    GPR_ASSERT(cq_.Pluck(&buf));
+    ops.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&ops);
+    GPR_ASSERT(cq_.Pluck(&ops));
     return status;
   }
 
@@ -150,48 +157,50 @@
 };
 
 template <class W>
-class ClientWriter GRPC_FINAL : public ClientWriterInterface<W> {
+class ClientWriter : public ClientWriterInterface<W> {
  public:
   // Blocking create a stream.
+  template <class R>
   ClientWriter(ChannelInterface* channel, const RpcMethod& method,
-               ClientContext* context, grpc::protobuf::Message* response)
-      : context_(context),
-        response_(response),
-        call_(channel->CreateCall(method, context, &cq_)) {
-    CallOpBuffer buf;
-    buf.AddSendInitialMetadata(&context->send_initial_metadata_);
-    call_.PerformOps(&buf);
-    cq_.Pluck(&buf);
+               ClientContext* context, R* response)
+      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+    finish_ops_.RecvMessage(response);
+
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
-    buf.AddSendMessage(msg);
-    call_.PerformOps(&buf);
-    return cq_.Pluck(&buf);
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
   }
 
   bool WritesDone() GRPC_OVERRIDE {
-    CallOpBuffer buf;
-    buf.AddClientSendClose();
-    call_.PerformOps(&buf);
-    return cq_.Pluck(&buf);
+    CallOpSet<CallOpClientSendClose> ops;
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
   }
 
   // Read the final response and wait for the final status.
   Status Finish() GRPC_OVERRIDE {
-    CallOpBuffer buf;
     Status status;
-    buf.AddRecvMessage(response_);
-    buf.AddClientRecvStatus(context_, &status);
-    call_.PerformOps(&buf);
-    GPR_ASSERT(cq_.Pluck(&buf));
+    finish_ops_.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&finish_ops_);
+    GPR_ASSERT(cq_.Pluck(&finish_ops_));
     return status;
   }
 
  private:
   ClientContext* context_;
-  grpc::protobuf::Message* const response_;
+  CallOpSet<CallOpGenericRecvMessage, CallOpClientRecvStatus> finish_ops_;
   CompletionQueue cq_;
   Call call_;
 };
@@ -213,10 +222,10 @@
   ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
                      ClientContext* context)
       : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
-    CallOpBuffer buf;
-    buf.AddSendInitialMetadata(&context->send_initial_metadata_);
-    call_.PerformOps(&buf);
-    cq_.Pluck(&buf);
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
   }
 
   // Blocking wait for initial metadata from server. The received metadata
@@ -226,42 +235,43 @@
   void WaitForInitialMetadata() {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    CallOpBuffer buf;
-    buf.AddRecvInitialMetadata(context_);
-    call_.PerformOps(&buf);
-    cq_.Pluck(&buf);  // status ignored
+    CallOpSet<CallOpRecvInitialMetadata> ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  // status ignored
   }
 
   bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
+    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops;
     if (!context_->initial_metadata_received_) {
-      buf.AddRecvInitialMetadata(context_);
+      ops.RecvInitialMetadata(context_);
     }
-    buf.AddRecvMessage(msg);
-    call_.PerformOps(&buf);
-    return cq_.Pluck(&buf) && buf.got_message;
+    ops.RecvMessage(msg);
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops) && ops.got_message;
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
-    buf.AddSendMessage(msg);
-    call_.PerformOps(&buf);
-    return cq_.Pluck(&buf);
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) return false;
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
   }
 
   bool WritesDone() GRPC_OVERRIDE {
-    CallOpBuffer buf;
-    buf.AddClientSendClose();
-    call_.PerformOps(&buf);
-    return cq_.Pluck(&buf);
+    CallOpSet<CallOpClientSendClose> ops;
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
   }
 
   Status Finish() GRPC_OVERRIDE {
-    CallOpBuffer buf;
+    CallOpSet<CallOpClientRecvStatus> ops;
     Status status;
-    buf.AddClientRecvStatus(context_, &status);
-    call_.PerformOps(&buf);
-    GPR_ASSERT(cq_.Pluck(&buf));
+    ops.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&ops);
+    GPR_ASSERT(cq_.Pluck(&ops));
     return status;
   }
 
@@ -279,18 +289,18 @@
   void SendInitialMetadata() {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    CallOpBuffer buf;
-    buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&buf);
-    call_->cq()->Pluck(&buf);
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
   }
 
   bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
-    buf.AddRecvMessage(msg);
-    call_->PerformOps(&buf);
-    return call_->cq()->Pluck(&buf) && buf.got_message;
+    CallOpSet<CallOpRecvMessage<R>> ops;
+    ops.RecvMessage(msg);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops) && ops.got_message;
   }
 
  private:
@@ -306,22 +316,25 @@
   void SendInitialMetadata() {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    CallOpBuffer buf;
-    buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&buf);
-    call_->cq()->Pluck(&buf);
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
     if (!ctx_->sent_initial_metadata_) {
-      buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      ops.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    buf.AddSendMessage(msg);
-    call_->PerformOps(&buf);
-    return call_->cq()->Pluck(&buf);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops);
   }
 
  private:
@@ -339,29 +352,32 @@
   void SendInitialMetadata() {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    CallOpBuffer buf;
-    buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&buf);
-    call_->cq()->Pluck(&buf);
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
   }
 
   bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
-    buf.AddRecvMessage(msg);
-    call_->PerformOps(&buf);
-    return call_->cq()->Pluck(&buf) && buf.got_message;
+    CallOpSet<CallOpRecvMessage<R>> ops;
+    ops.RecvMessage(msg);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops) && ops.got_message;
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
-    CallOpBuffer buf;
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
     if (!ctx_->sent_initial_metadata_) {
-      buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      ops.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    buf.AddSendMessage(msg);
-    call_->PerformOps(&buf);
-    return call_->cq()->Pluck(&buf);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops);
   }
 
  private:
@@ -400,57 +416,59 @@
 
 template <class R>
 class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface,
-                                   public AsyncReaderInterface<R> {
-};
+                                   public AsyncReaderInterface<R> {};
 
 template <class R>
 class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> {
  public:
   // Create a stream and write the first request out.
+  template <class W>
   ClientAsyncReader(ChannelInterface* channel, CompletionQueue* cq,
                     const RpcMethod& method, ClientContext* context,
-                    const grpc::protobuf::Message& request, void* tag)
+                    const W& request, void* tag)
       : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_buf_.Reset(tag);
-    init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
-    init_buf_.AddSendMessage(request);
-    init_buf_.AddClientSendClose();
-    call_.PerformOps(&init_buf_);
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(init_ops_.SendMessage(request).ok());
+    init_ops_.ClientSendClose();
+    call_.PerformOps(&init_ops_);
   }
 
   void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddRecvInitialMetadata(context_);
-    call_.PerformOps(&meta_buf_);
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
   }
 
   void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_buf_.Reset(tag);
+    read_ops_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      read_buf_.AddRecvInitialMetadata(context_);
+      read_ops_.RecvInitialMetadata(context_);
     }
-    read_buf_.AddRecvMessage(msg);
-    call_.PerformOps(&read_buf_);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
   }
 
   void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      finish_buf_.AddRecvInitialMetadata(context_);
+      finish_ops_.RecvInitialMetadata(context_);
     }
-    finish_buf_.AddClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_buf_);
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
   }
 
  private:
   ClientContext* context_;
   Call call_;
-  CallOpBuffer init_buf_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer read_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
+      init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
 };
 
 template <class W>
@@ -463,56 +481,57 @@
 template <class W>
 class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> {
  public:
+  template <class R>
   ClientAsyncWriter(ChannelInterface* channel, CompletionQueue* cq,
                     const RpcMethod& method, ClientContext* context,
-                    grpc::protobuf::Message* response, void* tag)
-      : context_(context),
-        response_(response),
-        call_(channel->CreateCall(method, context, cq)) {
-    init_buf_.Reset(tag);
-    init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
-    call_.PerformOps(&init_buf_);
+                    R* response, void* tag)
+      : context_(context), call_(channel->CreateCall(method, context, cq)) {
+    finish_ops_.RecvMessage(response);
+
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&init_ops_);
   }
 
   void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddRecvInitialMetadata(context_);
-    call_.PerformOps(&meta_buf_);
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
   }
 
   void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_buf_.Reset(tag);
-    write_buf_.AddSendMessage(msg);
-    call_.PerformOps(&write_buf_);
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
   }
 
   void WritesDone(void* tag) GRPC_OVERRIDE {
-    writes_done_buf_.Reset(tag);
-    writes_done_buf_.AddClientSendClose();
-    call_.PerformOps(&writes_done_buf_);
+    writes_done_ops_.set_output_tag(tag);
+    writes_done_ops_.ClientSendClose();
+    call_.PerformOps(&writes_done_ops_);
   }
 
   void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      finish_buf_.AddRecvInitialMetadata(context_);
+      finish_ops_.RecvInitialMetadata(context_);
     }
-    finish_buf_.AddRecvMessage(response_);
-    finish_buf_.AddClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_buf_);
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
   }
 
  private:
   ClientContext* context_;
-  grpc::protobuf::Message* const response_;
   Call call_;
-  CallOpBuffer init_buf_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer write_buf_;
-  CallOpBuffer writes_done_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata> init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpClientSendClose> writes_done_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
+            CallOpClientRecvStatus> finish_ops_;
 };
 
 // Client-side interface for bi-directional streaming.
@@ -532,58 +551,59 @@
                           const RpcMethod& method, ClientContext* context,
                           void* tag)
       : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_buf_.Reset(tag);
-    init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
-    call_.PerformOps(&init_buf_);
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&init_ops_);
   }
 
   void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddRecvInitialMetadata(context_);
-    call_.PerformOps(&meta_buf_);
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
   }
 
   void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_buf_.Reset(tag);
+    read_ops_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      read_buf_.AddRecvInitialMetadata(context_);
+      read_ops_.RecvInitialMetadata(context_);
     }
-    read_buf_.AddRecvMessage(msg);
-    call_.PerformOps(&read_buf_);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
   }
 
   void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_buf_.Reset(tag);
-    write_buf_.AddSendMessage(msg);
-    call_.PerformOps(&write_buf_);
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
   }
 
   void WritesDone(void* tag) GRPC_OVERRIDE {
-    writes_done_buf_.Reset(tag);
-    writes_done_buf_.AddClientSendClose();
-    call_.PerformOps(&writes_done_buf_);
+    writes_done_ops_.set_output_tag(tag);
+    writes_done_ops_.ClientSendClose();
+    call_.PerformOps(&writes_done_ops_);
   }
 
   void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      finish_buf_.AddRecvInitialMetadata(context_);
+      finish_ops_.RecvInitialMetadata(context_);
     }
-    finish_buf_.AddClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_buf_);
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
   }
 
  private:
   ClientContext* context_;
   Call call_;
-  CallOpBuffer init_buf_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer read_buf_;
-  CallOpBuffer write_buf_;
-  CallOpBuffer writes_done_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata> init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpClientSendClose> writes_done_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
 };
 
 template <class W, class R>
@@ -596,41 +616,44 @@
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_buf_);
+    call_.PerformOps(&meta_ops_);
   }
 
   void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_buf_.Reset(tag);
-    read_buf_.AddRecvMessage(msg);
-    call_.PerformOps(&read_buf_);
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
   }
 
   void Finish(const W& msg, const Status& status, void* tag) {
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
     // The response is dropped if the status is not OK.
     if (status.ok()) {
-      finish_buf_.AddSendMessage(msg);
+      finish_ops_.ServerSendStatus(
+          ctx_->trailing_metadata_,
+          finish_ops_.SendMessage(msg));
+    } else {
+      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
     }
-    finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_buf_);
+    call_.PerformOps(&finish_ops_);
   }
 
   void FinishWithError(const Status& status, void* tag) {
     GPR_ASSERT(!status.ok());
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_buf_);
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
   }
 
  private:
@@ -638,9 +661,10 @@
 
   Call call_;
   ServerContext* ctx_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer read_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpServerSendStatus> finish_ops_;
 };
 
 template <class W>
@@ -653,30 +677,31 @@
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_buf_);
+    call_.PerformOps(&meta_ops_);
   }
 
   void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_buf_.Reset(tag);
+    write_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      write_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    write_buf_.AddSendMessage(msg);
-    call_.PerformOps(&write_buf_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
   }
 
   void Finish(const Status& status, void* tag) {
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_buf_);
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
   }
 
  private:
@@ -684,9 +709,9 @@
 
   Call call_;
   ServerContext* ctx_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer write_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
 };
 
 // Server-side interface for bi-directional streaming.
@@ -701,36 +726,37 @@
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
     GPR_ASSERT(!ctx_->sent_initial_metadata_);
 
-    meta_buf_.Reset(tag);
-    meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
     ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_buf_);
+    call_.PerformOps(&meta_ops_);
   }
 
   void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_buf_.Reset(tag);
-    read_buf_.AddRecvMessage(msg);
-    call_.PerformOps(&read_buf_);
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
   }
 
   void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_buf_.Reset(tag);
+    write_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      write_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    write_buf_.AddSendMessage(msg);
-    call_.PerformOps(&write_buf_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
   }
 
   void Finish(const Status& status, void* tag) {
-    finish_buf_.Reset(tag);
+    finish_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
       ctx_->sent_initial_metadata_ = true;
     }
-    finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_buf_);
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
   }
 
  private:
@@ -738,10 +764,10 @@
 
   Call call_;
   ServerContext* ctx_;
-  CallOpBuffer meta_buf_;
-  CallOpBuffer read_buf_;
-  CallOpBuffer write_buf_;
-  CallOpBuffer finish_buf_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/thread_pool_interface.h b/include/grpc++/thread_pool_interface.h
index ead307f..d080b31 100644
--- a/include/grpc++/thread_pool_interface.h
+++ b/include/grpc++/thread_pool_interface.h
@@ -44,9 +44,11 @@
   virtual ~ThreadPoolInterface() {}
 
   // Schedule the given callback for execution.
-  virtual void ScheduleCallback(const std::function<void()>& callback) = 0;
+  virtual void Add(const std::function<void()>& callback) = 0;
 };
 
+ThreadPoolInterface* CreateDefaultThreadPool();
+
 }  // namespace grpc
 
 #endif  // GRPCXX_THREAD_POOL_INTERFACE_H
diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h
index 6d08474..913e2a7 100644
--- a/include/grpc/byte_buffer.h
+++ b/include/grpc/byte_buffer.h
@@ -85,7 +85,6 @@
 /** Destroys \a byte_buffer deallocating all its memory. */
 void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
 
-
 /** Reader for byte buffers. Iterates over slices in the byte buffer */
 struct grpc_byte_buffer_reader;
 typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
@@ -103,8 +102,12 @@
 int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
                                  gpr_slice *slice);
 
+/** Returns a RAW byte buffer instance from the output of \a reader. */
+grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
+    grpc_byte_buffer_reader *reader);
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif  /* GRPC_BYTE_BUFFER_H */
+#endif /* GRPC_BYTE_BUFFER_H */
diff --git a/include/grpc/byte_buffer_reader.h b/include/grpc/byte_buffer_reader.h
index 1ef817c..b0e63a6 100644
--- a/include/grpc/byte_buffer_reader.h
+++ b/include/grpc/byte_buffer_reader.h
@@ -55,4 +55,4 @@
 }
 #endif
 
-#endif  /* GRPC_BYTE_BUFFER_READER_H */
+#endif /* GRPC_BYTE_BUFFER_READER_H */
diff --git a/include/grpc/census.h b/include/grpc/census.h
index b2049b3..3fc07af 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -61,6 +61,10 @@
 int census_initialize(int functions);
 void census_shutdown();
 
+/* If any census feature has been initialized, this funtion will return a
+ * non-zero value. */
+int census_available();
+
 /* Internally, Census relies on a context, which should be propagated across
  * RPC's. From the RPC subsystems viewpoint, this is an opaque data structure.
  * A context must be used as the first argument to all other census
diff --git a/include/grpc/compression.h b/include/grpc/compression.h
index 207898f..913e553 100644
--- a/include/grpc/compression.h
+++ b/include/grpc/compression.h
@@ -34,8 +34,12 @@
 #ifndef GRPC_COMPRESSION_H
 #define GRPC_COMPRESSION_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** To be used in channel arguments */
-#define GRPC_COMPRESSION_LEVEL_ARG "grpc.compression_level"
+#define GRPC_COMPRESSION_ALGORITHM_ARG "grpc.compression_algorithm"
 
 /* The various compression algorithms supported by GRPC */
 typedef enum {
@@ -50,13 +54,34 @@
   GRPC_COMPRESS_LEVEL_NONE = 0,
   GRPC_COMPRESS_LEVEL_LOW,
   GRPC_COMPRESS_LEVEL_MED,
-  GRPC_COMPRESS_LEVEL_HIGH
+  GRPC_COMPRESS_LEVEL_HIGH,
+  GRPC_COMPRESS_LEVEL_COUNT
 } grpc_compression_level;
 
-const char *grpc_compression_algorithm_name(
+/** Parses \a name as a grpc_compression_algorithm instance, updating \a
+ * algorithm. Returns 1 upon success, 0 otherwise. */
+int grpc_compression_algorithm_parse(const char *name,
+                                     grpc_compression_algorithm *algorithm);
+
+/** Updates \a name with the encoding name corresponding to a valid \a
+ * algorithm.  Returns 1 upon success, 0 otherwise. */
+int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
+                                    char **name);
+
+/** Returns the compression level corresponding to \a algorithm.
+ *
+ * It abort()s for unknown algorithms. */
+grpc_compression_level grpc_compression_level_for_algorithm(
     grpc_compression_algorithm algorithm);
 
+/** Returns the compression algorithm corresponding to \a level.
+ *
+ * It abort()s for unknown levels . */
 grpc_compression_algorithm grpc_compression_algorithm_for_level(
     grpc_compression_level level);
 
-#endif  /* GRPC_COMPRESSION_H */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_COMPRESSION_H */
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 722ce4f..686984f 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -45,40 +45,49 @@
 extern "C" {
 #endif
 
-/* Completion Queues enable notification of the completion of asynchronous
-   actions. */
+/*! \mainpage GRPC Core
+ *
+ * \section intro_sec The GRPC Core library is a low-level library designed
+ * to be wrapped by higher level libraries.
+ *
+ * The top-level API is provided in grpc.h. 
+ * Security related functionality lives in grpc_security.h.
+ */
+
+/** Completion Queues enable notification of the completion of asynchronous
+    actions. */
 typedef struct grpc_completion_queue grpc_completion_queue;
 
-/* The Channel interface allows creation of Call objects. */
+/** The Channel interface allows creation of Call objects. */
 typedef struct grpc_channel grpc_channel;
 
-/* A server listens to some port and responds to request calls */
+/** A server listens to some port and responds to request calls */
 typedef struct grpc_server grpc_server;
 
-/* A Call represents an RPC. When created, it is in a configuration state
-   allowing properties to be set until it is invoked. After invoke, the Call
-   can have messages written to it and read from it. */
+/** A Call represents an RPC. When created, it is in a configuration state
+    allowing properties to be set until it is invoked. After invoke, the Call
+    can have messages written to it and read from it. */
 typedef struct grpc_call grpc_call;
 
-/* Type specifier for grpc_arg */
+/** Type specifier for grpc_arg */
 typedef enum {
   GRPC_ARG_STRING,
   GRPC_ARG_INTEGER,
   GRPC_ARG_POINTER
 } grpc_arg_type;
 
-/* A single argument... each argument has a key and a value
+/** A single argument... each argument has a key and a value
 
-   A note on naming keys:
-     Keys are namespaced into groups, usually grouped by library, and are
-     keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
-     be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
-     Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
+    A note on naming keys:
+      Keys are namespaced into groups, usually grouped by library, and are
+      keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
+      be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
+      Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
 
-     GRPC core library keys are prefixed by grpc.
+    GRPC core library keys are prefixed by grpc.
 
-     Library authors are strongly encouraged to #define symbolic constants for
-     their keys so that it's possible to change them in the future. */
+    Library authors are strongly encouraged to \#define symbolic constants for
+    their keys so that it's possible to change them in the future. */
 typedef struct {
   grpc_arg_type type;
   char *key;
@@ -107,67 +116,84 @@
 } grpc_channel_args;
 
 /* Channel argument keys: */
-/* Enable census for tracing and stats collection */
+/** Enable census for tracing and stats collection */
 #define GRPC_ARG_ENABLE_CENSUS "grpc.census"
-/* Maximum number of concurrent incoming streams to allow on a http2
-   connection */
+/** Maximum number of concurrent incoming streams to allow on a http2
+    connection */
 #define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
-/* Maximum message length that the channel can receive */
+/** Maximum message length that the channel can receive */
 #define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
-/* Initial sequence number for http2 transports */
+/** Initial sequence number for http2 transports */
 #define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
   "grpc.http2.initial_sequence_number"
 
-/* Result of a grpc call. If the caller satisfies the prerequisites of a
-   particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
-   Receiving any other value listed here is an indication of a bug in the
-   caller. */
+/** Connectivity state of a channel. */
+typedef enum {
+  /** channel is idle */
+  GRPC_CHANNEL_IDLE,
+  /** channel is connecting */
+  GRPC_CHANNEL_CONNECTING,
+  /** channel is ready for work */
+  GRPC_CHANNEL_READY,
+  /** channel has seen a failure but expects to recover */
+  GRPC_CHANNEL_TRANSIENT_FAILURE,
+  /** channel has seen a failure that it cannot recover from */
+  GRPC_CHANNEL_FATAL_FAILURE
+} grpc_connectivity_state;
+
+/** Result of a grpc call. If the caller satisfies the prerequisites of a
+    particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
+    Receiving any other value listed here is an indication of a bug in the
+    caller. */
 typedef enum grpc_call_error {
-  /* everything went ok */
+  /** everything went ok */
   GRPC_CALL_OK = 0,
-  /* something failed, we don't know what */
+  /** something failed, we don't know what */
   GRPC_CALL_ERROR,
-  /* this method is not available on the server */
+  /** this method is not available on the server */
   GRPC_CALL_ERROR_NOT_ON_SERVER,
-  /* this method is not available on the client */
+  /** this method is not available on the client */
   GRPC_CALL_ERROR_NOT_ON_CLIENT,
-  /* this method must be called before server_accept */
+  /** this method must be called before server_accept */
   GRPC_CALL_ERROR_ALREADY_ACCEPTED,
-  /* this method must be called before invoke */
+  /** this method must be called before invoke */
   GRPC_CALL_ERROR_ALREADY_INVOKED,
-  /* this method must be called after invoke */
+  /** this method must be called after invoke */
   GRPC_CALL_ERROR_NOT_INVOKED,
-  /* this call is already finished
-     (writes_done or write_status has already been called) */
+  /** this call is already finished
+      (writes_done or write_status has already been called) */
   GRPC_CALL_ERROR_ALREADY_FINISHED,
-  /* there is already an outstanding read/write operation on the call */
+  /** there is already an outstanding read/write operation on the call */
   GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
-  /* the flags value was illegal for this call */
+  /** the flags value was illegal for this call */
   GRPC_CALL_ERROR_INVALID_FLAGS,
-  /* invalid metadata was passed to this call */
-  GRPC_CALL_ERROR_INVALID_METADATA
+  /** invalid metadata was passed to this call */
+  GRPC_CALL_ERROR_INVALID_METADATA,
+  /** completion queue for notification has not been registered with the 
+      server */
+  GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE
 } grpc_call_error;
 
 /* Write Flags: */
-/* Hint that the write may be buffered and need not go out on the wire
-   immediately. GRPC is free to buffer the message until the next non-buffered
-   write, or until writes_done, but it need not buffer completely or at all. */
+/** Hint that the write may be buffered and need not go out on the wire
+    immediately. GRPC is free to buffer the message until the next non-buffered
+    write, or until writes_done, but it need not buffer completely or at all. */
 #define GRPC_WRITE_BUFFER_HINT (0x00000001u)
-/* Force compression to be disabled for a particular write
-   (start_write/add_metadata). Illegal on invoke/accept. */
+/** Force compression to be disabled for a particular write
+    (start_write/add_metadata). Illegal on invoke/accept. */
 #define GRPC_WRITE_NO_COMPRESS (0x00000002u)
-/* Mask of all valid flags. */
+/** Mask of all valid flags. */
 #define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS)
 
-/* A single metadata element */
+/** A single metadata element */
 typedef struct grpc_metadata {
   const char *key;
   const char *value;
   size_t value_length;
 
-  /* 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. */
+  /** 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];
   } internal_data;
@@ -218,42 +244,41 @@
 void grpc_call_details_destroy(grpc_call_details *details);
 
 typedef enum {
-  /* Send initial metadata: one and only one instance MUST be sent for each
-     call,
-     unless the call was cancelled - in which case this can be skipped */
+  /** Send initial metadata: one and only one instance MUST be sent for each
+      call, unless the call was cancelled - in which case this can be skipped */
   GRPC_OP_SEND_INITIAL_METADATA = 0,
-  /* Send a message: 0 or more of these operations can occur for each call */
+  /** Send a message: 0 or more of these operations can occur for each call */
   GRPC_OP_SEND_MESSAGE,
-  /* Send a close from the client: one and only one instance MUST be sent from
-     the client,
-     unless the call was cancelled - in which case this can be skipped */
+  /** Send a close from the client: one and only one instance MUST be sent from
+      the client, unless the call was cancelled - in which case this can be 
+      skipped */
   GRPC_OP_SEND_CLOSE_FROM_CLIENT,
-  /* Send status from the server: one and only one instance MUST be sent from
-     the server
-     unless the call was cancelled - in which case this can be skipped */
+  /** Send status from the server: one and only one instance MUST be sent from
+      the server unless the call was cancelled - in which case this can be 
+      skipped */
   GRPC_OP_SEND_STATUS_FROM_SERVER,
-  /* Receive initial metadata: one and only one MUST be made on the client, must
-     not be made on the server */
+  /** Receive initial metadata: one and only one MUST be made on the client, 
+      must not be made on the server */
   GRPC_OP_RECV_INITIAL_METADATA,
-  /* Receive a message: 0 or more of these operations can occur for each call */
+  /** Receive a message: 0 or more of these operations can occur for each call */
   GRPC_OP_RECV_MESSAGE,
-  /* Receive status on the client: one and only one must be made on the client.
+  /** Receive status on the client: one and only one must be made on the client.
      This operation always succeeds, meaning ops paired with this operation
      will also appear to succeed, even though they may not have. In that case
-     the status will indicate some failure.
-     */
+     the status will indicate some failure. */
   GRPC_OP_RECV_STATUS_ON_CLIENT,
-  /* Receive close on the server: one and only one must be made on the server
-     */
+  /** Receive close on the server: one and only one must be made on the 
+      server */
   GRPC_OP_RECV_CLOSE_ON_SERVER
 } grpc_op_type;
 
-/* Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
-   which has
-   no arguments) */
+/** Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
+   which has no arguments) */
 typedef struct grpc_op {
+  /** Operation type, as defined by grpc_op_type */
   grpc_op_type op;
-  gpr_uint32 flags;  /**< Write flags bitset for grpc_begin_messages */
+  /** Write flags bitset for grpc_begin_messages */
+  gpr_uint32 flags; 
   union {
     struct {
       size_t count;
@@ -266,53 +291,49 @@
       grpc_status_code status;
       const char *status_details;
     } send_status_from_server;
-    /* ownership of the array is with the caller, but ownership of the elements
-       stays with the call object (ie key, value members are owned by the call
-       object, recv_initial_metadata->array is owned by the caller).
-       After the operation completes, call grpc_metadata_array_destroy on this
-       value, or reuse it in a future op. */
+    /** ownership of the array is with the caller, but ownership of the elements
+        stays with the call object (ie key, value members are owned by the call
+        object, recv_initial_metadata->array is owned by the caller).
+        After the operation completes, call grpc_metadata_array_destroy on this
+        value, or reuse it in a future op. */
     grpc_metadata_array *recv_initial_metadata;
-    /* ownership of the byte buffer is moved to the caller; the caller must call
-       grpc_byte_buffer_destroy on this value, or reuse it in a future op. */
+    /** ownership of the byte buffer is moved to the caller; the caller must call
+        grpc_byte_buffer_destroy on this value, or reuse it in a future op. */
     grpc_byte_buffer **recv_message;
     struct {
-      /* ownership of the array is with the caller, but ownership of the
-         elements
-         stays with the call object (ie key, value members are owned by the call
-         object, trailing_metadata->array is owned by the caller).
-         After the operation completes, call grpc_metadata_array_destroy on this
-         value, or reuse it in a future op. */
+      /** ownership of the array is with the caller, but ownership of the
+          elements stays with the call object (ie key, value members are owned 
+          by the call object, trailing_metadata->array is owned by the caller).
+          After the operation completes, call grpc_metadata_array_destroy on this
+          value, or reuse it in a future op. */
       grpc_metadata_array *trailing_metadata;
       grpc_status_code *status;
-      /* status_details is a buffer owned by the application before the op
-         completes
-         and after the op has completed. During the operation status_details may
-         be
-         reallocated to a size larger than *status_details_capacity, in which
-         case
-         *status_details_capacity will be updated with the new array capacity.
+      /** status_details is a buffer owned by the application before the op
+          completes and after the op has completed. During the operation
+          status_details may be reallocated to a size larger than 
+          *status_details_capacity, in which case *status_details_capacity will 
+          be updated with the new array capacity.
 
-         Pre-allocating space:
-         size_t my_capacity = 8;
-         char *my_details = gpr_malloc(my_capacity);
-         x.status_details = &my_details;
-         x.status_details_capacity = &my_capacity;
+          Pre-allocating space:
+          size_t my_capacity = 8;
+          char *my_details = gpr_malloc(my_capacity);
+          x.status_details = &my_details;
+          x.status_details_capacity = &my_capacity;
 
-         Not pre-allocating space:
-         size_t my_capacity = 0;
-         char *my_details = NULL;
-         x.status_details = &my_details;
-         x.status_details_capacity = &my_capacity;
+          Not pre-allocating space:
+          size_t my_capacity = 0;
+          char *my_details = NULL;
+          x.status_details = &my_details;
+          x.status_details_capacity = &my_capacity;
 
-         After the call:
-         gpr_free(my_details); */
+          After the call:
+          gpr_free(my_details); */
       char **status_details;
       size_t *status_details_capacity;
     } recv_status_on_client;
     struct {
-      /* out argument, set to 1 if the call failed in any way (seen as a
-         cancellation
-         on the server), or 0 if the call succeeded */
+      /** out argument, set to 1 if the call failed in any way (seen as a
+          cancellation on the server), or 0 if the call succeeded */
       int *cancelled;
     } recv_close_on_server;
   } data;
@@ -334,11 +355,14 @@
     destroyed. */
 void grpc_shutdown(void);
 
+/** Return a string representing the current version of grpc */
+const char *grpc_version_string(void);
+
 /** Create a completion queue */
 grpc_completion_queue *grpc_completion_queue_create(void);
 
 /** Blocks until an event is available, the completion queue is being shut down,
-    or deadline is reached. 
+    or deadline is reached.
 
     Returns a grpc_event with type GRPC_QUEUE_TIMEOUT on timeout,
     otherwise a grpc_event describing the event that occurred.
@@ -349,7 +373,7 @@
                                       gpr_timespec deadline);
 
 /** Blocks until an event with tag 'tag' is available, the completion queue is
-    being shutdown or deadline is reached. 
+    being shutdown or deadline is reached.
 
     Returns a grpc_event with type GRPC_QUEUE_TIMEOUT on timeout,
     otherwise a grpc_event describing the event that occurred.
@@ -359,111 +383,113 @@
 grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
                                        gpr_timespec deadline);
 
-/* Begin destruction of a completion queue. Once all possible events are
-   drained then grpc_completion_queue_next will start to produce
-   GRPC_QUEUE_SHUTDOWN events only. At that point it's safe to call
-   grpc_completion_queue_destroy.
+/** Begin destruction of a completion queue. Once all possible events are
+    drained then grpc_completion_queue_next will start to produce
+    GRPC_QUEUE_SHUTDOWN events only. At that point it's safe to call
+    grpc_completion_queue_destroy.
 
-   After calling this function applications should ensure that no
-   NEW work is added to be published on this completion queue. */
+    After calling this function applications should ensure that no
+    NEW work is added to be published on this completion queue. */
 void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
 
-/* Destroy a completion queue. The caller must ensure that the queue is
-   drained and no threads are executing grpc_completion_queue_next */
+/** Destroy a completion queue. The caller must ensure that the queue is
+    drained and no threads are executing grpc_completion_queue_next */
 void grpc_completion_queue_destroy(grpc_completion_queue *cq);
 
-/* Create a call given a grpc_channel, in order to call 'method'. The request
-   is not sent until grpc_call_invoke is called. All completions are sent to
-   'completion_queue'. 'method' and 'host' need only live through the invocation
-   of this function. */
+/** Create a call given a grpc_channel, in order to call 'method'. All
+    completions are sent to 'completion_queue'. 'method' and 'host' need only
+    live through the invocation of this function. */
 grpc_call *grpc_channel_create_call(grpc_channel *channel,
                                     grpc_completion_queue *completion_queue,
                                     const char *method, const char *host,
                                     gpr_timespec deadline);
 
-/* Pre-register a method/host pair on a channel. */
+/** Pre-register a method/host pair on a channel. */
 void *grpc_channel_register_call(grpc_channel *channel, const char *method,
                                  const char *host);
 
-/* Create a call given a handle returned from grpc_channel_register_call */
+/** Create a call given a handle returned from grpc_channel_register_call */
 grpc_call *grpc_channel_create_registered_call(
     grpc_channel *channel, grpc_completion_queue *completion_queue,
     void *registered_call_handle, gpr_timespec deadline);
 
-/* 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.
-   The order of ops specified in the batch has no significance.
-   Only one operation of each type can be active at once in any given
-   batch. */
+/** 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.
+    The order of ops specified in the batch has no significance.
+    Only one operation of each type can be active at once in any given
+    batch. You must call grpc_completion_queue_next or
+    grpc_completion_queue_pluck on the completion queue associated with 'call'
+    for work to be performed.
+    THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
+    needs to be synchronized. As an optimization, you may synchronize batches
+    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);
 
-/* Create a client channel to 'target'. Additional channel level configuration
-   MAY be provided by grpc_channel_args, though the expectation is that most
-   clients will want to simply pass NULL. See grpc_channel_args definition for
-   more on this. The data in 'args' need only live through the invocation of
-   this function. */
+/** Create a client channel to 'target'. Additional channel level configuration
+    MAY be provided by grpc_channel_args, though the expectation is that most
+    clients will want to simply pass NULL. See grpc_channel_args definition for
+    more on this. The data in 'args' need only live through the invocation of
+    this function. */
 grpc_channel *grpc_channel_create(const char *target,
                                   const grpc_channel_args *args);
 
-/* Create a lame client: this client fails every operation attempted on it. */
+/** Create a lame client: this client fails every operation attempted on it. */
 grpc_channel *grpc_lame_client_channel_create(void);
 
-/* Close and destroy a grpc channel */
+/** Close and destroy a grpc channel */
 void grpc_channel_destroy(grpc_channel *channel);
 
-/* THREAD-SAFETY for grpc_call
-   The following functions are thread-compatible for any given call:
-     grpc_call_add_metadata
-     grpc_call_invoke
-     grpc_call_start_write
-     grpc_call_writes_done
-     grpc_call_start_read
-     grpc_call_destroy
-   The function grpc_call_cancel is thread-safe, and can be called at any
-   point before grpc_call_destroy is called. */
-
 /* Error handling for grpc_call
    Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
    then the operation failed due to some unsatisfied precondition.
    If a grpc_call fails, it's guaranteed that no change to the call state
    has been made. */
 
-/* Called by clients to cancel an RPC on the server.
-   Can be called multiple times, from any thread. */
+/** Called by clients to cancel an RPC on the server.
+    Can be called multiple times, from any thread.
+    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);
 
-/* Called by clients to cancel an RPC on the server.
-   Can be called multiple times, from any thread.
-   If a status has not been received for the call, set it to the status code
-   and description passed in.
-   Importantly, this function does not send status nor description to the
-   remote endpoint. */
+/** Called by clients to cancel an RPC on the server.
+    Can be called multiple times, from any thread.
+    If a status has not been received for the call, set it to the status code
+    and description passed in.
+    Importantly, this function does not send status nor description to the
+    remote endpoint. */
 grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
                                              grpc_status_code status,
                                              const char *description);
 
-/* Destroy a call. */
+/** Destroy a call.
+    THREAD SAFETY: grpc_call_destroy is thread-compatible */
 void grpc_call_destroy(grpc_call *call);
 
-/* Request notification of a new call */
+/** Request notification of a new call. 'cq_for_notification' must
+    have been registered to the server via 
+    grpc_server_register_completion_queue. */
 grpc_call_error grpc_server_request_call(
     grpc_server *server, grpc_call **call, grpc_call_details *details,
     grpc_metadata_array *request_metadata,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag_new);
 
-/* Registers a method in the server.
-   Methods to this (host, method) pair will not be reported by
-   grpc_server_request_call, but instead be reported by
-   grpc_server_request_registered_call when passed the appropriate
-   registered_method (as returned by this function).
-   Must be called before grpc_server_start.
-   Returns NULL on failure. */
+/** Registers a method in the server.
+    Methods to this (host, method) pair will not be reported by
+    grpc_server_request_call, but instead be reported by
+    grpc_server_request_registered_call when passed the appropriate
+    registered_method (as returned by this function).
+    Must be called before grpc_server_start.
+    Returns NULL on failure. */
 void *grpc_server_register_method(grpc_server *server, const char *method,
                                   const char *host);
 
-/* Request notification of a new pre-registered call */
+/** Request notification of a new pre-registered call. 'cq_for_notification' 
+    must have been registered to the server via 
+    grpc_server_register_completion_queue. */
 grpc_call_error grpc_server_request_registered_call(
     grpc_server *server, void *registered_method, grpc_call **call,
     gpr_timespec *deadline, grpc_metadata_array *request_metadata,
@@ -471,52 +497,54 @@
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag_new);
 
-/* Create a server. Additional configuration for each incoming channel can
-   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. */
+/** Create a server. Additional configuration for each incoming channel can
+    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);
 
-/* Register a completion queue with the server. Must be done for any completion
-   queue that is passed to grpc_server_request_* call. Must be performed prior
-   to grpc_server_start. */
+/** 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);
 
-/* Add a HTTP2 over plaintext over tcp listener.
-   Returns bound port number on success, 0 on failure.
-   REQUIRES: server not started */
+/** Add a HTTP2 over plaintext over tcp listener.
+    Returns bound port number on success, 0 on failure.
+    REQUIRES: server not started */
 int grpc_server_add_http2_port(grpc_server *server, const char *addr);
 
-/* Start a server - tells all listeners to start listening */
+/** Start a server - tells all listeners to start listening */
 void grpc_server_start(grpc_server *server);
 
-/* Begin shutting down a server.
-   After completion, no new calls or connections will be admitted.
-   Existing calls will be allowed to complete.
-   Send a GRPC_OP_COMPLETE event when there are no more calls being serviced.
-   Shutdown is idempotent, and all tags will be notified at once if multiple
-   grpc_server_shutdown_and_notify calls are made. */
+/** Begin shutting down a server.
+    After completion, no new calls or connections will be admitted.
+    Existing calls will be allowed to complete.
+    Send a GRPC_OP_COMPLETE event when there are no more calls being serviced.
+    Shutdown is idempotent, and all tags will be notified at once if multiple
+    grpc_server_shutdown_and_notify calls are made. 'cq' must have been
+    registered to this server via grpc_server_register_completion_queue. */
 void grpc_server_shutdown_and_notify(grpc_server *server,
                                      grpc_completion_queue *cq, void *tag);
 
-/* Cancel all in-progress calls.
-   Only usable after shutdown. */
+/** Cancel all in-progress calls.
+    Only usable after shutdown. */
 void grpc_server_cancel_all_calls(grpc_server *server);
 
-/* Destroy a server.
-   Shutdown must have completed beforehand (i.e. all tags generated by
-   grpc_server_shutdown_and_notify must have been received, and at least
-   one call to grpc_server_shutdown_and_notify must have been made). */
+/** Destroy a server.
+    Shutdown must have completed beforehand (i.e. all tags generated by
+    grpc_server_shutdown_and_notify must have been received, and at least
+    one call to grpc_server_shutdown_and_notify must have been made). */
 void grpc_server_destroy(grpc_server *server);
 
 /** Enable or disable a tracer.
 
     Tracers (usually controlled by the environment variable GRPC_TRACE)
     allow printf-style debugging on GRPC internals, and are useful for
-    tracking down problems in the field. 
+    tracking down problems in the field.
 
-    Use of this function is not strictly thread-safe, but the 
+    Use of this function is not strictly thread-safe, but the
     thread-safety issues raised by it should not be of concern. */
 int grpc_tracer_set_enabled(const char *name, int enabled);
 
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index e104b69..37d66c0 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -51,6 +51,11 @@
    The creator of the credentials object is responsible for its release. */
 void grpc_credentials_release(grpc_credentials *creds);
 
+/* Environment variable that points to the google default application
+   credentials json key or refresh token. Used in the
+   grpc_google_default_credentials_create function. */
+#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
+
 /* Creates default credentials to connect to a google gRPC service.
    WARNING: Do NOT use this credentials to connect to a non-google service as
    this could result in an oauth2 token leak. */
@@ -126,13 +131,18 @@
 grpc_credentials *grpc_refresh_token_credentials_create(
     const char *json_refresh_token);
 
-/* Creates a fake transport security credentials object for testing. */
-grpc_credentials *grpc_fake_transport_security_credentials_create(void);
+/* Creates an Oauth2 Access Token credentials with an access token that was
+   aquired by an out of band mechanism. */
+grpc_credentials *grpc_access_token_credentials_create(
+    const char *access_token);
 
 /* Creates an IAM credentials object. */
 grpc_credentials *grpc_iam_credentials_create(const char *authorization_token,
                                               const char *authority_selector);
 
+/* Creates a fake transport security credentials object for testing. */
+grpc_credentials *grpc_fake_transport_security_credentials_create(void);
+
 /* --- Secure channel creation. --- */
 
 /* The caller of the secure_channel_create functions may override the target
@@ -195,8 +205,7 @@
 
 /* TODO(jboeuf): Define some well-known property names. */
 
-#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME \
-  "transport_security_type"
+#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type"
 #define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
 #define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
 
@@ -244,11 +253,15 @@
 /* Returns 1 if the peer is authenticated, 0 otherwise. */
 int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx);
 
-/* Gets the auth context from the call. */
-const grpc_auth_context *grpc_call_auth_context(grpc_call *call);
+/* Gets the auth context from the call. Caller needs to call
+   grpc_auth_context_release on the returned context. */
+grpc_auth_context *grpc_call_auth_context(grpc_call *call);
+
+/* Releases the auth context returned from grpc_call_auth_context. */
+void grpc_auth_context_release(grpc_auth_context *context);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif  /* GRPC_GRPC_SECURITY_H */
+#endif /* GRPC_GRPC_SECURITY_H */
diff --git a/include/grpc/support/atm_win32.h b/include/grpc/support/atm_win32.h
index dcba4d4..da99021 100644
--- a/include/grpc/support/atm_win32.h
+++ b/include/grpc/support/atm_win32.h
@@ -37,8 +37,6 @@
 /* Win32 variant of atm_platform.h */
 #include <grpc/support/port_platform.h>
 
-#include <windows.h>
-
 typedef gpr_intptr gpr_atm;
 
 #define gpr_atm_full_barrier MemoryBarrier
diff --git a/include/grpc/support/log_win32.h b/include/grpc/support/log_win32.h
index ad0edcd..595a81a 100644
--- a/include/grpc/support/log_win32.h
+++ b/include/grpc/support/log_win32.h
@@ -34,8 +34,6 @@
 #ifndef GRPC_SUPPORT_LOG_WIN32_H
 #define GRPC_SUPPORT_LOG_WIN32_H
 
-#include <windows.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index a695acf..a5d1b62 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -34,6 +34,38 @@
 #ifndef GRPC_SUPPORT_PORT_PLATFORM_H
 #define GRPC_SUPPORT_PORT_PLATFORM_H
 
+/* Get windows.h included everywhere (we need it) */
+#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
+#ifndef WIN32_LEAN_AND_MEAN
+#define GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
+#define WIN32_LEAN_AND_MEAN
+#endif /* WIN32_LEAN_AND_MEAN */
+
+#ifndef NOMINMAX
+#define GRPC_NOMINMX_WAS_NOT_DEFINED
+#define NOMINMAX
+#endif /* NOMINMAX */
+
+#if defined(_WIN32_WINNT)
+#if _WIN32_WINNT < 0x0600
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif /* _WIN32_WINNT < 0x0600 */
+#endif /* defined(_WIN32_WINNT) */
+
+#include <windows.h>
+
+#ifdef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
+#undef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
+#undef WIN32_LEAN_AND_MEAN
+#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
+
+#ifdef GRPC_NOMINMAX_WAS_NOT_DEFINED
+#undef GRPC_NOMINMAX_WAS_NOT_DEFINED
+#undef NOMINMAX
+#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
+#endif /* defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) */
+
 /* Override this file with one for your platform if you need to redefine
    things.  */
 
@@ -50,6 +82,7 @@
 #define GPR_WIN32_ATOMIC 1
 #define GPR_MSVC_TLS 1
 #endif
+#define GPR_WINDOWS_CRASH_HANDLER 1
 #elif defined(_WIN32) || defined(WIN32)
 #define GPR_ARCH_32 1
 #define GPR_WIN32 1
@@ -62,6 +95,7 @@
 #define GPR_WIN32_ATOMIC 1
 #define GPR_MSVC_TLS 1
 #endif
+#define GPR_WINDOWS_CRASH_HANDLER 1
 #elif defined(ANDROID) || defined(__ANDROID__)
 #define GPR_ANDROID 1
 #define GPR_ARCH_32 1
@@ -223,7 +257,9 @@
 #endif
 
 /* Validate platform combinations */
-#if defined(GPR_GCC_ATOMIC) + defined(GPR_GCC_SYNC) + defined(GPR_WIN32_ATOMIC) != 1
+#if defined(GPR_GCC_ATOMIC) + defined(GPR_GCC_SYNC) + \
+        defined(GPR_WIN32_ATOMIC) !=                  \
+    1
 #error Must define exactly one of GPR_GCC_ATOMIC, GPR_GCC_SYNC, GPR_WIN32_ATOMIC
 #endif
 
@@ -231,7 +267,9 @@
 #error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64
 #endif
 
-#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + defined(GPR_CPU_IPHONE) + defined(GPR_CPU_CUSTOM) != 1
+#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + \
+        defined(GPR_CPU_IPHONE) + defined(GPR_CPU_CUSTOM) !=               \
+    1
 #error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE, GPR_CPU_CUSTOM
 #endif
 
@@ -239,11 +277,15 @@
 #error Must define GPR_POSIX_SOCKET to use GPR_POSIX_MULTIPOLL_WITH_POLL
 #endif
 
-#if defined(GPR_POSIX_SOCKET) + defined(GPR_WINSOCK_SOCKET) + defined(GPR_CUSTOM_SOCKET) != 1
+#if defined(GPR_POSIX_SOCKET) + defined(GPR_WINSOCK_SOCKET) + \
+        defined(GPR_CUSTOM_SOCKET) !=                         \
+    1
 #error Must define exactly one of GPR_POSIX_SOCKET, GPR_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET
 #endif
 
-#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + defined(GPR_CUSTOM_TLS) != 1
+#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + \
+        defined(GPR_CUSTOM_TLS) !=                                            \
+    1
 #error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, GPR_CUSTOM_TLS
 #endif
 
@@ -266,4 +308,12 @@
    power of two */
 #define GPR_MAX_ALIGNMENT 16
 
-#endif  /* GRPC_SUPPORT_PORT_PLATFORM_H */
+#ifndef GRPC_MUST_USE_RESULT
+#ifdef __GNUC__
+#define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))
+#else
+#define GRPC_MUST_USE_RESULT
+#endif
+#endif
+
+#endif /* GRPC_SUPPORT_PORT_PLATFORM_H */
diff --git a/include/grpc/support/slice.h b/include/grpc/support/slice.h
index 3ee103b..ec6c117 100644
--- a/include/grpc/support/slice.h
+++ b/include/grpc/support/slice.h
@@ -97,8 +97,8 @@
   ((slice).refcount ? (slice).data.refcounted.length \
                     : (slice).data.inlined.length)
 #define GPR_SLICE_SET_LENGTH(slice, newlen)                       \
-  ((slice).refcount ? ((slice).data.refcounted.length = (newlen)) \
-                    : ((slice).data.inlined.length = (newlen)))
+  ((slice).refcount ? ((slice).data.refcounted.length = (size_t)(newlen)) \
+                    : ((slice).data.inlined.length = (gpr_uint8)(newlen)))
 #define GPR_SLICE_END_PTR(slice) \
   GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(slice)
 #define GPR_SLICE_IS_EMPTY(slice) (GPR_SLICE_LENGTH(slice) == 0)
@@ -176,4 +176,4 @@
 }
 #endif
 
-#endif  /* GRPC_SUPPORT_SLICE_H */
+#endif /* GRPC_SUPPORT_SLICE_H */
diff --git a/include/grpc/support/slice_buffer.h b/include/grpc/support/slice_buffer.h
index 1545dbf..ec048e8 100644
--- a/include/grpc/support/slice_buffer.h
+++ b/include/grpc/support/slice_buffer.h
@@ -84,6 +84,8 @@
 void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb);
 /* swap the contents of two slice buffers */
 void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b);
+/* move all of the elements of src into dst */
+void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/sync_win32.h b/include/grpc/support/sync_win32.h
index cb2a866..66b9af9 100644
--- a/include/grpc/support/sync_win32.h
+++ b/include/grpc/support/sync_win32.h
@@ -36,8 +36,6 @@
 
 #include <grpc/support/sync_generic.h>
 
-#include <windows.h>
-
 typedef struct {
   CRITICAL_SECTION cs; /* Not an SRWLock until Vista is unsupported */
   int locked;
diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h
index 1fd3181..3f375f6 100644
--- a/include/grpc/support/time.h
+++ b/include/grpc/support/time.h
@@ -45,15 +45,30 @@
 extern "C" {
 #endif
 
+/* The clocks we support. */
+typedef enum {
+  /* Monotonic clock. Epoch undefined. Always moves forwards. */
+  GPR_CLOCK_MONOTONIC = 0,
+  /* Realtime clock. May jump forwards or backwards. Settable by
+     the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */
+  GPR_CLOCK_REALTIME,
+  /* Unmeasurable clock type: no base, created by taking the difference
+     between two times */
+  GPR_TIMESPAN
+} gpr_clock_type;
+
 typedef struct gpr_timespec {
-    time_t tv_sec;
-    int tv_nsec;
+  time_t tv_sec;
+  int tv_nsec;
+  /** Against which clock was this time measured? (or GPR_TIMESPAN if
+      this is a relative time meaure) */
+  gpr_clock_type clock_type;
 } gpr_timespec;
 
 /* Time constants. */
-extern const gpr_timespec gpr_time_0;     /* The zero time interval. */
-extern const gpr_timespec gpr_inf_future; /* The far future */
-extern const gpr_timespec gpr_inf_past;   /* The far past. */
+gpr_timespec gpr_time_0(gpr_clock_type type);     /* The zero time interval. */
+gpr_timespec gpr_inf_future(gpr_clock_type type); /* The far future */
+gpr_timespec gpr_inf_past(gpr_clock_type type);   /* The far past. */
 
 #define GPR_MS_PER_SEC 1000
 #define GPR_US_PER_SEC 1000000
@@ -62,8 +77,11 @@
 #define GPR_NS_PER_US 1000
 #define GPR_US_PER_MS 1000
 
-/* Return the current time measured from the system's default epoch. */
-gpr_timespec gpr_now(void);
+/* initialize time subsystem */
+void gpr_time_init(void);
+
+/* Return the current time measured from the given clocks epoch. */
+gpr_timespec gpr_now(gpr_clock_type clock);
 
 /* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
    respectively.  */
@@ -78,12 +96,12 @@
 
 /* Return a timespec representing a given number of time units. LONG_MIN is
    interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future.  */
-gpr_timespec gpr_time_from_micros(long x);
-gpr_timespec gpr_time_from_nanos(long x);
-gpr_timespec gpr_time_from_millis(long x);
-gpr_timespec gpr_time_from_seconds(long x);
-gpr_timespec gpr_time_from_minutes(long x);
-gpr_timespec gpr_time_from_hours(long x);
+gpr_timespec gpr_time_from_micros(long x, gpr_clock_type clock_type);
+gpr_timespec gpr_time_from_nanos(long x, gpr_clock_type clock_type);
+gpr_timespec gpr_time_from_millis(long x, gpr_clock_type clock_type);
+gpr_timespec gpr_time_from_seconds(long x, gpr_clock_type clock_type);
+gpr_timespec gpr_time_from_minutes(long x, gpr_clock_type clock_type);
+gpr_timespec gpr_time_from_hours(long x, gpr_clock_type clock_type);
 
 gpr_int32 gpr_time_to_millis(gpr_timespec timespec);
 
@@ -100,4 +118,4 @@
 }
 #endif
 
-#endif  /* GRPC_SUPPORT_TIME_H */
+#endif /* GRPC_SUPPORT_TIME_H */
diff --git a/include/grpc/support/tls_pthread.h b/include/grpc/support/tls_pthread.h
index c18f247..50e55d3 100644
--- a/include/grpc/support/tls_pthread.h
+++ b/include/grpc/support/tls_pthread.h
@@ -34,7 +34,7 @@
 #ifndef GRPC_SUPPORT_TLS_PTHREAD_H
 #define GRPC_SUPPORT_TLS_PTHREAD_H
 
-#include <grpc/support/log.h>  /* for GPR_ASSERT */
+#include <grpc/support/log.h> /* for GPR_ASSERT */
 #include <pthread.h>
 
 /* Thread local storage based on pthread library calls.
@@ -44,8 +44,7 @@
   pthread_key_t key;
 };
 
-#define GPR_TLS_DECL(name) \
-    static struct gpr_pthread_thread_local name = {0}
+#define GPR_TLS_DECL(name) static struct gpr_pthread_thread_local name = {0}
 
 #define gpr_tls_init(tls) GPR_ASSERT(0 == pthread_key_create(&(tls)->key, NULL))
 #define gpr_tls_destroy(tls) pthread_key_delete((tls)->key)
diff --git a/include/grpc/support/useful.h b/include/grpc/support/useful.h
index e1ce045..3842611 100644
--- a/include/grpc/support/useful.h
+++ b/include/grpc/support/useful.h
@@ -52,4 +52,24 @@
     b = x;               \
   } while (0)
 
+/** Set the \a n-th bit of \a i (a mutable pointer). */
+#define GPR_BITSET(i, n) ((*(i)) |= (1u << (n)))
+
+/** Clear the \a n-th bit of \a i (a mutable pointer). */
+#define GPR_BITCLEAR(i, n) ((*(i)) &= ~(1u << (n)))
+
+/** Get the \a n-th bit of \a i */
+#define GPR_BITGET(i, n) (((i) & (1u << (n))) != 0)
+
+#define GPR_INTERNAL_HEXDIGIT_BITCOUNT(x)                        \
+  ((x) - (((x) >> 1) & 0x77777777) - (((x) >> 2) & 0x33333333) - \
+   (((x) >> 3) & 0x11111111))
+
+/** Returns number of bits set in bitset \a i */
+#define GPR_BITCOUNT(i)                          \
+  (((GPR_INTERNAL_HEXDIGIT_BITCOUNT(i) +         \
+     (GPR_INTERNAL_HEXDIGIT_BITCOUNT(i) >> 4)) & \
+    0x0f0f0f0f) %                                \
+   255)
+
 #endif  /* GRPC_SUPPORT_USEFUL_H */
diff --git a/src/compiler/config.h b/src/compiler/config.h
index e81de8d..cd52aca 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -35,6 +35,7 @@
 #define SRC_COMPILER_CONFIG_H
 
 #include <grpc++/config.h>
+#include <grpc++/config_protobuf.h>
 
 #ifndef GRPC_CUSTOM_DESCRIPTOR
 #include <google/protobuf/descriptor.h>
@@ -48,7 +49,8 @@
 #ifndef GRPC_CUSTOM_CODEGENERATOR
 #include <google/protobuf/compiler/code_generator.h>
 #define GRPC_CUSTOM_CODEGENERATOR ::google::protobuf::compiler::CodeGenerator
-#define GRPC_CUSTOM_GENERATORCONTEXT ::google::protobuf::compiler::GeneratorContext
+#define GRPC_CUSTOM_GENERATORCONTEXT \
+  ::google::protobuf::compiler::GeneratorContext
 #endif
 
 #ifndef GRPC_CUSTOM_PRINTER
@@ -57,7 +59,8 @@
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #define GRPC_CUSTOM_PRINTER ::google::protobuf::io::Printer
 #define GRPC_CUSTOM_CODEDOUTPUTSTREAM ::google::protobuf::io::CodedOutputStream
-#define GRPC_CUSTOM_STRINGOUTPUTSTREAM ::google::protobuf::io::StringOutputStream
+#define GRPC_CUSTOM_STRINGOUTPUTSTREAM \
+  ::google::protobuf::io::StringOutputStream
 #endif
 
 #ifndef GRPC_CUSTOM_PLUGINMAIN
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 6cd6150..7565994 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -97,7 +97,8 @@
     vars["filename_base"] = grpc_generator::StripProto(file->name());
 
     printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
-    printer.Print(vars, "// If you make any local change, they will be lost.\n");
+    printer.Print(vars,
+                  "// If you make any local change, they will be lost.\n");
     printer.Print(vars, "// source: $filename$\n");
     printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
     printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
@@ -113,6 +114,7 @@
   grpc::string temp =
       "#include <grpc++/impl/internal_stub.h>\n"
       "#include <grpc++/impl/rpc_method.h>\n"
+      "#include <grpc++/impl/proto_utils.h>\n"
       "#include <grpc++/impl/service_type.h>\n"
       "#include <grpc++/async_unary_call.h>\n"
       "#include <grpc++/status.h>\n"
@@ -141,10 +143,10 @@
   return temp;
 }
 
-void PrintHeaderClientMethodInterfaces(grpc::protobuf::io::Printer *printer,
-                             const grpc::protobuf::MethodDescriptor *method,
-                             std::map<grpc::string, grpc::string> *vars,
-                             bool is_public) {
+void PrintHeaderClientMethodInterfaces(
+    grpc::protobuf::io::Printer *printer,
+    const grpc::protobuf::MethodDescriptor *method,
+    std::map<grpc::string, grpc::string> *vars, bool is_public) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] =
       grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -157,19 +159,17 @@
           *vars,
           "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, "
           "const $Request$& request, $Response$* response) = 0;\n");
-      printer->Print(
-          *vars,
-          "std::unique_ptr< "
-          "::grpc::ClientAsyncResponseReaderInterface< $Response$>> "
-          "Async$Method$(::grpc::ClientContext* context, "
-          "const $Request$& request, "
-          "::grpc::CompletionQueue* cq) {\n");
+      printer->Print(*vars,
+                     "std::unique_ptr< "
+                     "::grpc::ClientAsyncResponseReaderInterface< $Response$>> "
+                     "Async$Method$(::grpc::ClientContext* context, "
+                     "const $Request$& request, "
+                     "::grpc::CompletionQueue* cq) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< "
-          "::grpc::ClientAsyncResponseReaderInterface< $Response$>>("
-          "Async$Method$Raw(context, request, cq));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< "
+                     "::grpc::ClientAsyncResponseReaderInterface< $Response$>>("
+                     "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
     } else if (ClientOnlyStreaming(method)) {
@@ -188,14 +188,14 @@
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>"
-          " Async$Method$(::grpc::ClientContext* context, $Response$* response, "
+          " Async$Method$(::grpc::ClientContext* context, $Response$* "
+          "response, "
           "::grpc::CompletionQueue* cq, void* tag) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< "
-          "::grpc::ClientAsyncWriterInterface< $Request$>>("
-          "Async$Method$Raw(context, response, cq, tag));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< "
+                     "::grpc::ClientAsyncWriterInterface< $Request$>>("
+                     "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
     } else if (ServerOnlyStreaming(method)) {
@@ -218,18 +218,17 @@
           "::grpc::ClientContext* context, const $Request$& request, "
           "::grpc::CompletionQueue* cq, void* tag) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< "
-          "::grpc::ClientAsyncReaderInterface< $Response$>>("
-          "Async$Method$Raw(context, request, cq, tag));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< "
+                     "::grpc::ClientAsyncReaderInterface< $Response$>>("
+                     "Async$Method$Raw(context, request, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
     } else if (BidiStreaming(method)) {
-      printer->Print(
-          *vars,
-          "std::unique_ptr< ::grpc::ClientReaderWriterInterface< $Request$, $Response$>> "
-          "$Method$(::grpc::ClientContext* context) {\n");
+      printer->Print(*vars,
+                     "std::unique_ptr< ::grpc::ClientReaderWriterInterface< "
+                     "$Request$, $Response$>> "
+                     "$Method$(::grpc::ClientContext* context) {\n");
       printer->Indent();
       printer->Print(
           *vars,
@@ -267,12 +266,11 @@
           "virtual ::grpc::ClientWriterInterface< $Request$>*"
           " $Method$Raw("
           "::grpc::ClientContext* context, $Response$* response) = 0;\n");
-      printer->Print(
-          *vars,
-          "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*"
-          " Async$Method$Raw(::grpc::ClientContext* context, "
-          "$Response$* response, "
-          "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
+      printer->Print(*vars,
+                     "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*"
+                     " Async$Method$Raw(::grpc::ClientContext* context, "
+                     "$Response$* response, "
+                     "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
     } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
@@ -285,16 +283,15 @@
           "::grpc::ClientContext* context, const $Request$& request, "
           "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
     } else if (BidiStreaming(method)) {
-      printer->Print(
-          *vars,
-          "virtual ::grpc::ClientReaderWriterInterface< $Request$, $Response$>* "
-          "$Method$Raw(::grpc::ClientContext* context) = 0;\n");
-      printer->Print(
-          *vars,
-          "virtual ::grpc::ClientAsyncReaderWriterInterface< "
-          "$Request$, $Response$>* "
-          "Async$Method$Raw(::grpc::ClientContext* context, "
-          "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
+      printer->Print(*vars,
+                     "virtual ::grpc::ClientReaderWriterInterface< $Request$, "
+                     "$Response$>* "
+                     "$Method$Raw(::grpc::ClientContext* context) = 0;\n");
+      printer->Print(*vars,
+                     "virtual ::grpc::ClientAsyncReaderWriterInterface< "
+                     "$Request$, $Response$>* "
+                     "Async$Method$Raw(::grpc::ClientContext* context, "
+                     "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
     }
   }
 }
@@ -321,11 +318,10 @@
           "const $Request$& request, "
           "::grpc::CompletionQueue* cq) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< "
-          "::grpc::ClientAsyncResponseReader< $Response$>>("
-          "Async$Method$Raw(context, request, cq));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< "
+                     "::grpc::ClientAsyncResponseReader< $Response$>>("
+                     "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
     } else if (ClientOnlyStreaming(method)) {
@@ -335,17 +331,16 @@
           " $Method$("
           "::grpc::ClientContext* context, $Response$* response) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
-          "($Method$Raw(context, response));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
+                     "($Method$Raw(context, response));\n");
       printer->Outdent();
       printer->Print("}\n");
-      printer->Print(
-          *vars,
-          "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>"
-          " Async$Method$(::grpc::ClientContext* context, $Response$* response, "
-          "::grpc::CompletionQueue* cq, void* tag) {\n");
+      printer->Print(*vars,
+                     "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>"
+                     " Async$Method$(::grpc::ClientContext* context, "
+                     "$Response$* response, "
+                     "::grpc::CompletionQueue* cq, void* tag) {\n");
       printer->Indent();
       printer->Print(
           *vars,
@@ -385,53 +380,47 @@
           "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>"
           " $Method$(::grpc::ClientContext* context) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< "
-          "::grpc::ClientReaderWriter< $Request$, $Response$>>("
-          "$Method$Raw(context));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< "
+                     "::grpc::ClientReaderWriter< $Request$, $Response$>>("
+                     "$Method$Raw(context));\n");
       printer->Outdent();
       printer->Print("}\n");
-      printer->Print(
-          *vars,
-          "std::unique_ptr<  ::grpc::ClientAsyncReaderWriter< "
-          "$Request$, $Response$>> "
-          "Async$Method$(::grpc::ClientContext* context, "
-          "::grpc::CompletionQueue* cq, void* tag) {\n");
+      printer->Print(*vars,
+                     "std::unique_ptr<  ::grpc::ClientAsyncReaderWriter< "
+                     "$Request$, $Response$>> "
+                     "Async$Method$(::grpc::ClientContext* context, "
+                     "::grpc::CompletionQueue* cq, void* tag) {\n");
       printer->Indent();
-      printer->Print(
-          *vars,
-          "return std::unique_ptr< "
-          "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>("
-          "Async$Method$Raw(context, cq, tag));\n");
+      printer->Print(*vars,
+                     "return std::unique_ptr< "
+                     "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>("
+                     "Async$Method$Raw(context, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
     }
   } else {
     if (NoStreaming(method)) {
-      printer->Print(
-          *vars,
-          "::grpc::ClientAsyncResponseReader< $Response$>* "
-          "Async$Method$Raw(::grpc::ClientContext* context, "
-          "const $Request$& request, "
-          "::grpc::CompletionQueue* cq) GRPC_OVERRIDE;\n");
+      printer->Print(*vars,
+                     "::grpc::ClientAsyncResponseReader< $Response$>* "
+                     "Async$Method$Raw(::grpc::ClientContext* context, "
+                     "const $Request$& request, "
+                     "::grpc::CompletionQueue* cq) GRPC_OVERRIDE;\n");
     } else if (ClientOnlyStreaming(method)) {
-      printer->Print(
-          *vars,
-          "::grpc::ClientWriter< $Request$>* $Method$Raw("
-          "::grpc::ClientContext* context, $Response$* response) "
-          "GRPC_OVERRIDE;\n");
+      printer->Print(*vars,
+                     "::grpc::ClientWriter< $Request$>* $Method$Raw("
+                     "::grpc::ClientContext* context, $Response$* response) "
+                     "GRPC_OVERRIDE;\n");
       printer->Print(
           *vars,
           "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw("
           "::grpc::ClientContext* context, $Response$* response, "
           "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
     } else if (ServerOnlyStreaming(method)) {
-      printer->Print(
-          *vars,
-          "::grpc::ClientReader< $Response$>* $Method$Raw("
-          "::grpc::ClientContext* context, const $Request$& request)"
-          " GRPC_OVERRIDE;\n");
+      printer->Print(*vars,
+                     "::grpc::ClientReader< $Response$>* $Method$Raw("
+                     "::grpc::ClientContext* context, const $Request$& request)"
+                     " GRPC_OVERRIDE;\n");
       printer->Print(
           *vars,
           "::grpc::ClientAsyncReader< $Response$>* Async$Method$Raw("
@@ -629,7 +618,7 @@
                                const Parameters &params) {
   grpc::string output;
   {
-	// Scope the output stream so it closes and finalizes output to the string.
+    // Scope the output stream so it closes and finalizes output to the string.
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     grpc::protobuf::io::Printer printer(&output_stream, '$');
     std::map<grpc::string, grpc::string> vars;
@@ -693,7 +682,8 @@
     vars["filename_base"] = grpc_generator::StripProto(file->name());
 
     printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
-    printer.Print(vars, "// If you make any local change, they will be lost.\n");
+    printer.Print(vars,
+                  "// If you make any local change, they will be lost.\n");
     printer.Print(vars, "// source: $filename$\n\n");
     printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
     printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
@@ -1056,8 +1046,7 @@
           "    new ::grpc::RpcMethodHandler< $ns$$Service$::Service, "
           "$Request$, "
           "$Response$>(\n"
-          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this),\n"
-          "    new $Request$, new $Response$));\n");
+          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
     } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
@@ -1066,8 +1055,7 @@
           "    ::grpc::RpcMethod::CLIENT_STREAMING,\n"
           "    new ::grpc::ClientStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
-          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this),\n"
-          "    new $Request$, new $Response$));\n");
+          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
     } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
@@ -1076,8 +1064,7 @@
           "    ::grpc::RpcMethod::SERVER_STREAMING,\n"
           "    new ::grpc::ServerStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
-          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this),\n"
-          "    new $Request$, new $Response$));\n");
+          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
     } else if (BidiStreaming(method)) {
       printer->Print(
           *vars,
@@ -1086,8 +1073,7 @@
           "    ::grpc::RpcMethod::BIDI_STREAMING,\n"
           "    new ::grpc::BidiStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
-          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this),\n"
-          "    new $Request$, new $Response$));\n");
+          "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
     }
   }
   printer->Print("return service_;\n");
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index ccb0b68..1910e9b 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -257,7 +257,7 @@
 }
 
 void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// client-side stub interface\n");
+  out->Print("// client interface\n");
   out->Print("public interface $name$\n", "name",
              GetClientInterfaceName(service));
   out->Print("{\n");
@@ -269,7 +269,7 @@
     if (method_type == METHODTYPE_NO_STREAMING) {
       // unary calls have an extra synchronous stub method
       out->Print(
-          "$response$ $methodname$($request$ request, CancellationToken token = default(CancellationToken));\n",
+          "$response$ $methodname$($request$ request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
           GetClassName(method->output_type()));
@@ -280,7 +280,7 @@
       method_name += "Async";  // prevent name clash with synchronous method.
     }
     out->Print(
-        "$returntype$ $methodname$($request_maybe$CancellationToken token = default(CancellationToken));\n",
+        "$returntype$ $methodname$($request_maybe$Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));\n",
         "methodname", method_name, "request_maybe",
         GetMethodRequestParamMaybe(method), "returntype",
         GetMethodReturnTypeClient(method));
@@ -312,7 +312,7 @@
 void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
   out->Print("// client stub\n");
   out->Print(
-      "public class $name$ : AbstractStub<$name$, StubConfiguration>, $interface$\n",
+      "public class $name$ : ClientBase, $interface$\n",
       "name", GetClientClassName(service), "interface",
       GetClientInterfaceName(service));
   out->Print("{\n");
@@ -320,12 +320,7 @@
 
   // constructors
   out->Print(
-      "public $name$(Channel channel) : this(channel, StubConfiguration.Default)\n",
-      "name", GetClientClassName(service));
-  out->Print("{\n");
-  out->Print("}\n");
-  out->Print(
-      "public $name$(Channel channel, StubConfiguration config) : base(channel, config)\n",
+      "public $name$(Channel channel) : base(channel)\n",
       "name", GetClientClassName(service));
   out->Print("{\n");
   out->Print("}\n");
@@ -337,16 +332,16 @@
     if (method_type == METHODTYPE_NO_STREAMING) {
       // unary calls have an extra synchronous stub method
       out->Print(
-          "public $response$ $methodname$($request$ request, CancellationToken token = default(CancellationToken))\n",
+          "public $response$ $methodname$($request$ request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
           GetClassName(method->output_type()));
       out->Print("{\n");
       out->Indent();
-      out->Print("var call = CreateCall($servicenamefield$, $methodfield$);\n",
+      out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers);\n",
                  "servicenamefield", GetServiceNameFieldName(), "methodfield",
                  GetMethodFieldName(method));
-      out->Print("return Calls.BlockingUnaryCall(call, request, token);\n");
+      out->Print("return Calls.BlockingUnaryCall(call, request, cancellationToken);\n");
       out->Outdent();
       out->Print("}\n");
     }
@@ -356,28 +351,28 @@
       method_name += "Async";  // prevent name clash with synchronous method.
     }
     out->Print(
-        "public $returntype$ $methodname$($request_maybe$CancellationToken token = default(CancellationToken))\n",
+        "public $returntype$ $methodname$($request_maybe$Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))\n",
         "methodname", method_name, "request_maybe",
         GetMethodRequestParamMaybe(method), "returntype",
         GetMethodReturnTypeClient(method));
     out->Print("{\n");
     out->Indent();
-    out->Print("var call = CreateCall($servicenamefield$, $methodfield$);\n",
+    out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers);\n",
                "servicenamefield", GetServiceNameFieldName(), "methodfield",
                GetMethodFieldName(method));
     switch (GetMethodType(method)) {
       case METHODTYPE_NO_STREAMING:
-        out->Print("return Calls.AsyncUnaryCall(call, request, token);\n");
+        out->Print("return Calls.AsyncUnaryCall(call, request, cancellationToken);\n");
         break;
       case METHODTYPE_CLIENT_STREAMING:
-        out->Print("return Calls.AsyncClientStreamingCall(call, token);\n");
+        out->Print("return Calls.AsyncClientStreamingCall(call, cancellationToken);\n");
         break;
       case METHODTYPE_SERVER_STREAMING:
         out->Print(
-            "return Calls.AsyncServerStreamingCall(call, request, token);\n");
+            "return Calls.AsyncServerStreamingCall(call, request, cancellationToken);\n");
         break;
       case METHODTYPE_BIDI_STREAMING:
-        out->Print("return Calls.AsyncDuplexStreamingCall(call, token);\n");
+        out->Print("return Calls.AsyncDuplexStreamingCall(call, cancellationToken);\n");
         break;
       default:
         GOOGLE_LOG(FATAL)<< "Can't get here.";
@@ -423,9 +418,9 @@
 }
 
 void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// creates a new client stub\n");
-  out->Print("public static $interface$ NewStub(Channel channel)\n",
-             "interface", GetClientInterfaceName(service));
+  out->Print("// creates a new client\n");
+  out->Print("public static $classname$ NewClient(Channel channel)\n",
+             "classname", GetClientClassName(service));
   out->Print("{\n");
   out->Indent();
   out->Print("return new $classname$(channel);\n", "classname",
@@ -433,17 +428,6 @@
   out->Outdent();
   out->Print("}\n");
   out->Print("\n");
-
-  out->Print("// creates a new client stub\n");
-  out->Print(
-      "public static $interface$ NewStub(Channel channel, StubConfiguration config)\n",
-      "interface", GetClientInterfaceName(service));
-  out->Print("{\n");
-  out->Indent();
-  out->Print("return new $classname$(channel, config);\n", "classname",
-             GetClientClassName(service));
-  out->Outdent();
-  out->Print("}\n");
 }
 
 void GenerateService(Printer* out, const ServiceDescriptor *service) {
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index b235911..69b3805 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -57,33 +57,34 @@
   vars["server_stream"] = method->server_streaming() ? "stream " : "";
 
   printer->Print(vars,
-      "#pragma mark $method_name$($client_stream$$request_type$)"
-      " returns ($server_stream$$response_type$)\n\n");
+                 "#pragma mark $method_name$($client_stream$$request_type$)"
+                 " returns ($server_stream$$response_type$)\n\n");
 }
 
-void PrintMethodSignature(Printer *printer,
-                          const MethodDescriptor *method,
-                          const map<string, string>& vars) {
+void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
+                          const map<string, string> &vars) {
   // TODO(jcanizales): Print method comments.
 
   printer->Print(vars, "- ($return_type$)$method_name$With");
   if (method->client_streaming()) {
-    printer->Print("RequestsWriter:(id<GRXWriter>)request");
+    printer->Print("RequestsWriter:(GRXWriter *)requestWriter");
   } else {
     printer->Print(vars, "Request:($request_class$ *)request");
   }
 
   // TODO(jcanizales): Put this on a new line and align colons.
-  // TODO(jcanizales): eventHandler for server streaming?
-  printer->Print(" handler:(void(^)(");
   if (method->server_streaming()) {
-    printer->Print("BOOL done, ");
+    printer->Print(vars,
+                   " eventHandler:(void(^)(BOOL done, "
+                   "$response_class$ *response, NSError *error))eventHandler");
+  } else {
+    printer->Print(vars,
+                   " handler:(void(^)($response_class$ *response, "
+                   "NSError *error))handler");
   }
-  printer->Print(vars, "$response_class$ *response, NSError *error))handler");
 }
 
-void PrintSimpleSignature(Printer *printer,
-                          const MethodDescriptor *method,
+void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
                           map<string, string> vars) {
   vars["method_name"] =
       grpc_generator::LowercaseFirstLetter(vars["method_name"]);
@@ -91,8 +92,7 @@
   PrintMethodSignature(printer, method, vars);
 }
 
-void PrintAdvancedSignature(Printer *printer,
-                            const MethodDescriptor *method,
+void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
                             map<string, string> vars) {
   vars["method_name"] = "RPCTo" + vars["method_name"];
   vars["return_type"] = "ProtoRPC *";
@@ -100,15 +100,16 @@
 }
 
 inline map<string, string> GetMethodVars(const MethodDescriptor *method) {
-  return {{ "method_name", method->name() },
-          { "request_type", method->input_type()->name() },
-          { "response_type", method->output_type()->name() },
-          { "request_class", ClassName(method->input_type()) },
-          { "response_class", ClassName(method->output_type()) }};
+  map<string, string> res;
+  res["method_name"] = method->name();
+  res["request_type"] = method->input_type()->name();
+  res["response_type"] = method->output_type()->name();
+  res["request_class"] = ClassName(method->input_type());
+  res["response_class"] = ClassName(method->output_type());
+  return res;
 }
 
-void PrintMethodDeclarations(Printer *printer,
-                             const MethodDescriptor *method) {
+void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
   map<string, string> vars = GetMethodVars(method);
 
   PrintProtoRpcDeclarationAsPragma(printer, method, vars);
@@ -119,17 +120,20 @@
   printer->Print(";\n\n\n");
 }
 
-void PrintSimpleImplementation(Printer *printer,
-                               const MethodDescriptor *method,
+void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
                                map<string, string> vars) {
   printer->Print("{\n");
   printer->Print(vars, "  [[self RPCTo$method_name$With");
   if (method->client_streaming()) {
-    printer->Print("RequestsWriter:request");
+    printer->Print("RequestsWriter:requestWriter");
   } else {
     printer->Print("Request:request");
   }
-  printer->Print(" handler:handler] start];\n");
+  if (method->server_streaming()) {
+    printer->Print(" eventHandler:eventHandler] start];\n");
+  } else {
+    printer->Print(" handler:handler] start];\n");
+  }
   printer->Print("}\n");
 }
 
@@ -141,7 +145,7 @@
 
   printer->Print("            requestsWriter:");
   if (method->client_streaming()) {
-    printer->Print("request\n");
+    printer->Print("requestWriter\n");
   } else {
     printer->Print("[GRXWriter writerWithValue:request]\n");
   }
@@ -150,7 +154,7 @@
 
   printer->Print("        responsesWriteable:[GRXWriteable ");
   if (method->server_streaming()) {
-    printer->Print("writeableWithStreamHandler:handler]];\n");
+    printer->Print("writeableWithStreamHandler:eventHandler]];\n");
   } else {
     printer->Print("writeableWithSingleValueHandler:handler]];\n");
   }
@@ -173,7 +177,7 @@
   PrintAdvancedImplementation(printer, method, vars);
 }
 
-} // namespace
+}  // namespace
 
 string GetHeader(const ServiceDescriptor *service) {
   string output;
@@ -181,9 +185,6 @@
     // Scope the output stream so it closes and finalizes output to the string.
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     Printer printer(&output_stream, '$');
-  
-    printer.Print("@protocol GRXWriteable;\n");
-    printer.Print("@protocol GRXWriter;\n\n");
 
     map<string, string> vars = {{"service_class", ServiceClassName(service)}};
 
@@ -194,12 +195,15 @@
     }
     printer.Print("@end\n\n");
 
-    printer.Print("// Basic service implementation, over gRPC, that only does"
+    printer.Print(
+        "// Basic service implementation, over gRPC, that only does"
         " marshalling and parsing.\n");
-    printer.Print(vars, "@interface $service_class$ :"
-      " ProtoService<$service_class$>\n");
-    printer.Print("- (instancetype)initWithHost:(NSString *)host"
-      " NS_DESIGNATED_INITIALIZER;\n");
+    printer.Print(vars,
+                  "@interface $service_class$ :"
+                  " ProtoService<$service_class$>\n");
+    printer.Print(
+        "- (instancetype)initWithHost:(NSString *)host"
+        " NS_DESIGNATED_INITIALIZER;\n");
     printer.Print("@end\n");
   }
   return output;
@@ -217,18 +221,20 @@
                                 {"package", service->file()->package()}};
 
     printer.Print(vars,
-        "static NSString *const kPackageName = @\"$package$\";\n");
-    printer.Print(vars,
-        "static NSString *const kServiceName = @\"$service_name$\";\n\n");
+                  "static NSString *const kPackageName = @\"$package$\";\n");
+    printer.Print(
+        vars, "static NSString *const kServiceName = @\"$service_name$\";\n\n");
 
     printer.Print(vars, "@implementation $service_class$\n\n");
-  
+
     printer.Print("// Designated initializer\n");
     printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
-    printer.Print("  return (self = [super initWithHost:host"
+    printer.Print(
+        "  return (self = [super initWithHost:host"
         " packageName:kPackageName serviceName:kServiceName]);\n");
     printer.Print("}\n\n");
-    printer.Print("// Override superclass initializer to disallow different"
+    printer.Print(
+        "// Override superclass initializer to disallow different"
         " package and service names.\n");
     printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
     printer.Print("                 packageName:(NSString *)packageName\n");
@@ -245,4 +251,4 @@
   return output;
 }
 
-} // namespace grpc_objective_c_generator
+}  // namespace grpc_objective_c_generator
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index b5ac2ba..10f06ad 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -62,8 +62,10 @@
     {
       // Generate .pbrpc.h
 
-      string imports = string("#import \"") + file_name + ".pbobjc.h\"\n"
-        "#import <gRPC/ProtoService.h>\n";
+      string imports = 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
@@ -87,10 +89,9 @@
     {
       // Generate .pbrpc.m
 
-      string imports = string("#import \"") + file_name + ".pbrpc.h\"\n"
-        "#import <gRPC/GRXWriteable.h>\n"
-        "#import <gRPC/GRXWriter+Immediate.h>\n"
-        "#import <gRPC/ProtoRPC.h>\n";
+      string imports = string("#import \"") + file_name + ".pbrpc.h\"\n\n"
+        "#import <ProtoRPC/ProtoRPC.h>\n"
+        "#import <RxLibrary/GRXWriter+Immediate.h>\n";
 
       string definitions;
       for (int i = 0; i < file->service_count(); i++) {
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 72149bc..724b69c 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -42,7 +42,7 @@
 #include <tuple>
 #include <vector>
 
-#include "grpc++/config.h"
+#include <grpc++/config.h>
 #include "src/compiler/config.h"
 #include "src/compiler/generator_helpers.h"
 #include "src/compiler/python_generator.h"
diff --git a/src/core/census/context.c b/src/core/census/context.c
index 1358c51..df238ec 100644
--- a/src/core/census/context.c
+++ b/src/core/census/context.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "context.h"
+#include "src/core/census/context.h"
 
 #include <string.h>
 #include <grpc/census.h>
diff --git a/src/core/census/grpc_context.c b/src/core/census/grpc_context.c
index cf23531..0ed6346 100644
--- a/src/core/census/grpc_context.c
+++ b/src/core/census/grpc_context.c
@@ -34,12 +34,28 @@
 #include <grpc/census.h>
 #include "src/core/census/grpc_context.h"
 
-void *grpc_census_context_create() {
-  census_context *context;
-  census_context_deserialize(NULL, &context);
-  return (void *)context;
+static void grpc_census_context_destroy(void *context) {
+  census_context_destroy((census_context *)context);
 }
 
-void grpc_census_context_destroy(void *context) {
-  census_context_destroy((census_context *)context);
+void grpc_census_call_set_context(grpc_call *call, census_context *context) {
+  if (!census_available()) {
+    return;
+  }
+  if (context == NULL) {
+    if (grpc_call_is_client(call)) {
+      census_context *context_ptr;
+      census_context_deserialize(NULL, &context_ptr);
+      grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context_ptr,
+                            grpc_census_context_destroy);
+    } else {
+      /* TODO(aveitch): server side context code to be implemented. */
+    }
+  } else {
+    grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL);
+  }
+}
+
+census_context *grpc_census_call_get_context(grpc_call *call) {
+  return (census_context *)grpc_call_context_get(call, GRPC_CONTEXT_TRACING);
 }
diff --git a/src/core/census/grpc_context.h b/src/core/census/grpc_context.h
index f610f6c..4637e72 100644
--- a/src/core/census/grpc_context.h
+++ b/src/core/census/grpc_context.h
@@ -36,7 +36,22 @@
 #ifndef CENSUS_GRPC_CONTEXT_H
 #define CENSUS_GRPC_CONTEXT_H
 
-void *grpc_census_context_create();
-void grpc_census_context_destroy(void *context);
+#include <grpc/census.h>
+#include "src/core/surface/call.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set census context for the call; Must be called before first call to
+   grpc_call_start_batch(). */
+void grpc_census_call_set_context(grpc_call *call, census_context *context);
+
+/* Retrieve the calls current census context. */
+census_context *grpc_census_call_get_context(grpc_call *call);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* CENSUS_GRPC_CONTEXT_H */
diff --git a/src/core/census/initialize.c b/src/core/census/initialize.c
index 057ac78..8016520 100644
--- a/src/core/census/initialize.c
+++ b/src/core/census/initialize.c
@@ -48,3 +48,5 @@
 }
 
 void census_shutdown() { census_fns_enabled = CENSUS_NONE; }
+
+int census_available() { return (census_fns_enabled != CENSUS_NONE); }
diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c
index 7e393a0..d996c34 100644
--- a/src/core/channel/census_filter.c
+++ b/src/core/channel/census_filter.c
@@ -84,7 +84,8 @@
   }
 }
 
-static void client_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
+static void client_mutate_op(grpc_call_element* elem,
+                             grpc_transport_stream_op* op) {
   call_data* calld = elem->call_data;
   channel_data* chand = elem->channel_data;
   if (op->send_ops) {
@@ -93,7 +94,7 @@
 }
 
 static void client_start_transport_op(grpc_call_element* elem,
-                                      grpc_transport_op* op) {
+                                      grpc_transport_stream_op* op) {
   call_data* calld = elem->call_data;
   GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
   client_mutate_op(elem, op);
@@ -110,7 +111,8 @@
   calld->on_done_recv(calld->recv_user_data, success);
 }
 
-static void server_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
+static void server_mutate_op(grpc_call_element* elem,
+                             grpc_transport_stream_op* op) {
   call_data* calld = elem->call_data;
   if (op->recv_ops) {
     /* substitute our callback for the op callback */
@@ -123,7 +125,7 @@
 }
 
 static void server_start_transport_op(grpc_call_element* elem,
-                                      grpc_transport_op* op) {
+                                      grpc_transport_stream_op* op) {
   call_data* calld = elem->call_data;
   GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
   server_mutate_op(elem, op);
@@ -145,11 +147,11 @@
 
 static void client_init_call_elem(grpc_call_element* elem,
                                   const void* server_transport_data,
-                                  grpc_transport_op* initial_op) {
+                                  grpc_transport_stream_op* initial_op) {
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
   init_rpc_stats(&d->stats);
-  d->start_ts = gpr_now();
+  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
   d->op_id = census_tracing_start_op();
   if (initial_op) client_mutate_op(elem, initial_op);
 }
@@ -163,11 +165,11 @@
 
 static void server_init_call_elem(grpc_call_element* elem,
                                   const void* server_transport_data,
-                                  grpc_transport_op* initial_op) {
+                                  grpc_transport_stream_op* initial_op) {
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
   init_rpc_stats(&d->stats);
-  d->start_ts = gpr_now();
+  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
   d->op_id = census_tracing_start_op();
   if (initial_op) server_mutate_op(elem, initial_op);
 }
@@ -175,8 +177,8 @@
 static void server_destroy_call_elem(grpc_call_element* elem) {
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
-  d->stats.elapsed_time_ms =
-      gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
+  d->stats.elapsed_time_ms = gpr_timespec_to_micros(
+      gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), d->start_ts));
   census_record_rpc_server_stats(d->op_id, &d->stats);
   census_tracing_end_op(d->op_id);
 }
@@ -195,16 +197,28 @@
   channel_data* chand = elem->channel_data;
   GPR_ASSERT(chand != NULL);
   if (chand->path_str != NULL) {
-    grpc_mdstr_unref(chand->path_str);
+    GRPC_MDSTR_UNREF(chand->path_str);
   }
 }
 
 const grpc_channel_filter grpc_client_census_filter = {
-    client_start_transport_op, channel_op, sizeof(call_data),
-    client_init_call_elem, client_destroy_call_elem, sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, "census-client"};
+    client_start_transport_op,
+    channel_op,
+    sizeof(call_data),
+    client_init_call_elem,
+    client_destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    "census-client"};
 
 const grpc_channel_filter grpc_server_census_filter = {
-    server_start_transport_op, channel_op, sizeof(call_data),
-    server_init_call_elem, server_destroy_call_elem, sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, "census-server"};
+    server_start_transport_op,
+    channel_op,
+    sizeof(call_data),
+    server_init_call_elem,
+    server_destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    "census-server"};
diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c
index 166d559..c430b56 100644
--- a/src/core/channel/channel_args.c
+++ b/src/core/channel/channel_args.c
@@ -62,7 +62,8 @@
 }
 
 grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
-                                                  const grpc_arg *to_add) {
+                                                  const grpc_arg *to_add,
+                                                  size_t num_to_add) {
   grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args));
   size_t i;
   size_t src_num_args = (src == NULL) ? 0 : src->num_args;
@@ -71,17 +72,24 @@
     dst->args = NULL;
     return dst;
   }
-  dst->num_args = src_num_args + ((to_add == NULL) ? 0 : 1);
+  dst->num_args = src_num_args + num_to_add;
   dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args);
   for (i = 0; i < src_num_args; i++) {
     dst->args[i] = copy_arg(&src->args[i]);
   }
-  if (to_add != NULL) dst->args[src_num_args] = copy_arg(to_add);
+  for (i = 0; i < num_to_add; i++) {
+    dst->args[i + src_num_args] = copy_arg(&to_add[i]);
+  }
   return dst;
 }
 
 grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) {
-  return grpc_channel_args_copy_and_add(src, NULL);
+  return grpc_channel_args_copy_and_add(src, NULL, 0);
+}
+
+grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
+                                           const grpc_channel_args *b) {
+  return grpc_channel_args_copy_and_add(a, b->args, b->num_args);
 }
 
 void grpc_channel_args_destroy(grpc_channel_args *a) {
@@ -106,7 +114,7 @@
 }
 
 int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
-  unsigned i;
+  size_t i;
   if (a == NULL) return 0;
   for (i = 0; i < a->num_args; i++) {
     if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) {
@@ -116,26 +124,25 @@
   return 0;
 }
 
-grpc_compression_level grpc_channel_args_get_compression_level(
+grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
     const grpc_channel_args *a) {
   size_t i;
-  if (a) {
-    for (i = 0; a && i < a->num_args; ++i) {
-      if (a->args[i].type == GRPC_ARG_INTEGER &&
-          !strcmp(GRPC_COMPRESSION_LEVEL_ARG, a->args[i].key)) {
-        return a->args[i].value.integer;
-        break;
-      }
+  if (a == NULL) return 0;
+  for (i = 0; i < a->num_args; ++i) {
+    if (a->args[i].type == GRPC_ARG_INTEGER &&
+        !strcmp(GRPC_COMPRESSION_ALGORITHM_ARG, a->args[i].key)) {
+      return a->args[i].value.integer;
+      break;
     }
   }
-  return GRPC_COMPRESS_LEVEL_NONE;
+  return GRPC_COMPRESS_NONE;
 }
 
-void grpc_channel_args_set_compression_level(
-    grpc_channel_args **a, grpc_compression_level level) {
+grpc_channel_args *grpc_channel_args_set_compression_algorithm(
+    grpc_channel_args *a, grpc_compression_algorithm algorithm) {
   grpc_arg tmp;
   tmp.type = GRPC_ARG_INTEGER;
-  tmp.key = GRPC_COMPRESSION_LEVEL_ARG;
-  tmp.value.integer = level;
-  *a = grpc_channel_args_copy_and_add(*a, &tmp);
+  tmp.key = GRPC_COMPRESSION_ALGORITHM_ARG;
+  tmp.value.integer = algorithm;
+  return grpc_channel_args_copy_and_add(a, &tmp, 1);
 }
diff --git a/src/core/channel/channel_args.h b/src/core/channel/channel_args.h
index bf747b2..7e6ddd3 100644
--- a/src/core/channel/channel_args.h
+++ b/src/core/channel/channel_args.h
@@ -43,7 +43,12 @@
 /** Copy some arguments and add the to_add parameter in the end.
    If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */
 grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
-                                                  const grpc_arg *to_add);
+                                                  const grpc_arg *to_add,
+                                                  size_t num_to_add);
+
+/** Copy args from a then args from b into a new channel args */
+grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
+                                           const grpc_channel_args *b);
 
 /** Destroy arguments created by grpc_channel_args_copy */
 void grpc_channel_args_destroy(grpc_channel_args *a);
@@ -52,13 +57,14 @@
  * is specified in channel args, otherwise returns 0. */
 int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
 
-/** Returns the compression level set in \a a. */
-grpc_compression_level grpc_channel_args_get_compression_level(
+/** Returns the compression algorithm set in \a a. */
+grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
     const grpc_channel_args *a);
 
-/** Sets the compression level in \a a to \a level. Setting it to
- * GRPC_COMPRESS_LEVEL_NONE disables compression for the channel. */
-void grpc_channel_args_set_compression_level(
-    grpc_channel_args **a, grpc_compression_level level);
+/** Returns a channel arg instance with compression enabled. If \a a is
+ * non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression
+ * for the channel. */
+grpc_channel_args *grpc_channel_args_set_compression_algorithm(
+    grpc_channel_args *a, grpc_compression_algorithm algorithm);
 
-#endif  /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index 311f4f0..e38dcb5 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -102,7 +102,8 @@
 }
 
 void grpc_channel_stack_init(const grpc_channel_filter **filters,
-                             size_t filter_count, const grpc_channel_args *args,
+                             size_t filter_count, grpc_channel *master,
+                             const grpc_channel_args *args,
                              grpc_mdctx *metadata_context,
                              grpc_channel_stack *stack) {
   size_t call_size =
@@ -122,8 +123,9 @@
   for (i = 0; i < filter_count; i++) {
     elems[i].filter = filters[i];
     elems[i].channel_data = user_data;
-    elems[i].filter->init_channel_elem(&elems[i], args, metadata_context,
-                                       i == 0, i == (filter_count - 1));
+    elems[i].filter->init_channel_elem(&elems[i], master, args,
+                                       metadata_context, i == 0,
+                                       i == (filter_count - 1));
     user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
     call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
   }
@@ -148,7 +150,7 @@
 
 void grpc_call_stack_init(grpc_channel_stack *channel_stack,
                           const void *transport_server_data,
-                          grpc_transport_op *initial_op,
+                          grpc_transport_stream_op *initial_op,
                           grpc_call_stack *call_stack) {
   grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
   size_t count = channel_stack->count;
@@ -184,14 +186,14 @@
   }
 }
 
-void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op) {
+void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op) {
   grpc_call_element *next_elem = elem + 1;
-  next_elem->filter->start_transport_op(next_elem, op);
+  next_elem->filter->start_transport_stream_op(next_elem, op);
 }
 
-void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
-  grpc_channel_element *next_elem = elem + op->dir;
-  next_elem->filter->channel_op(next_elem, elem, op);
+void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op) {
+  grpc_channel_element *next_elem = elem + 1;
+  next_elem->filter->start_transport_op(next_elem, op);
 }
 
 grpc_channel_stack *grpc_channel_stack_from_top_element(
@@ -206,14 +208,8 @@
 }
 
 void grpc_call_element_send_cancel(grpc_call_element *cur_elem) {
-  grpc_transport_op op;
+  grpc_transport_stream_op op;
   memset(&op, 0, sizeof(op));
   op.cancel_with_status = GRPC_STATUS_CANCELLED;
   grpc_call_next_op(cur_elem, &op);
 }
-
-void grpc_call_element_recv_status(grpc_call_element *cur_elem,
-                                   grpc_status_code status,
-                                   const char *message) {
-  abort();
-}
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index de0e4e4..785be89 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -51,45 +51,6 @@
 typedef struct grpc_channel_element grpc_channel_element;
 typedef struct grpc_call_element grpc_call_element;
 
-/* The direction of the call.
-   The values of the enums (1, -1) matter here - they are used to increment
-   or decrement a pointer to find the next element to call */
-typedef enum { GRPC_CALL_DOWN = 1, GRPC_CALL_UP = -1 } grpc_call_dir;
-
-typedef enum {
-  /* send a goaway message to remote channels indicating that we are going
-     to disconnect in the future */
-  GRPC_CHANNEL_GOAWAY,
-  /* disconnect any underlying transports */
-  GRPC_CHANNEL_DISCONNECT,
-  /* transport received a new call */
-  GRPC_ACCEPT_CALL,
-  /* an underlying transport was closed */
-  GRPC_TRANSPORT_CLOSED,
-  /* an underlying transport is about to be closed */
-  GRPC_TRANSPORT_GOAWAY
-} grpc_channel_op_type;
-
-/* A single filterable operation to be performed on a channel */
-typedef struct {
-  /* The type of operation we're performing */
-  grpc_channel_op_type type;
-  /* The directionality of this call - is it bubbling up the stack, or down? */
-  grpc_call_dir dir;
-
-  /* Argument data, matching up with grpc_channel_op_type names */
-  union {
-    struct {
-      grpc_transport *transport;
-      const void *transport_server_data;
-    } accept_call;
-    struct {
-      grpc_status_code status;
-      gpr_slice message;
-    } goaway;
-  } data;
-} grpc_channel_op;
-
 /* Channel filters specify:
    1. the amount of memory needed in the channel & call (via the sizeof_XXX
       members)
@@ -103,12 +64,12 @@
 typedef struct {
   /* Called to eg. send/receive data on a call.
      See grpc_call_next_op on how to call the next element in the stack */
-  void (*start_transport_op)(grpc_call_element *elem, grpc_transport_op *op);
+  void (*start_transport_stream_op)(grpc_call_element *elem,
+                                    grpc_transport_stream_op *op);
   /* Called to handle channel level operations - e.g. new calls, or transport
      closure.
      See grpc_channel_next_op on how to call the next element in the stack */
-  void (*channel_op)(grpc_channel_element *elem,
-                     grpc_channel_element *from_elem, grpc_channel_op *op);
+  void (*start_transport_op)(grpc_channel_element *elem, grpc_transport_op *op);
 
   /* sizeof(per call data) */
   size_t sizeof_call_data;
@@ -122,7 +83,7 @@
      argument.*/
   void (*init_call_elem)(grpc_call_element *elem,
                          const void *server_transport_data,
-                         grpc_transport_op *initial_op);
+                         grpc_transport_stream_op *initial_op);
   /* Destroy per call data.
      The filter does not need to do any chaining */
   void (*destroy_call_elem)(grpc_call_element *elem);
@@ -135,7 +96,7 @@
      is_first, is_last designate this elements position in the stack, and are
      useful for asserting correct configuration by upper layer code.
      The filter does not need to do any chaining */
-  void (*init_channel_elem)(grpc_channel_element *elem,
+  void (*init_channel_elem)(grpc_channel_element *elem, grpc_channel *master,
                             const grpc_channel_args *args,
                             grpc_mdctx *metadata_context, int is_first,
                             int is_last);
@@ -190,7 +151,8 @@
                                size_t filter_count);
 /* Initialize a channel stack given some filters */
 void grpc_channel_stack_init(const grpc_channel_filter **filters,
-                             size_t filter_count, const grpc_channel_args *args,
+                             size_t filter_count, grpc_channel *master,
+                             const grpc_channel_args *args,
                              grpc_mdctx *metadata_context,
                              grpc_channel_stack *stack);
 /* Destroy a channel stack */
@@ -201,16 +163,16 @@
    server. */
 void grpc_call_stack_init(grpc_channel_stack *channel_stack,
                           const void *transport_server_data,
-                          grpc_transport_op *initial_op,
+                          grpc_transport_stream_op *initial_op,
                           grpc_call_stack *call_stack);
 /* Destroy a call stack */
 void grpc_call_stack_destroy(grpc_call_stack *stack);
 
 /* Call the next operation in a call stack */
-void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op);
+void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op);
 /* Call the next operation (depending on call directionality) in a channel
    stack */
-void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op);
+void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op);
 
 /* Given the top element of a channel stack, get the channel stack itself */
 grpc_channel_stack *grpc_channel_stack_from_top_element(
@@ -219,7 +181,7 @@
 grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
 
 void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
-                      grpc_call_element *elem, grpc_transport_op *op);
+                      grpc_call_element *elem, grpc_transport_stream_op *op);
 
 void grpc_call_element_send_cancel(grpc_call_element *cur_elem);
 
diff --git a/src/core/channel/child_channel.c b/src/core/channel/child_channel.c
deleted file mode 100644
index 600f7df..0000000
--- a/src/core/channel/child_channel.c
+++ /dev/null
@@ -1,307 +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.
- *
- */
-
-#include "src/core/channel/child_channel.h"
-#include "src/core/iomgr/iomgr.h"
-#include <grpc/support/alloc.h>
-
-/* Link back filter: passes up calls to the client channel, pushes down calls
-   down */
-
-static void maybe_destroy_channel(grpc_child_channel *channel);
-
-typedef struct {
-  gpr_mu mu;
-  gpr_cv cv;
-  grpc_channel_element *back;
-  /* # of active calls on the channel */
-  gpr_uint32 active_calls;
-  /* has grpc_child_channel_destroy been called? */
-  gpr_uint8 destroyed;
-  /* has the transport reported itself disconnected? */
-  gpr_uint8 disconnected;
-  /* are we calling 'back' - our parent channel */
-  gpr_uint8 calling_back;
-  /* have we or our parent sent goaway yet? - dup suppression */
-  gpr_uint8 sent_goaway;
-  /* are we currently sending farewell (in this file: goaway + disconnect) */
-  gpr_uint8 sending_farewell;
-  /* have we sent farewell (goaway + disconnect) */
-  gpr_uint8 sent_farewell;
-
-  grpc_iomgr_closure finally_destroy_channel_closure;
-  grpc_iomgr_closure send_farewells_closure;
-} lb_channel_data;
-
-typedef struct { grpc_child_channel *channel; } lb_call_data;
-
-static void lb_start_transport_op(grpc_call_element *elem,
-                                  grpc_transport_op *op) {
-  grpc_call_next_op(elem, op);
-}
-
-/* Currently we assume all channel operations should just be pushed up. */
-static void lb_channel_op(grpc_channel_element *elem,
-                          grpc_channel_element *from_elem,
-                          grpc_channel_op *op) {
-  lb_channel_data *chand = elem->channel_data;
-  grpc_channel_element *back;
-  int calling_back = 0;
-
-  switch (op->dir) {
-    case GRPC_CALL_UP:
-      gpr_mu_lock(&chand->mu);
-      back = chand->back;
-      if (back) {
-        chand->calling_back++;
-        calling_back = 1;
-      }
-      gpr_mu_unlock(&chand->mu);
-      if (back) {
-        back->filter->channel_op(chand->back, elem, op);
-      } else if (op->type == GRPC_TRANSPORT_GOAWAY) {
-        gpr_slice_unref(op->data.goaway.message);
-      }
-      break;
-    case GRPC_CALL_DOWN:
-      grpc_channel_next_op(elem, op);
-      break;
-  }
-
-  gpr_mu_lock(&chand->mu);
-  switch (op->type) {
-    case GRPC_TRANSPORT_CLOSED:
-      chand->disconnected = 1;
-      maybe_destroy_channel(grpc_channel_stack_from_top_element(elem));
-      break;
-    case GRPC_CHANNEL_GOAWAY:
-      chand->sent_goaway = 1;
-      break;
-    case GRPC_CHANNEL_DISCONNECT:
-    case GRPC_TRANSPORT_GOAWAY:
-    case GRPC_ACCEPT_CALL:
-      break;
-  }
-
-  if (calling_back) {
-    chand->calling_back--;
-    gpr_cv_signal(&chand->cv);
-    maybe_destroy_channel(grpc_channel_stack_from_top_element(elem));
-  }
-  gpr_mu_unlock(&chand->mu);
-}
-
-/* Constructor for call_data */
-static void lb_init_call_elem(grpc_call_element *elem,
-                              const void *server_transport_data,
-                              grpc_transport_op *initial_op) {}
-
-/* Destructor for call_data */
-static void lb_destroy_call_elem(grpc_call_element *elem) {}
-
-/* Constructor for channel_data */
-static void lb_init_channel_elem(grpc_channel_element *elem,
-                                 const grpc_channel_args *args,
-                                 grpc_mdctx *metadata_context, int is_first,
-                                 int is_last) {
-  lb_channel_data *chand = elem->channel_data;
-  GPR_ASSERT(is_first);
-  GPR_ASSERT(!is_last);
-  gpr_mu_init(&chand->mu);
-  gpr_cv_init(&chand->cv);
-  chand->back = NULL;
-  chand->destroyed = 0;
-  chand->disconnected = 0;
-  chand->active_calls = 0;
-  chand->sent_goaway = 0;
-  chand->calling_back = 0;
-  chand->sending_farewell = 0;
-  chand->sent_farewell = 0;
-}
-
-/* Destructor for channel_data */
-static void lb_destroy_channel_elem(grpc_channel_element *elem) {
-  lb_channel_data *chand = elem->channel_data;
-  gpr_mu_destroy(&chand->mu);
-  gpr_cv_destroy(&chand->cv);
-}
-
-const grpc_channel_filter grpc_child_channel_top_filter = {
-    lb_start_transport_op, lb_channel_op,           sizeof(lb_call_data),
-    lb_init_call_elem,     lb_destroy_call_elem,    sizeof(lb_channel_data),
-    lb_init_channel_elem,  lb_destroy_channel_elem, "child-channel",
-};
-
-/* grpc_child_channel proper */
-
-#define LINK_BACK_ELEM_FROM_CHANNEL(channel) \
-  grpc_channel_stack_element((channel), 0)
-
-#define LINK_BACK_ELEM_FROM_CALL(call) grpc_call_stack_element((call), 0)
-
-static void finally_destroy_channel(void *c, int success) {
-  /* ignore success or not... this is a destruction callback and will only
-     happen once - the only purpose here is to release resources */
-  grpc_child_channel *channel = c;
-  lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
-  /* wait for the initiator to leave the mutex */
-  gpr_mu_lock(&chand->mu);
-  gpr_mu_unlock(&chand->mu);
-  grpc_channel_stack_destroy(channel);
-  gpr_free(channel);
-}
-
-static void send_farewells(void *c, int success) {
-  grpc_child_channel *channel = c;
-  grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel);
-  lb_channel_data *chand = lbelem->channel_data;
-  int send_goaway;
-  grpc_channel_op op;
-
-  gpr_mu_lock(&chand->mu);
-  send_goaway = !chand->sent_goaway;
-  chand->sent_goaway = 1;
-  gpr_mu_unlock(&chand->mu);
-
-  if (send_goaway) {
-    op.type = GRPC_CHANNEL_GOAWAY;
-    op.dir = GRPC_CALL_DOWN;
-    op.data.goaway.status = GRPC_STATUS_OK;
-    op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect");
-    grpc_channel_next_op(lbelem, &op);
-  }
-
-  op.type = GRPC_CHANNEL_DISCONNECT;
-  op.dir = GRPC_CALL_DOWN;
-  grpc_channel_next_op(lbelem, &op);
-
-  gpr_mu_lock(&chand->mu);
-  chand->sending_farewell = 0;
-  chand->sent_farewell = 1;
-  maybe_destroy_channel(channel);
-  gpr_mu_unlock(&chand->mu);
-}
-
-static void maybe_destroy_channel(grpc_child_channel *channel) {
-  lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
-  if (chand->destroyed && chand->disconnected && chand->active_calls == 0 &&
-      !chand->sending_farewell && !chand->calling_back) {
-    chand->finally_destroy_channel_closure.cb = finally_destroy_channel;
-    chand->finally_destroy_channel_closure.cb_arg = channel;
-    grpc_iomgr_add_callback(&chand->finally_destroy_channel_closure);
-  } else if (chand->destroyed && !chand->disconnected &&
-             chand->active_calls == 0 && !chand->sending_farewell &&
-             !chand->sent_farewell) {
-    chand->sending_farewell = 1;
-    chand->send_farewells_closure.cb = send_farewells;
-    chand->send_farewells_closure.cb_arg = channel;
-    grpc_iomgr_add_callback(&chand->send_farewells_closure);
-  }
-}
-
-grpc_child_channel *grpc_child_channel_create(
-    grpc_channel_element *parent, const grpc_channel_filter **filters,
-    size_t filter_count, const grpc_channel_args *args,
-    grpc_mdctx *metadata_context) {
-  grpc_channel_stack *stk =
-      gpr_malloc(grpc_channel_stack_size(filters, filter_count));
-  lb_channel_data *lb;
-
-  grpc_channel_stack_init(filters, filter_count, args, metadata_context, stk);
-
-  lb = LINK_BACK_ELEM_FROM_CHANNEL(stk)->channel_data;
-  gpr_mu_lock(&lb->mu);
-  lb->back = parent;
-  gpr_mu_unlock(&lb->mu);
-
-  return stk;
-}
-
-void grpc_child_channel_destroy(grpc_child_channel *channel,
-                                int wait_for_callbacks) {
-  grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel);
-  lb_channel_data *chand = lbelem->channel_data;
-
-  gpr_mu_lock(&chand->mu);
-  while (wait_for_callbacks && chand->calling_back) {
-    gpr_cv_wait(&chand->cv, &chand->mu, gpr_inf_future);
-  }
-
-  chand->back = NULL;
-  chand->destroyed = 1;
-  maybe_destroy_channel(channel);
-  gpr_mu_unlock(&chand->mu);
-}
-
-void grpc_child_channel_handle_op(grpc_child_channel *channel,
-                                  grpc_channel_op *op) {
-  grpc_channel_next_op(LINK_BACK_ELEM_FROM_CHANNEL(channel), op);
-}
-
-grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
-                                                grpc_call_element *parent,
-                                                grpc_transport_op *initial_op) {
-  grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size);
-  grpc_call_element *lbelem;
-  lb_call_data *lbcalld;
-  lb_channel_data *lbchand;
-
-  grpc_call_stack_init(channel, NULL, initial_op, stk);
-  lbelem = LINK_BACK_ELEM_FROM_CALL(stk);
-  lbchand = lbelem->channel_data;
-  lbcalld = lbelem->call_data;
-  lbcalld->channel = channel;
-
-  gpr_mu_lock(&lbchand->mu);
-  lbchand->active_calls++;
-  gpr_mu_unlock(&lbchand->mu);
-
-  return stk;
-}
-
-void grpc_child_call_destroy(grpc_child_call *call) {
-  grpc_call_element *lbelem = LINK_BACK_ELEM_FROM_CALL(call);
-  lb_call_data *calld = lbelem->call_data;
-  lb_channel_data *chand = lbelem->channel_data;
-  grpc_child_channel *channel = calld->channel;
-  grpc_call_stack_destroy(call);
-  gpr_free(call);
-  gpr_mu_lock(&chand->mu);
-  chand->active_calls--;
-  maybe_destroy_channel(channel);
-  gpr_mu_unlock(&chand->mu);
-}
-
-grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call) {
-  return LINK_BACK_ELEM_FROM_CALL(call);
-}
diff --git a/src/core/channel/child_channel.h b/src/core/channel/child_channel.h
deleted file mode 100644
index 556a1c7..0000000
--- a/src/core/channel/child_channel.h
+++ /dev/null
@@ -1,65 +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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H
-
-#include "src/core/channel/channel_stack.h"
-
-/* helper for filters that need to host child channel stacks... handles
-   lifetime and upwards propagation cleanly */
-
-extern const grpc_channel_filter grpc_child_channel_top_filter;
-
-typedef grpc_channel_stack grpc_child_channel;
-typedef grpc_call_stack grpc_child_call;
-
-/* filters[0] must be &grpc_child_channel_top_filter */
-grpc_child_channel *grpc_child_channel_create(
-    grpc_channel_element *parent, const grpc_channel_filter **filters,
-    size_t filter_count, const grpc_channel_args *args,
-    grpc_mdctx *metadata_context);
-void grpc_child_channel_handle_op(grpc_child_channel *channel,
-                                  grpc_channel_op *op);
-grpc_channel_element *grpc_child_channel_get_bottom_element(
-    grpc_child_channel *channel);
-void grpc_child_channel_destroy(grpc_child_channel *channel,
-                                int wait_for_callbacks);
-
-grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
-                                                grpc_call_element *parent,
-                                                grpc_transport_op *initial_op);
-grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call);
-void grpc_child_call_destroy(grpc_child_call *call);
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 42e242a..10e01eb 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -34,12 +34,15 @@
 #include "src/core/channel/client_channel.h"
 
 #include <stdio.h>
+#include <string.h>
 
 #include "src/core/channel/channel_args.h"
-#include "src/core/channel/child_channel.h"
 #include "src/core/channel/connected_channel.h"
+#include "src/core/surface/channel.h"
 #include "src/core/iomgr/iomgr.h"
+#include "src/core/iomgr/pollset_set.h"
 #include "src/core/support/string.h"
+#include "src/core/transport/connectivity_state.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
@@ -50,31 +53,38 @@
 typedef struct call_data call_data;
 
 typedef struct {
-  /* protects children, child_count, child_capacity, active_child,
-     transport_setup_initiated
-     does not protect channel stacks held by children
-     transport_setup is assumed to be set once during construction */
-  gpr_mu mu;
-
-  /* the sending child (may be null) */
-  grpc_child_channel *active_child;
+  /** metadata context for this channel */
   grpc_mdctx *mdctx;
+  /** resolver for this channel */
+  grpc_resolver *resolver;
+  /** master channel - the grpc_channel instance that ultimately owns
+      this channel_data via its channel stack.
+      We occasionally use this to bump the refcount on the master channel
+      to keep ourselves alive through an asynchronous operation. */
+  grpc_channel *master;
 
-  /* calls waiting for a channel to be ready */
-  call_data **waiting_children;
-  size_t waiting_child_count;
-  size_t waiting_child_capacity;
-
-  /* transport setup for this channel */
-  grpc_transport_setup *transport_setup;
-  int transport_setup_initiated;
-
-  grpc_channel_args *args;
+  /** mutex protecting client configuration, including all
+      variables below in this data structure */
+  gpr_mu mu_config;
+  /** currently active load balancer - guarded by mu_config */
+  grpc_lb_policy *lb_policy;
+  /** incoming configuration - set by resolver.next
+      guarded by mu_config */
+  grpc_client_config *incoming_configuration;
+  /** a list of closures that are all waiting for config to come in */
+  grpc_iomgr_closure *waiting_for_config_closures;
+  /** resolver callback */
+  grpc_iomgr_closure on_config_changed;
+  /** connectivity state being tracked */
+  grpc_connectivity_state_tracker state_tracker;
 } channel_data;
 
 typedef enum {
   CALL_CREATED,
-  CALL_WAITING,
+  CALL_WAITING_FOR_SEND,
+  CALL_WAITING_FOR_CONFIG,
+  CALL_WAITING_FOR_PICK,
+  CALL_WAITING_FOR_CALL,
   CALL_ACTIVE,
   CALL_CANCELLED
 } call_state;
@@ -83,273 +93,421 @@
   /* owning element */
   grpc_call_element *elem;
 
+  gpr_mu mu_state;
+
   call_state state;
   gpr_timespec deadline;
-  union {
-    struct {
-      /* our child call stack */
-      grpc_child_call *child_call;
-    } active;
-    grpc_transport_op waiting_op;
-    struct {
-      grpc_linked_mdelem status;
-      grpc_linked_mdelem details;
-    } cancelled;
-  } s;
+  grpc_subchannel *picked_channel;
+  grpc_iomgr_closure async_setup_task;
+  grpc_transport_stream_op waiting_op;
+  /* our child call stack */
+  grpc_subchannel_call *subchannel_call;
+  grpc_linked_mdelem status;
+  grpc_linked_mdelem details;
 };
 
-static int prepare_activate(grpc_call_element *elem,
-                            grpc_child_channel *on_child) {
-  call_data *calld = elem->call_data;
-  if (calld->state == CALL_CANCELLED) return 0;
-
-  /* no more access to calld->s.waiting allowed */
-  GPR_ASSERT(calld->state == CALL_WAITING);
-  calld->state = CALL_ACTIVE;
-
-  /* create a child call */
-  /* TODO(ctiller): pass the waiting op down here */
-  calld->s.active.child_call =
-      grpc_child_channel_create_call(on_child, elem, NULL);
-
-  return 1;
-}
-
-static void complete_activate(grpc_call_element *elem, grpc_transport_op *op) {
-  call_data *calld = elem->call_data;
-  grpc_call_element *child_elem =
-      grpc_child_call_get_top_element(calld->s.active.child_call);
-
-  GPR_ASSERT(calld->state == CALL_ACTIVE);
-
-  /* continue the start call down the stack, this nees to happen after metadata
-     are flushed*/
-  child_elem->filter->start_transport_op(child_elem, op);
-}
-
-static void remove_waiting_child(channel_data *chand, call_data *calld) {
-  size_t new_count;
-  size_t i;
-  for (i = 0, new_count = 0; i < chand->waiting_child_count; i++) {
-    if (chand->waiting_children[i] == calld) continue;
-    chand->waiting_children[new_count++] = chand->waiting_children[i];
-  }
-  GPR_ASSERT(new_count == chand->waiting_child_count - 1 ||
-             new_count == chand->waiting_child_count);
-  chand->waiting_child_count = new_count;
-}
+static grpc_iomgr_closure *merge_into_waiting_op(
+    grpc_call_element *elem,
+    grpc_transport_stream_op *new_op) GRPC_MUST_USE_RESULT;
 
 static void handle_op_after_cancellation(grpc_call_element *elem,
-                                         grpc_transport_op *op) {
+                                         grpc_transport_stream_op *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   if (op->send_ops) {
     grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops);
-    op->on_done_send(op->send_user_data, 0);
+    op->on_done_send->cb(op->on_done_send->cb_arg, 0);
   }
   if (op->recv_ops) {
     char status[GPR_LTOA_MIN_BUFSIZE];
     grpc_metadata_batch mdb;
     gpr_ltoa(GRPC_STATUS_CANCELLED, status);
-    calld->s.cancelled.status.md =
+    calld->status.md =
         grpc_mdelem_from_strings(chand->mdctx, "grpc-status", status);
-    calld->s.cancelled.details.md =
+    calld->details.md =
         grpc_mdelem_from_strings(chand->mdctx, "grpc-message", "Cancelled");
-    calld->s.cancelled.status.prev = calld->s.cancelled.details.next = NULL;
-    calld->s.cancelled.status.next = &calld->s.cancelled.details;
-    calld->s.cancelled.details.prev = &calld->s.cancelled.status;
-    mdb.list.head = &calld->s.cancelled.status;
-    mdb.list.tail = &calld->s.cancelled.details;
+    calld->status.prev = calld->details.next = NULL;
+    calld->status.next = &calld->details;
+    calld->details.prev = &calld->status;
+    mdb.list.head = &calld->status;
+    mdb.list.tail = &calld->details;
     mdb.garbage.head = mdb.garbage.tail = NULL;
-    mdb.deadline = gpr_inf_future;
+    mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
     grpc_sopb_add_metadata(op->recv_ops, mdb);
     *op->recv_state = GRPC_STREAM_CLOSED;
-    op->on_done_recv(op->recv_user_data, 1);
+    op->on_done_recv->cb(op->on_done_recv->cb_arg, 1);
+  }
+  if (op->on_consumed) {
+    op->on_consumed->cb(op->on_consumed->cb_arg, 0);
   }
 }
 
-static void cc_start_transport_op(grpc_call_element *elem,
-                                  grpc_transport_op *op) {
+typedef struct {
+  grpc_iomgr_closure closure;
+  grpc_call_element *elem;
+} waiting_call;
+
+static void perform_transport_stream_op(grpc_call_element *elem,
+                                        grpc_transport_stream_op *op,
+                                        int continuation);
+
+static void continue_with_pick(void *arg, int iomgr_success) {
+  waiting_call *wc = arg;
+  call_data *calld = wc->elem->call_data;
+  perform_transport_stream_op(wc->elem, &calld->waiting_op, 1);
+  gpr_free(wc);
+}
+
+static void add_to_lb_policy_wait_queue_locked_state_config(
+    grpc_call_element *elem) {
+  channel_data *chand = elem->channel_data;
+  waiting_call *wc = gpr_malloc(sizeof(*wc));
+  grpc_iomgr_closure_init(&wc->closure, continue_with_pick, wc);
+  wc->elem = elem;
+  wc->closure.next = chand->waiting_for_config_closures;
+  chand->waiting_for_config_closures = &wc->closure;
+}
+
+static int is_empty(void *p, int len) {
+  char *ptr = p;
+  int i;
+  for (i = 0; i < len; i++) {
+    if (ptr[i] != 0) return 0;
+  }
+  return 1;
+}
+
+static void started_call(void *arg, int iomgr_success) {
+  call_data *calld = arg;
+  grpc_transport_stream_op op;
+  int have_waiting;
+
+  gpr_mu_lock(&calld->mu_state);
+  if (calld->state == CALL_CANCELLED && calld->subchannel_call != NULL) {
+    memset(&op, 0, sizeof(op));
+    op.cancel_with_status = GRPC_STATUS_CANCELLED;
+    gpr_mu_unlock(&calld->mu_state);
+    grpc_subchannel_call_process_op(calld->subchannel_call, &op);
+  } else if (calld->state == CALL_WAITING_FOR_CALL) {
+    have_waiting = !is_empty(&calld->waiting_op, sizeof(calld->waiting_op));
+    if (calld->subchannel_call != NULL) {
+      calld->state = CALL_ACTIVE;
+      gpr_mu_unlock(&calld->mu_state);
+      if (have_waiting) {
+        grpc_subchannel_call_process_op(calld->subchannel_call,
+                                        &calld->waiting_op);
+      }
+    } else {
+      calld->state = CALL_CANCELLED;
+      gpr_mu_unlock(&calld->mu_state);
+      if (have_waiting) {
+        handle_op_after_cancellation(calld->elem, &calld->waiting_op);
+      }
+    }
+  } else {
+    GPR_ASSERT(calld->state == CALL_CANCELLED);
+    gpr_mu_unlock(&calld->mu_state);
+  }
+}
+
+static void picked_target(void *arg, int iomgr_success) {
+  call_data *calld = arg;
+  grpc_pollset *pollset;
+
+  if (calld->picked_channel == NULL) {
+    /* treat this like a cancellation */
+    calld->waiting_op.cancel_with_status = GRPC_STATUS_UNAVAILABLE;
+    perform_transport_stream_op(calld->elem, &calld->waiting_op, 1);
+  } else {
+    gpr_mu_lock(&calld->mu_state);
+    if (calld->state == CALL_CANCELLED) {
+      gpr_mu_unlock(&calld->mu_state);
+      handle_op_after_cancellation(calld->elem, &calld->waiting_op);
+    } else {
+      GPR_ASSERT(calld->state == CALL_WAITING_FOR_PICK);
+      calld->state = CALL_WAITING_FOR_CALL;
+      pollset = calld->waiting_op.bind_pollset;
+      gpr_mu_unlock(&calld->mu_state);
+      grpc_iomgr_closure_init(&calld->async_setup_task, started_call, calld);
+      grpc_subchannel_create_call(calld->picked_channel, pollset,
+                                  &calld->subchannel_call,
+                                  &calld->async_setup_task);
+    }
+  }
+}
+
+static void pick_target(grpc_lb_policy *lb_policy, call_data *calld) {
+  grpc_metadata_batch *initial_metadata;
+  grpc_transport_stream_op *op = &calld->waiting_op;
+
+  GPR_ASSERT(op->bind_pollset);
+  GPR_ASSERT(op->send_ops);
+  GPR_ASSERT(op->send_ops->nops >= 1);
+  GPR_ASSERT(op->send_ops->ops[0].type == GRPC_OP_METADATA);
+  initial_metadata = &op->send_ops->ops[0].data.metadata;
+
+  grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, calld);
+  grpc_lb_policy_pick(lb_policy, op->bind_pollset, initial_metadata,
+                      &calld->picked_channel, &calld->async_setup_task);
+}
+
+static grpc_iomgr_closure *merge_into_waiting_op(
+    grpc_call_element *elem, grpc_transport_stream_op *new_op) {
+  call_data *calld = elem->call_data;
+  grpc_iomgr_closure *consumed_op = NULL;
+  grpc_transport_stream_op *waiting_op = &calld->waiting_op;
+  GPR_ASSERT((waiting_op->send_ops != NULL) + (new_op->send_ops != NULL) <= 1);
+  GPR_ASSERT((waiting_op->recv_ops != NULL) + (new_op->recv_ops != NULL) <= 1);
+  if (new_op->send_ops != NULL) {
+    waiting_op->send_ops = new_op->send_ops;
+    waiting_op->is_last_send = new_op->is_last_send;
+    waiting_op->on_done_send = new_op->on_done_send;
+  }
+  if (new_op->recv_ops != NULL) {
+    waiting_op->recv_ops = new_op->recv_ops;
+    waiting_op->recv_state = new_op->recv_state;
+    waiting_op->on_done_recv = new_op->on_done_recv;
+  }
+  if (new_op->on_consumed != NULL) {
+    if (waiting_op->on_consumed != NULL) {
+      consumed_op = waiting_op->on_consumed;
+    }
+    waiting_op->on_consumed = new_op->on_consumed;
+  }
+  if (new_op->cancel_with_status != GRPC_STATUS_OK) {
+    waiting_op->cancel_with_status = new_op->cancel_with_status;
+  }
+  return consumed_op;
+}
+
+static void perform_transport_stream_op(grpc_call_element *elem,
+                                        grpc_transport_stream_op *op,
+                                        int continuation) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
-  grpc_call_element *child_elem;
-  grpc_transport_op waiting_op;
+  grpc_subchannel_call *subchannel_call;
+  grpc_lb_policy *lb_policy;
+  grpc_transport_stream_op op2;
+  grpc_iomgr_closure *consumed_op = NULL;
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 
-  gpr_mu_lock(&chand->mu);
+  gpr_mu_lock(&calld->mu_state);
   switch (calld->state) {
     case CALL_ACTIVE:
-      child_elem = grpc_child_call_get_top_element(calld->s.active.child_call);
-      gpr_mu_unlock(&chand->mu);
-      child_elem->filter->start_transport_op(child_elem, op);
+      GPR_ASSERT(!continuation);
+      subchannel_call = calld->subchannel_call;
+      gpr_mu_unlock(&calld->mu_state);
+      grpc_subchannel_call_process_op(subchannel_call, op);
       break;
+    case CALL_CANCELLED:
+      gpr_mu_unlock(&calld->mu_state);
+      handle_op_after_cancellation(elem, op);
+      break;
+    case CALL_WAITING_FOR_SEND:
+      GPR_ASSERT(!continuation);
+      consumed_op = merge_into_waiting_op(elem, op);
+      if (!calld->waiting_op.send_ops &&
+          calld->waiting_op.cancel_with_status == GRPC_STATUS_OK) {
+        gpr_mu_unlock(&calld->mu_state);
+        break;
+      }
+      *op = calld->waiting_op;
+      memset(&calld->waiting_op, 0, sizeof(calld->waiting_op));
+      continuation = 1;
+    /* fall through */
+    case CALL_WAITING_FOR_CONFIG:
+    case CALL_WAITING_FOR_PICK:
+    case CALL_WAITING_FOR_CALL:
+      if (!continuation) {
+        if (op->cancel_with_status != GRPC_STATUS_OK) {
+          calld->state = CALL_CANCELLED;
+          op2 = calld->waiting_op;
+          memset(&calld->waiting_op, 0, sizeof(calld->waiting_op));
+          if (op->on_consumed) {
+            calld->waiting_op.on_consumed = op->on_consumed;
+            op->on_consumed = NULL;
+          } else if (op2.on_consumed) {
+            calld->waiting_op.on_consumed = op2.on_consumed;
+            op2.on_consumed = NULL;
+          }
+          gpr_mu_unlock(&calld->mu_state);
+          handle_op_after_cancellation(elem, op);
+          handle_op_after_cancellation(elem, &op2);
+        } else {
+          consumed_op = merge_into_waiting_op(elem, op);
+          gpr_mu_unlock(&calld->mu_state);
+        }
+        break;
+      }
+    /* fall through */
     case CALL_CREATED:
       if (op->cancel_with_status != GRPC_STATUS_OK) {
         calld->state = CALL_CANCELLED;
-        gpr_mu_unlock(&chand->mu);
+        gpr_mu_unlock(&calld->mu_state);
         handle_op_after_cancellation(elem, op);
       } else {
-        calld->state = CALL_WAITING;
-        if (chand->active_child) {
-          /* channel is connected - use the connected stack */
-          if (prepare_activate(elem, chand->active_child)) {
-            gpr_mu_unlock(&chand->mu);
-            /* activate the request (pass it down) outside the lock */
-            complete_activate(elem, op);
-          } else {
-            gpr_mu_unlock(&chand->mu);
-          }
-        } else {
-          /* check to see if we should initiate a connection (if we're not
-             already),
-             but don't do so until outside the lock to avoid re-entrancy
-             problems if
-             the callback is immediate */
-          int initiate_transport_setup = 0;
-          if (!chand->transport_setup_initiated) {
-            chand->transport_setup_initiated = 1;
-            initiate_transport_setup = 1;
-          }
-          /* add this call to the waiting set to be resumed once we have a child
-             channel stack, growing the waiting set if needed */
-          if (chand->waiting_child_count == chand->waiting_child_capacity) {
-            chand->waiting_child_capacity =
-                GPR_MAX(chand->waiting_child_capacity * 2, 8);
-            chand->waiting_children = gpr_realloc(
-                chand->waiting_children,
-                chand->waiting_child_capacity * sizeof(call_data *));
-          }
-          calld->s.waiting_op = *op;
-          chand->waiting_children[chand->waiting_child_count++] = calld;
-          gpr_mu_unlock(&chand->mu);
+        calld->waiting_op = *op;
 
-          /* finally initiate transport setup if needed */
-          if (initiate_transport_setup) {
-            grpc_transport_setup_initiate(chand->transport_setup);
+        if (op->send_ops == NULL) {
+          /* need to have some send ops before we can select the
+             lb target */
+          calld->state = CALL_WAITING_FOR_SEND;
+          gpr_mu_unlock(&calld->mu_state);
+        } else {
+          gpr_mu_lock(&chand->mu_config);
+          lb_policy = chand->lb_policy;
+          if (lb_policy) {
+            GRPC_LB_POLICY_REF(lb_policy, "pick");
+            gpr_mu_unlock(&chand->mu_config);
+            calld->state = CALL_WAITING_FOR_PICK;
+            gpr_mu_unlock(&calld->mu_state);
+
+            pick_target(lb_policy, calld);
+
+            GRPC_LB_POLICY_UNREF(lb_policy, "pick");
+          } else if (chand->resolver != NULL) {
+            calld->state = CALL_WAITING_FOR_CONFIG;
+            add_to_lb_policy_wait_queue_locked_state_config(elem);
+            gpr_mu_unlock(&chand->mu_config);
+            gpr_mu_unlock(&calld->mu_state);
+          } else {
+            calld->state = CALL_CANCELLED;
+            gpr_mu_unlock(&chand->mu_config);
+            gpr_mu_unlock(&calld->mu_state);
+            handle_op_after_cancellation(elem, op);
           }
         }
       }
       break;
-    case CALL_WAITING:
-      if (op->cancel_with_status != GRPC_STATUS_OK) {
-        waiting_op = calld->s.waiting_op;
-        remove_waiting_child(chand, calld);
-        calld->state = CALL_CANCELLED;
-        gpr_mu_unlock(&chand->mu);
-        handle_op_after_cancellation(elem, &waiting_op);
-        handle_op_after_cancellation(elem, op);
-      } else {
-        GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) !=
-                   (op->send_ops == NULL));
-        GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) !=
-                   (op->recv_ops == NULL));
-        if (op->send_ops) {
-          calld->s.waiting_op.send_ops = op->send_ops;
-          calld->s.waiting_op.is_last_send = op->is_last_send;
-          calld->s.waiting_op.on_done_send = op->on_done_send;
-          calld->s.waiting_op.send_user_data = op->send_user_data;
-        }
-        if (op->recv_ops) {
-          calld->s.waiting_op.recv_ops = op->recv_ops;
-          calld->s.waiting_op.recv_state = op->recv_state;
-          calld->s.waiting_op.on_done_recv = op->on_done_recv;
-          calld->s.waiting_op.recv_user_data = op->recv_user_data;
-        }
-        gpr_mu_unlock(&chand->mu);
-      }
-      break;
-    case CALL_CANCELLED:
-      gpr_mu_unlock(&chand->mu);
-      handle_op_after_cancellation(elem, op);
-      break;
+  }
+
+  if (consumed_op != NULL) {
+    consumed_op->cb(consumed_op->cb_arg, 1);
   }
 }
 
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  channel_data *chand = elem->channel_data;
-  grpc_child_channel *child_channel;
-  grpc_channel_op rop;
-  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+static void cc_start_transport_stream_op(grpc_call_element *elem,
+                                         grpc_transport_stream_op *op) {
+  perform_transport_stream_op(elem, op, 0);
+}
 
-  switch (op->type) {
-    case GRPC_CHANNEL_GOAWAY:
-      /* sending goaway: clear out the active child on the way through */
-      gpr_mu_lock(&chand->mu);
-      child_channel = chand->active_child;
-      chand->active_child = NULL;
-      gpr_mu_unlock(&chand->mu);
-      if (child_channel) {
-        grpc_child_channel_handle_op(child_channel, op);
-        grpc_child_channel_destroy(child_channel, 1);
-      } else {
-        gpr_slice_unref(op->data.goaway.message);
-      }
-      break;
-    case GRPC_CHANNEL_DISCONNECT:
-      /* sending disconnect: clear out the active child on the way through */
-      gpr_mu_lock(&chand->mu);
-      child_channel = chand->active_child;
-      chand->active_child = NULL;
-      gpr_mu_unlock(&chand->mu);
-      if (child_channel) {
-        grpc_child_channel_destroy(child_channel, 1);
-      }
-      /* fake a transport closed to satisfy the refcounting in client */
-      rop.type = GRPC_TRANSPORT_CLOSED;
-      rop.dir = GRPC_CALL_UP;
-      grpc_channel_next_op(elem, &rop);
-      break;
-    case GRPC_TRANSPORT_GOAWAY:
-      /* receiving goaway: if it's from our active child, drop the active child;
-         in all cases consume the event here */
-      gpr_mu_lock(&chand->mu);
-      child_channel = grpc_channel_stack_from_top_element(from_elem);
-      if (child_channel == chand->active_child) {
-        chand->active_child = NULL;
-      } else {
-        child_channel = NULL;
-      }
-      gpr_mu_unlock(&chand->mu);
-      if (child_channel) {
-        grpc_child_channel_destroy(child_channel, 0);
-      }
-      gpr_slice_unref(op->data.goaway.message);
-      break;
-    case GRPC_TRANSPORT_CLOSED:
-      /* receiving disconnect: if it's from our active child, drop the active
-         child; in all cases consume the event here */
-      gpr_mu_lock(&chand->mu);
-      child_channel = grpc_channel_stack_from_top_element(from_elem);
-      if (child_channel == chand->active_child) {
-        chand->active_child = NULL;
-      } else {
-        child_channel = NULL;
-      }
-      gpr_mu_unlock(&chand->mu);
-      if (child_channel) {
-        grpc_child_channel_destroy(child_channel, 0);
-      }
-      break;
-    default:
-      switch (op->dir) {
-        case GRPC_CALL_UP:
-          grpc_channel_next_op(elem, op);
-          break;
-        case GRPC_CALL_DOWN:
-          gpr_log(GPR_ERROR, "unhandled channel op: %d", op->type);
-          abort();
-          break;
-      }
-      break;
+static void cc_on_config_changed(void *arg, int iomgr_success) {
+  channel_data *chand = arg;
+  grpc_lb_policy *lb_policy = NULL;
+  grpc_lb_policy *old_lb_policy;
+  grpc_resolver *old_resolver;
+  grpc_iomgr_closure *wakeup_closures = NULL;
+
+  if (chand->incoming_configuration != NULL) {
+    lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
+    GRPC_LB_POLICY_REF(lb_policy, "channel");
+
+    grpc_client_config_unref(chand->incoming_configuration);
+  }
+
+  chand->incoming_configuration = NULL;
+
+  gpr_mu_lock(&chand->mu_config);
+  old_lb_policy = chand->lb_policy;
+  chand->lb_policy = lb_policy;
+  if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) {
+    wakeup_closures = chand->waiting_for_config_closures;
+    chand->waiting_for_config_closures = NULL;
+  }
+  gpr_mu_unlock(&chand->mu_config);
+
+  if (old_lb_policy) {
+    GRPC_LB_POLICY_UNREF(old_lb_policy, "channel");
+  }
+
+  gpr_mu_lock(&chand->mu_config);
+  if (iomgr_success && chand->resolver) {
+    grpc_resolver *resolver = chand->resolver;
+    GRPC_RESOLVER_REF(resolver, "channel-next");
+    gpr_mu_unlock(&chand->mu_config);
+    GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
+    grpc_resolver_next(resolver, &chand->incoming_configuration,
+                       &chand->on_config_changed);
+    GRPC_RESOLVER_UNREF(resolver, "channel-next");
+  } else {
+    old_resolver = chand->resolver;
+    chand->resolver = NULL;
+    grpc_connectivity_state_set(&chand->state_tracker,
+                                GRPC_CHANNEL_FATAL_FAILURE);
+    gpr_mu_unlock(&chand->mu_config);
+    if (old_resolver != NULL) {
+      grpc_resolver_shutdown(old_resolver);
+      GRPC_RESOLVER_UNREF(old_resolver, "channel");
+    }
+  }
+
+  while (wakeup_closures) {
+    grpc_iomgr_closure *next = wakeup_closures->next;
+    grpc_iomgr_add_callback(wakeup_closures);
+    wakeup_closures = next;
+  }
+
+  GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver");
+}
+
+static void cc_start_transport_op(grpc_channel_element *elem,
+                                  grpc_transport_op *op) {
+  grpc_lb_policy *lb_policy = NULL;
+  channel_data *chand = elem->channel_data;
+  grpc_resolver *destroy_resolver = NULL;
+  grpc_iomgr_closure *on_consumed = op->on_consumed;
+  op->on_consumed = NULL;
+
+  GPR_ASSERT(op->set_accept_stream == NULL);
+  GPR_ASSERT(op->bind_pollset == NULL);
+
+  gpr_mu_lock(&chand->mu_config);
+  if (op->on_connectivity_state_change != NULL) {
+    grpc_connectivity_state_notify_on_state_change(
+        &chand->state_tracker, op->connectivity_state,
+        op->on_connectivity_state_change);
+    op->on_connectivity_state_change = NULL;
+    op->connectivity_state = NULL;
+  }
+
+  if (op->disconnect && chand->resolver != NULL) {
+    grpc_connectivity_state_set(&chand->state_tracker,
+                                GRPC_CHANNEL_FATAL_FAILURE);
+    destroy_resolver = chand->resolver;
+    chand->resolver = NULL;
+    if (chand->lb_policy != NULL) {
+      grpc_lb_policy_shutdown(chand->lb_policy);
+    }
+  }
+
+  if (!is_empty(op, sizeof(*op))) {
+    lb_policy = chand->lb_policy;
+    if (lb_policy) {
+      GRPC_LB_POLICY_REF(lb_policy, "broadcast");
+    }
+  }
+  gpr_mu_unlock(&chand->mu_config);
+
+  if (destroy_resolver) {
+    grpc_resolver_shutdown(destroy_resolver);
+    GRPC_RESOLVER_UNREF(destroy_resolver, "channel");
+  }
+
+  if (lb_policy) {
+    grpc_lb_policy_broadcast(lb_policy, op);
+    GRPC_LB_POLICY_UNREF(lb_policy, "broadcast");
+  }
+
+  if (on_consumed) {
+    grpc_iomgr_add_callback(on_consumed);
   }
 }
 
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   call_data *calld = elem->call_data;
 
   /* TODO(ctiller): is there something useful we can do here? */
@@ -357,157 +515,97 @@
 
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
   GPR_ASSERT(server_transport_data == NULL);
+  gpr_mu_init(&calld->mu_state);
   calld->elem = elem;
   calld->state = CALL_CREATED;
-  calld->deadline = gpr_inf_future;
+  calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_call_element *elem) {
   call_data *calld = elem->call_data;
+  grpc_subchannel_call *subchannel_call;
 
   /* if the call got activated, we need to destroy the child stack also, and
      remove it from the in-flight requests tracked by the child_entry we
      picked */
-  if (calld->state == CALL_ACTIVE) {
-    grpc_child_call_destroy(calld->s.active.child_call);
+  gpr_mu_lock(&calld->mu_state);
+  switch (calld->state) {
+    case CALL_ACTIVE:
+      subchannel_call = calld->subchannel_call;
+      gpr_mu_unlock(&calld->mu_state);
+      GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "client_channel");
+      break;
+    case CALL_CREATED:
+    case CALL_CANCELLED:
+      gpr_mu_unlock(&calld->mu_state);
+      break;
+    case CALL_WAITING_FOR_PICK:
+    case CALL_WAITING_FOR_CONFIG:
+    case CALL_WAITING_FOR_CALL:
+    case CALL_WAITING_FOR_SEND:
+      gpr_log(GPR_ERROR, "should never reach here");
+      abort();
+      break;
   }
-  GPR_ASSERT(calld->state != CALL_WAITING);
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
                               int is_last) {
   channel_data *chand = elem->channel_data;
 
-  GPR_ASSERT(!is_first);
+  memset(chand, 0, sizeof(*chand));
+
   GPR_ASSERT(is_last);
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
 
-  gpr_mu_init(&chand->mu);
-  chand->active_child = NULL;
-  chand->waiting_children = NULL;
-  chand->waiting_child_count = 0;
-  chand->waiting_child_capacity = 0;
-  chand->transport_setup = NULL;
-  chand->transport_setup_initiated = 0;
-  chand->args = grpc_channel_args_copy(args);
+  gpr_mu_init(&chand->mu_config);
   chand->mdctx = metadata_context;
+  chand->master = master;
+  grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed,
+                          chand);
+
+  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE);
 }
 
 /* Destructor for channel_data */
 static void destroy_channel_elem(grpc_channel_element *elem) {
   channel_data *chand = elem->channel_data;
 
-  grpc_transport_setup_cancel(chand->transport_setup);
-
-  if (chand->active_child) {
-    grpc_child_channel_destroy(chand->active_child, 1);
-    chand->active_child = NULL;
+  if (chand->resolver != NULL) {
+    grpc_resolver_shutdown(chand->resolver);
+    GRPC_RESOLVER_UNREF(chand->resolver, "channel");
   }
-
-  grpc_channel_args_destroy(chand->args);
-
-  gpr_mu_destroy(&chand->mu);
-  GPR_ASSERT(chand->waiting_child_count == 0);
-  gpr_free(chand->waiting_children);
+  if (chand->lb_policy != NULL) {
+    GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
+  }
+  gpr_mu_destroy(&chand->mu_config);
 }
 
 const grpc_channel_filter grpc_client_channel_filter = {
-    cc_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "client-channel",
+    cc_start_transport_stream_op,
+    cc_start_transport_op,
+    sizeof(call_data),
+    init_call_elem,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    "client-channel",
 };
 
-grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
-    grpc_channel_stack *channel_stack, grpc_transport *transport,
-    grpc_channel_filter const **channel_filters, size_t num_channel_filters,
-    grpc_mdctx *mdctx) {
-  /* we just got a new transport: lets create a child channel stack for it */
-  grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
-  channel_data *chand = elem->channel_data;
-  size_t num_child_filters = 2 + num_channel_filters;
-  grpc_channel_filter const **child_filters;
-  grpc_transport_setup_result result;
-  grpc_child_channel *old_active = NULL;
-  call_data **waiting_children;
-  size_t waiting_child_count;
-  size_t i;
-  grpc_transport_op *call_ops;
-
-  /* build the child filter stack */
-  child_filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_child_filters);
-  /* we always need a link back filter to get back to the connected channel */
-  child_filters[0] = &grpc_child_channel_top_filter;
-  for (i = 0; i < num_channel_filters; i++) {
-    child_filters[i + 1] = channel_filters[i];
-  }
-  /* and we always need a connected channel to talk to the transport */
-  child_filters[num_child_filters - 1] = &grpc_connected_channel_filter;
-
-  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
-
-  /* BEGIN LOCKING CHANNEL */
-  gpr_mu_lock(&chand->mu);
-  chand->transport_setup_initiated = 0;
-
-  if (chand->active_child) {
-    old_active = chand->active_child;
-  }
-  chand->active_child = grpc_child_channel_create(
-      elem, child_filters, num_child_filters, chand->args, mdctx);
-  result =
-      grpc_connected_channel_bind_transport(chand->active_child, transport);
-
-  /* capture the waiting children - we'll activate them outside the lock
-     to avoid re-entrancy problems */
-  waiting_children = chand->waiting_children;
-  waiting_child_count = chand->waiting_child_count;
-  /* bumping up inflight_requests here avoids taking a lock per rpc below */
-
-  chand->waiting_children = NULL;
-  chand->waiting_child_count = 0;
-  chand->waiting_child_capacity = 0;
-
-  call_ops = gpr_malloc(sizeof(*call_ops) * waiting_child_count);
-
-  for (i = 0; i < waiting_child_count; i++) {
-    call_ops[i] = waiting_children[i]->s.waiting_op;
-    if (!prepare_activate(waiting_children[i]->elem, chand->active_child)) {
-      waiting_children[i] = NULL;
-      grpc_transport_op_finish_with_failure(&call_ops[i]);
-    }
-  }
-
-  /* END LOCKING CHANNEL */
-  gpr_mu_unlock(&chand->mu);
-
-  /* activate any pending operations - this is safe to do as we guarantee one
-     and only one write operation per request at the surface api - if we lose
-     that guarantee we need to do some curly locking here */
-  for (i = 0; i < waiting_child_count; i++) {
-    if (waiting_children[i]) {
-      complete_activate(waiting_children[i]->elem, &call_ops[i]);
-    }
-  }
-  gpr_free(waiting_children);
-  gpr_free(call_ops);
-  gpr_free(child_filters);
-
-  if (old_active) {
-    grpc_child_channel_destroy(old_active, 1);
-  }
-
-  return result;
-}
-
-void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
-                                             grpc_transport_setup *setup) {
+void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
+                                      grpc_resolver *resolver) {
   /* post construction initialization: set the transport setup pointer */
   grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
   channel_data *chand = elem->channel_data;
-  GPR_ASSERT(!chand->transport_setup);
-  chand->transport_setup = setup;
+  GPR_ASSERT(!chand->resolver);
+  chand->resolver = resolver;
+  GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
+  GRPC_RESOLVER_REF(resolver, "channel");
+  grpc_resolver_next(resolver, &chand->incoming_configuration,
+                     &chand->on_config_changed);
 }
diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h
index 7a67a9f..fd2be46 100644
--- a/src/core/channel/client_channel.h
+++ b/src/core/channel/client_channel.h
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H
 
 #include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/resolver.h"
 
 /* A client channel is a channel that begins disconnected, and can connect
    to some endpoint on demand. If that endpoint disconnects, it will be
@@ -48,15 +49,7 @@
 /* post-construction initializer to let the client channel know which
    transport setup it should cancel upon destruction, or initiate when it needs
    a connection */
-void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
-                                             grpc_transport_setup *setup);
+void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
+                                      grpc_resolver *resolver);
 
-/* grpc_transport_setup_callback for binding new transports into a client
-   channel - user_data should be the channel stack containing the client
-   channel */
-grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
-    grpc_channel_stack *channel_stack, grpc_transport *transport,
-    grpc_channel_filter const **channel_filters, size_t num_channel_filters,
-    grpc_mdctx *mdctx);
-
-#endif  /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/channel/client_setup.c b/src/core/channel/client_setup.c
deleted file mode 100644
index 6d892d6..0000000
--- a/src/core/channel/client_setup.c
+++ /dev/null
@@ -1,269 +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.
- *
- */
-
-#include "src/core/channel/client_setup.h"
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/channel_stack.h"
-#include "src/core/iomgr/alarm.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-
-struct grpc_client_setup {
-  grpc_transport_setup base; /* must be first */
-  void (*initiate)(void *user_data, grpc_client_setup_request *request);
-  void (*done)(void *user_data);
-  void *user_data;
-  grpc_channel_args *args;
-  grpc_mdctx *mdctx;
-  grpc_alarm backoff_alarm;
-  gpr_timespec current_backoff_interval;
-  int in_alarm;
-  int in_cb;
-  int cancelled;
-
-  gpr_mu mu;
-  gpr_cv cv;
-  grpc_client_setup_request *active_request;
-  int refs;
-};
-
-struct grpc_client_setup_request {
-  /* pointer back to the setup object */
-  grpc_client_setup *setup;
-  gpr_timespec deadline;
-};
-
-gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) {
-  return r->deadline;
-}
-
-static void destroy_setup(grpc_client_setup *s) {
-  gpr_mu_destroy(&s->mu);
-  gpr_cv_destroy(&s->cv);
-  s->done(s->user_data);
-  grpc_channel_args_destroy(s->args);
-  gpr_free(s);
-}
-
-/* initiate handshaking */
-static void setup_initiate(grpc_transport_setup *sp) {
-  grpc_client_setup *s = (grpc_client_setup *)sp;
-  grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
-  int in_alarm = 0;
-
-  r->setup = s;
-  /* TODO(klempner): Actually set a deadline */
-  r->deadline = gpr_inf_future;
-
-  gpr_mu_lock(&s->mu);
-  GPR_ASSERT(s->refs > 0);
-  /* there might be more than one request outstanding if the caller calls
-     initiate in some kind of rapid-fire way: we try to connect each time,
-     and keep track of the latest request (which is the only one that gets
-     to finish) */
-  if (!s->in_alarm) {
-    s->active_request = r;
-    s->refs++;
-  } else {
-    /* TODO(klempner): Maybe do something more clever here */
-    in_alarm = 1;
-  }
-  gpr_mu_unlock(&s->mu);
-
-  if (!in_alarm) {
-    s->initiate(s->user_data, r);
-  } else {
-    gpr_free(r);
-  }
-}
-
-/* cancel handshaking: cancel all requests, and shutdown (the caller promises
-   not to initiate again) */
-static void setup_cancel(grpc_transport_setup *sp) {
-  grpc_client_setup *s = (grpc_client_setup *)sp;
-  int cancel_alarm = 0;
-
-  gpr_mu_lock(&s->mu);
-  s->cancelled = 1;
-  while (s->in_cb) {
-    gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
-  }
-
-  GPR_ASSERT(s->refs > 0);
-  /* effectively cancels the current request (if any) */
-  s->active_request = NULL;
-  if (s->in_alarm) {
-    cancel_alarm = 1;
-  }
-  if (--s->refs == 0) {
-    gpr_mu_unlock(&s->mu);
-    destroy_setup(s);
-  } else {
-    gpr_mu_unlock(&s->mu);
-  }
-  if (cancel_alarm) {
-    grpc_alarm_cancel(&s->backoff_alarm);
-  }
-}
-
-int grpc_client_setup_cb_begin(grpc_client_setup_request *r) {
-  gpr_mu_lock(&r->setup->mu);
-  if (r->setup->cancelled) {
-    gpr_mu_unlock(&r->setup->mu);
-    return 0;
-  }
-  r->setup->in_cb++;
-  gpr_mu_unlock(&r->setup->mu);
-  return 1;
-}
-
-void grpc_client_setup_cb_end(grpc_client_setup_request *r) {
-  gpr_mu_lock(&r->setup->mu);
-  r->setup->in_cb--;
-  if (r->setup->cancelled) gpr_cv_signal(&r->setup->cv);
-  gpr_mu_unlock(&r->setup->mu);
-}
-
-/* vtable for transport setup */
-static const grpc_transport_setup_vtable setup_vtable = {setup_initiate,
-                                                         setup_cancel};
-
-void grpc_client_setup_create_and_attach(
-    grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
-    grpc_mdctx *mdctx,
-    void (*initiate)(void *user_data, grpc_client_setup_request *request),
-    void (*done)(void *user_data), void *user_data) {
-  grpc_client_setup *s = gpr_malloc(sizeof(grpc_client_setup));
-
-  s->base.vtable = &setup_vtable;
-  gpr_mu_init(&s->mu);
-  gpr_cv_init(&s->cv);
-  s->refs = 1;
-  s->mdctx = mdctx;
-  s->initiate = initiate;
-  s->done = done;
-  s->user_data = user_data;
-  s->active_request = NULL;
-  s->args = grpc_channel_args_copy(args);
-  s->current_backoff_interval = gpr_time_from_micros(1000000);
-  s->in_alarm = 0;
-  s->in_cb = 0;
-  s->cancelled = 0;
-
-  grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base);
-}
-
-int grpc_client_setup_request_should_continue(grpc_client_setup_request *r) {
-  int result;
-  if (gpr_time_cmp(gpr_now(), r->deadline) > 0) {
-    return 0;
-  }
-  gpr_mu_lock(&r->setup->mu);
-  result = r->setup->active_request == r;
-  gpr_mu_unlock(&r->setup->mu);
-  return result;
-}
-
-static void backoff_alarm_done(void *arg /* grpc_client_setup */, int success) {
-  grpc_client_setup *s = arg;
-  grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
-  r->setup = s;
-  /* TODO(klempner): Set this to something useful */
-  r->deadline = gpr_inf_future;
-  /* Handle status cancelled? */
-  gpr_mu_lock(&s->mu);
-  s->active_request = r;
-  s->in_alarm = 0;
-  if (!success) {
-    if (0 == --s->refs) {
-      gpr_mu_unlock(&s->mu);
-      destroy_setup(s);
-      gpr_free(r);
-      return;
-    } else {
-      gpr_mu_unlock(&s->mu);
-      return;
-    }
-  }
-  gpr_mu_unlock(&s->mu);
-  s->initiate(s->user_data, r);
-}
-
-void grpc_client_setup_request_finish(grpc_client_setup_request *r,
-                                      int was_successful) {
-  int retry = !was_successful;
-  grpc_client_setup *s = r->setup;
-
-  gpr_mu_lock(&s->mu);
-  if (s->active_request == r) {
-    s->active_request = NULL;
-  } else {
-    retry = 0;
-  }
-  if (!retry && 0 == --s->refs) {
-    gpr_mu_unlock(&s->mu);
-    destroy_setup(s);
-    gpr_free(r);
-    return;
-  }
-
-  gpr_free(r);
-
-  if (retry) {
-    /* TODO(klempner): Replace these values with further consideration. 2x is
-       probably too aggressive of a backoff. */
-    gpr_timespec max_backoff = gpr_time_from_minutes(2);
-    gpr_timespec now = gpr_now();
-    gpr_timespec deadline = gpr_time_add(s->current_backoff_interval, now);
-    GPR_ASSERT(!s->in_alarm);
-    s->in_alarm = 1;
-    grpc_alarm_init(&s->backoff_alarm, deadline, backoff_alarm_done, s, now);
-    s->current_backoff_interval =
-        gpr_time_add(s->current_backoff_interval, s->current_backoff_interval);
-    if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) {
-      s->current_backoff_interval = max_backoff;
-    }
-  }
-
-  gpr_mu_unlock(&s->mu);
-}
-
-const grpc_channel_args *grpc_client_setup_get_channel_args(
-    grpc_client_setup_request *r) {
-  return r->setup->args;
-}
-
-grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r) {
-  return r->setup->mdctx;
-}
diff --git a/src/core/channel/client_setup.h b/src/core/channel/client_setup.h
deleted file mode 100644
index 70137e1..0000000
--- a/src/core/channel/client_setup.h
+++ /dev/null
@@ -1,73 +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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H
-
-#include "src/core/channel/client_channel.h"
-#include "src/core/transport/metadata.h"
-#include <grpc/support/time.h>
-
-/* Convenience API's to simplify transport setup */
-
-typedef struct grpc_client_setup grpc_client_setup;
-typedef struct grpc_client_setup_request grpc_client_setup_request;
-
-void grpc_client_setup_create_and_attach(
-    grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
-    grpc_mdctx *mdctx,
-    void (*initiate)(void *user_data, grpc_client_setup_request *request),
-    void (*done)(void *user_data), void *user_data);
-
-/* Check that r is the active request: needs to be performed at each callback.
-   If this races, we'll have two connection attempts running at once and the
-   old one will get cleaned up in due course, which is fine. */
-int grpc_client_setup_request_should_continue(grpc_client_setup_request *r);
-void grpc_client_setup_request_finish(grpc_client_setup_request *r,
-                                      int was_successful);
-const grpc_channel_args *grpc_client_setup_get_channel_args(
-    grpc_client_setup_request *r);
-
-/* Call before calling back into the setup listener, and call only if
-   this function returns 1. If it returns 1, also promise to call
-   grpc_client_setup_cb_end */
-int grpc_client_setup_cb_begin(grpc_client_setup_request *r);
-void grpc_client_setup_cb_end(grpc_client_setup_request *r);
-
-/* Get the deadline for a request passed in to initiate. Implementations should
-   make a best effort to honor this deadline. */
-gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r);
-
-grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r);
-
-#endif  /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H */
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
new file mode 100644
index 0000000..14cb3da
--- /dev/null
+++ b/src/core/channel/compress_filter.c
@@ -0,0 +1,325 @@
+/*
+ *
+ * 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 <assert.h>
+#include <string.h>
+
+#include <grpc/compression.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/channel/compress_filter.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/compression/message_compress.h"
+
+typedef struct call_data {
+  gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
+  grpc_linked_mdelem compression_algorithm_storage;
+  int remaining_slice_bytes; /**< Input data to be read, as per BEGIN_MESSAGE */
+  int written_initial_metadata; /**< Already processed initial md? */
+  /** Compression algorithm we'll try to use. It may be given by incoming
+   * metadata, or by the channel's default compression settings. */
+  grpc_compression_algorithm compression_algorithm;
+   /** If true, contents of \a compression_algorithm are authoritative */
+  int has_compression_algorithm;
+} call_data;
+
+typedef struct channel_data {
+  /** Metadata key for the incoming (requested) compression algorithm */
+  grpc_mdstr *mdstr_request_compression_algorithm_key;
+  /** Metadata key for the outgoing (used) compression algorithm */
+  grpc_mdstr *mdstr_outgoing_compression_algorithm_key;
+  /** Precomputed metadata elements for all available compression algorithms */
+  grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT];
+  /** The default, channel-level, compression algorithm */
+  grpc_compression_algorithm default_compression_algorithm;
+} channel_data;
+
+/** Compress \a slices in place using \a algorithm. Returns 1 if compression did
+ * actually happen, 0 otherwise (for example if the compressed output size was
+ * larger than the raw input).
+ *
+ * Returns 1 if the data was actually compress and 0 otherwise. */
+static int compress_send_sb(grpc_compression_algorithm algorithm,
+                             gpr_slice_buffer *slices) {
+  int did_compress;
+  gpr_slice_buffer tmp;
+  gpr_slice_buffer_init(&tmp);
+  did_compress = grpc_msg_compress(algorithm, slices, &tmp);
+  if (did_compress) {
+    gpr_slice_buffer_swap(slices, &tmp);
+  }
+  gpr_slice_buffer_destroy(&tmp);
+  return did_compress;
+}
+
+/** For each \a md element from the incoming metadata, filter out the entry for
+ * "grpc-encoding", using its value to populate the call data's
+ * compression_algorithm field. */
+static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+
+  if (md->key == channeld->mdstr_request_compression_algorithm_key) {
+    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
+    if (!grpc_compression_algorithm_parse(md_c_str,
+                                          &calld->compression_algorithm)) {
+      gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.",
+              md_c_str);
+      calld->compression_algorithm = GRPC_COMPRESS_NONE;
+    }
+    calld->has_compression_algorithm = 1;
+    return NULL;
+  }
+
+  return md;
+}
+
+static int skip_compression(channel_data *channeld, call_data *calld) {
+  if (calld->has_compression_algorithm) {
+     if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
+       return 1;
+     }
+     return 0;  /* we have an actual call-specific algorithm */
+  }
+  /* no per-call compression override */
+  return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE;
+}
+
+/** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying
+ * the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length,
+ * flags indicating compression is in effect) and replaces \a send_ops with it.
+ * */
+static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops,
+                                   grpc_call_element *elem) {
+  size_t i;
+  call_data *calld = elem->call_data;
+  int new_slices_added = 0; /* GPR_FALSE */
+  grpc_metadata_batch metadata;
+  grpc_stream_op_buffer new_send_ops;
+  grpc_sopb_init(&new_send_ops);
+
+  for (i = 0; i < send_ops->nops; i++) {
+    grpc_stream_op *sop = &send_ops->ops[i];
+    switch (sop->type) {
+      case GRPC_OP_BEGIN_MESSAGE:
+        grpc_sopb_add_begin_message(
+            &new_send_ops, calld->slices.length,
+            sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS);
+        break;
+      case GRPC_OP_SLICE:
+        /* Once we reach the slices section of the original buffer, simply add
+         * all the new (compressed) slices. We obviously want to do this only
+         * once, hence the "new_slices_added" guard. */
+        if (!new_slices_added) {
+          size_t j;
+          for (j = 0; j < calld->slices.count; ++j) {
+            grpc_sopb_add_slice(&new_send_ops,
+                                gpr_slice_ref(calld->slices.slices[j]));
+          }
+          new_slices_added = 1; /* GPR_TRUE */
+        }
+        break;
+      case GRPC_OP_METADATA:
+        /* move the metadata to the new buffer. */
+        grpc_metadata_batch_move(&metadata, &sop->data.metadata);
+        grpc_sopb_add_metadata(&new_send_ops, metadata);
+        break;
+      case GRPC_NO_OP:
+        break;
+    }
+  }
+  grpc_sopb_swap(send_ops, &new_send_ops);
+  grpc_sopb_destroy(&new_send_ops);
+}
+
+/** Filter's "main" function, called for any incoming grpc_transport_stream_op
+ * instance that holds a non-zero number of send operations, accesible to this
+ * function in \a send_ops.  */
+static void process_send_ops(grpc_call_element *elem,
+                             grpc_stream_op_buffer *send_ops) {
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+  size_t i;
+  int did_compress = 0;
+
+  for (i = 0; i < send_ops->nops; ++i) {
+    grpc_stream_op *sop = &send_ops->ops[i];
+    switch (sop->type) {
+      case GRPC_OP_BEGIN_MESSAGE:
+        /* buffer up slices until we've processed all the expected ones (as
+         * given by GRPC_OP_BEGIN_MESSAGE) */
+        calld->remaining_slice_bytes = sop->data.begin_message.length;
+        if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) {
+          calld->has_compression_algorithm = 1;  /* GPR_TRUE */
+          calld->compression_algorithm = GRPC_COMPRESS_NONE;
+        }
+        break;
+      case GRPC_OP_METADATA:
+        if (!calld->written_initial_metadata) {
+          /* Parse incoming request for compression. If any, it'll be available
+           * at calld->compression_algorithm */
+          grpc_metadata_batch_filter(&(sop->data.metadata),
+                                     compression_md_filter, elem);
+          if (!calld->has_compression_algorithm) {
+            /* If no algorithm was found in the metadata and we aren't
+             * exceptionally skipping compression, fall back to the channel
+             * default */
+            calld->compression_algorithm =
+                channeld->default_compression_algorithm;
+            calld->has_compression_algorithm = 1; /* GPR_TRUE */
+          }
+          grpc_metadata_batch_add_head(
+              &(sop->data.metadata), &calld->compression_algorithm_storage,
+              grpc_mdelem_ref(channeld->mdelem_compression_algorithms
+                                  [calld->compression_algorithm]));
+          calld->written_initial_metadata = 1; /* GPR_TRUE */
+        }
+        break;
+      case GRPC_OP_SLICE:
+        if (skip_compression(channeld, calld)) continue;
+        GPR_ASSERT(calld->remaining_slice_bytes > 0);
+        /* Increase input ref count, gpr_slice_buffer_add takes ownership.  */
+        gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice));
+        calld->remaining_slice_bytes -= GPR_SLICE_LENGTH(sop->data.slice);
+        if (calld->remaining_slice_bytes == 0) {
+          did_compress =
+              compress_send_sb(calld->compression_algorithm, &calld->slices);
+        }
+        break;
+      case GRPC_NO_OP:
+        break;
+    }
+  }
+
+  /* Modify the send_ops stream_op_buffer depending on whether compression was
+   * carried out */
+  if (did_compress) {
+    finish_compressed_sopb(send_ops, elem);
+  }
+}
+
+/* Called either:
+     - in response to an API call (or similar) from above, to send something
+     - a network event (or similar) from below, to receive something
+   op contains type and call direction information, in addition to the data
+   that is being sent or received. */
+static void compress_start_transport_stream_op(grpc_call_element *elem,
+                                               grpc_transport_stream_op *op) {
+  if (op->send_ops && op->send_ops->nops > 0) {
+    process_send_ops(elem, op->send_ops);
+  }
+
+  /* pass control down the stack */
+  grpc_call_next_op(elem, op);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_call_element *elem,
+                           const void *server_transport_data,
+                           grpc_transport_stream_op *initial_op) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+
+  /* initialize members */
+  gpr_slice_buffer_init(&calld->slices);
+  calld->has_compression_algorithm = 0;
+  calld->written_initial_metadata = 0; /* GPR_FALSE */
+
+  if (initial_op) {
+    if (initial_op->send_ops && initial_op->send_ops->nops > 0) {
+      process_send_ops(elem, initial_op->send_ops);
+    }
+  }
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_call_element *elem) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  gpr_slice_buffer_destroy(&calld->slices);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
+                              const grpc_channel_args *args, grpc_mdctx *mdctx,
+                              int is_first, int is_last) {
+  channel_data *channeld = elem->channel_data;
+  grpc_compression_algorithm algo_idx;
+
+  channeld->default_compression_algorithm =
+      grpc_channel_args_get_compression_algorithm(args);
+
+  channeld->mdstr_request_compression_algorithm_key =
+      grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY);
+
+  channeld->mdstr_outgoing_compression_algorithm_key =
+      grpc_mdstr_from_string(mdctx, "grpc-encoding");
+
+  for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
+    char *algorith_name;
+    GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorith_name) != 0);
+    channeld->mdelem_compression_algorithms[algo_idx] =
+        grpc_mdelem_from_metadata_strings(
+            mdctx,
+            grpc_mdstr_ref(channeld->mdstr_outgoing_compression_algorithm_key),
+            grpc_mdstr_from_string(mdctx, algorith_name));
+  }
+
+  GPR_ASSERT(!is_last);
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_channel_element *elem) {
+  channel_data *channeld = elem->channel_data;
+  grpc_compression_algorithm algo_idx;
+
+  grpc_mdstr_unref(channeld->mdstr_request_compression_algorithm_key);
+  grpc_mdstr_unref(channeld->mdstr_outgoing_compression_algorithm_key);
+  for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT;
+       ++algo_idx) {
+    grpc_mdelem_unref(channeld->mdelem_compression_algorithms[algo_idx]);
+  }
+}
+
+const grpc_channel_filter grpc_compress_filter = {
+    compress_start_transport_stream_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    init_call_elem,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    "compress"};
diff --git a/src/core/channel/compress_filter.h b/src/core/channel/compress_filter.h
new file mode 100644
index 0000000..0694e2c
--- /dev/null
+++ b/src/core/channel/compress_filter.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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_CHANNEL_COMPRESS_FILTER_H
+#define GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H
+
+#include "src/core/channel/channel_stack.h"
+
+#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "internal:grpc-encoding-request"
+
+/** Compression filter for outgoing data.
+ *
+ * See <grpc/compression.h> for the available compression settings.
+ *
+ * Compression settings may come from:
+ *  - Channel configuration, as established at channel creation time.
+ *  - The metadata accompanying the outgoing data to be compressed. This is
+ *    taken as a request only. We may choose not to honor it. The metadata key
+ *    is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY.
+ *
+ * Compression can be disabled for concrete messages (for instance in order to
+ * prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in
+ * the BEGIN_MESSAGE flags.
+ *
+ * The attempted compression mechanism is added to the resulting initial
+ * metadata under the'grpc-encoding' key.
+ *
+ * If compression is actually performed, BEGIN_MESSAGE's flag is modified to
+ * incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the
+ * aforementioned 'grpc-encoding' metadata value, data will pass through
+ * uncompressed. */
+
+extern const grpc_channel_filter grpc_compress_filter;
+
+#endif  /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 14dda88..34d07de 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -61,42 +61,27 @@
 
 /* Intercept a call operation and either push it directly up or translate it
    into transport stream operations */
-static void con_start_transport_op(grpc_call_element *elem,
-                                   grpc_transport_op *op) {
+static void con_start_transport_stream_op(grpc_call_element *elem,
+                                          grpc_transport_stream_op *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 
-  grpc_transport_perform_op(chand->transport,
-                            TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
+  grpc_transport_perform_stream_op(chand->transport,
+                                   TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
 }
 
-/* Currently we assume all channel operations should just be pushed up. */
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
+static void con_start_transport_op(grpc_channel_element *elem,
+                                   grpc_transport_op *op) {
   channel_data *chand = elem->channel_data;
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-
-  switch (op->type) {
-    case GRPC_CHANNEL_GOAWAY:
-      grpc_transport_goaway(chand->transport, op->data.goaway.status,
-                            op->data.goaway.message);
-      break;
-    case GRPC_CHANNEL_DISCONNECT:
-      grpc_transport_close(chand->transport);
-      break;
-    default:
-      GPR_ASSERT(op->dir == GRPC_CALL_UP);
-      grpc_channel_next_op(elem, op);
-      break;
-  }
+  grpc_transport_perform_op(chand->transport, op);
 }
 
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   int r;
@@ -118,11 +103,10 @@
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
                               int is_first, int is_last) {
   channel_data *cd = (channel_data *)elem->channel_data;
-  GPR_ASSERT(!is_first);
   GPR_ASSERT(is_last);
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
   cd->transport = NULL;
@@ -136,70 +120,23 @@
 }
 
 const grpc_channel_filter grpc_connected_channel_filter = {
-    con_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "connected",
+    con_start_transport_stream_op,
+    con_start_transport_op,
+    sizeof(call_data),
+    init_call_elem,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    "connected",
 };
 
-/* Transport callback to accept a new stream... calls up to handle it */
-static void accept_stream(void *user_data, grpc_transport *transport,
-                          const void *transport_server_data) {
-  grpc_channel_element *elem = user_data;
-  channel_data *chand = elem->channel_data;
-  grpc_channel_op op;
-
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  GPR_ASSERT(chand->transport == transport);
-
-  op.type = GRPC_ACCEPT_CALL;
-  op.dir = GRPC_CALL_UP;
-  op.data.accept_call.transport = transport;
-  op.data.accept_call.transport_server_data = transport_server_data;
-  channel_op(elem, NULL, &op);
-}
-
-static void transport_goaway(void *user_data, grpc_transport *transport,
-                             grpc_status_code status, gpr_slice debug) {
-  /* transport got goaway ==> call up and handle it */
-  grpc_channel_element *elem = user_data;
-  channel_data *chand = elem->channel_data;
-  grpc_channel_op op;
-
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  GPR_ASSERT(chand->transport == transport);
-
-  op.type = GRPC_TRANSPORT_GOAWAY;
-  op.dir = GRPC_CALL_UP;
-  op.data.goaway.status = status;
-  op.data.goaway.message = debug;
-  channel_op(elem, NULL, &op);
-}
-
-static void transport_closed(void *user_data, grpc_transport *transport) {
-  /* transport was closed ==> call up and handle it */
-  grpc_channel_element *elem = user_data;
-  channel_data *chand = elem->channel_data;
-  grpc_channel_op op;
-
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  GPR_ASSERT(chand->transport == transport);
-
-  op.type = GRPC_TRANSPORT_CLOSED;
-  op.dir = GRPC_CALL_UP;
-  channel_op(elem, NULL, &op);
-}
-
-const grpc_transport_callbacks connected_channel_transport_callbacks = {
-    accept_stream, transport_goaway, transport_closed,
-};
-
-grpc_transport_setup_result grpc_connected_channel_bind_transport(
-    grpc_channel_stack *channel_stack, grpc_transport *transport) {
+void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack,
+                                           grpc_transport *transport) {
   /* Assumes that the connected channel filter is always the last filter
      in a channel stack */
   grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
   channel_data *cd = (channel_data *)elem->channel_data;
-  grpc_transport_setup_result ret;
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
   GPR_ASSERT(cd->transport == NULL);
   cd->transport = transport;
@@ -211,8 +148,4 @@
      the last call element, and the last call element MUST be the connected
      channel. */
   channel_stack->call_stack_size += grpc_transport_stream_size(transport);
-
-  ret.user_data = elem;
-  ret.callbacks = &connected_channel_transport_callbacks;
-  return ret;
 }
diff --git a/src/core/channel/connected_channel.h b/src/core/channel/connected_channel.h
index 8b35f69..b615b0d 100644
--- a/src/core/channel/connected_channel.h
+++ b/src/core/channel/connected_channel.h
@@ -43,7 +43,7 @@
 
 /* Post construction fixup: set the transport in the connected channel.
    Must be called before any call stack using this filter is used. */
-grpc_transport_setup_result grpc_connected_channel_bind_transport(
-    grpc_channel_stack *channel_stack, grpc_transport *transport);
+void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack,
+                                           grpc_transport *transport);
 
-#endif  /* GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 9805f32..63e4912 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -43,8 +43,13 @@
 
   int got_initial_metadata;
   grpc_stream_op_buffer *recv_ops;
-  void (*on_done_recv)(void *user_data, int success);
-  void *recv_user_data;
+
+  /** Closure to call when finished with the hc_on_recv hook */
+  grpc_iomgr_closure *on_done_recv;
+  /** Receive closures are chained: we inject this closure as the on_done_recv
+      up-call on transport_op, and remember to call our on_done_recv member
+      after handling it. */
+  grpc_iomgr_closure hc_on_recv;
 } call_data;
 
 typedef struct channel_data {
@@ -84,10 +89,11 @@
       grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem);
     }
   }
-  calld->on_done_recv(calld->recv_user_data, success);
+  calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
 }
 
-static void hc_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+static void hc_mutate_op(grpc_call_element *elem,
+                         grpc_transport_stream_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -102,13 +108,13 @@
       /* Send : prefixed headers, which have to be before any application
          layer headers. */
       grpc_metadata_batch_add_head(&op->data.metadata, &calld->method,
-                                   grpc_mdelem_ref(channeld->method));
+                                   GRPC_MDELEM_REF(channeld->method));
       grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme,
-                                   grpc_mdelem_ref(channeld->scheme));
+                                   GRPC_MDELEM_REF(channeld->scheme));
       grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers,
-                                   grpc_mdelem_ref(channeld->te_trailers));
+                                   GRPC_MDELEM_REF(channeld->te_trailers));
       grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type,
-                                   grpc_mdelem_ref(channeld->content_type));
+                                   GRPC_MDELEM_REF(channeld->content_type));
       break;
     }
   }
@@ -117,43 +123,26 @@
     /* substitute our callback for the higher callback */
     calld->recv_ops = op->recv_ops;
     calld->on_done_recv = op->on_done_recv;
-    calld->recv_user_data = op->recv_user_data;
-    op->on_done_recv = hc_on_recv;
-    op->recv_user_data = elem;
+    op->on_done_recv = &calld->hc_on_recv;
   }
 }
 
 static void hc_start_transport_op(grpc_call_element *elem,
-                                  grpc_transport_op *op) {
+                                  grpc_transport_stream_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   hc_mutate_op(elem, op);
   grpc_call_next_op(elem, op);
 }
 
-/* Called on special channel events, such as disconnection or new incoming
-   calls on the server */
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  /* grab pointers to our data from the channel element */
-  channel_data *channeld = elem->channel_data;
-
-  ignore_unused(channeld);
-
-  switch (op->type) {
-    default:
-      /* pass control up or down the stack depending on op->dir */
-      grpc_channel_next_op(elem, op);
-      break;
-  }
-}
-
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   call_data *calld = elem->call_data;
   calld->sent_initial_metadata = 0;
   calld->got_initial_metadata = 0;
+  calld->on_done_recv = NULL;
+  grpc_iomgr_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
   if (initial_op) hc_mutate_op(elem, initial_op);
 }
 
@@ -181,7 +170,7 @@
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
                               int is_first, int is_last) {
   /* grab pointers to our data from the channel element */
@@ -190,7 +179,6 @@
   /* The first and the last filters tend to be implemented differently to
      handle the case that there's no 'next' filter to call on the up or down
      path */
-  GPR_ASSERT(!is_first);
   GPR_ASSERT(!is_last);
 
   /* initialize members */
@@ -208,14 +196,14 @@
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
-  grpc_mdelem_unref(channeld->te_trailers);
-  grpc_mdelem_unref(channeld->method);
-  grpc_mdelem_unref(channeld->scheme);
-  grpc_mdelem_unref(channeld->content_type);
-  grpc_mdelem_unref(channeld->status);
+  GRPC_MDELEM_UNREF(channeld->te_trailers);
+  GRPC_MDELEM_UNREF(channeld->method);
+  GRPC_MDELEM_UNREF(channeld->scheme);
+  GRPC_MDELEM_UNREF(channeld->content_type);
+  GRPC_MDELEM_UNREF(channeld->status);
 }
 
 const grpc_channel_filter grpc_http_client_filter = {
-    hc_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "http-client"};
+    hc_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+    init_call_elem,        destroy_call_elem,    sizeof(channel_data),
+    init_channel_elem,     destroy_channel_elem, "http-client"};
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 11a53b1..a6cbb5a 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -47,8 +47,12 @@
   grpc_linked_mdelem status;
 
   grpc_stream_op_buffer *recv_ops;
-  void (*on_done_recv)(void *user_data, int success);
-  void *recv_user_data;
+  /** Closure to call when finished with the hs_on_recv hook */
+  grpc_iomgr_closure *on_done_recv;
+  /** Receive closures are chained: we inject this closure as the on_done_recv
+      up-call on transport_op, and remember to call our on_done_recv member
+      after handling it. */
+  grpc_iomgr_closure hs_on_recv;
 } call_data;
 
 typedef struct channel_data {
@@ -68,9 +72,6 @@
   grpc_mdctx *mdctx;
 } channel_data;
 
-/* used to silence 'variable not used' warnings */
-static void ignore_unused(void *ignored) {}
-
 static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
   grpc_call_element *elem = user_data;
   channel_data *channeld = elem->channel_data;
@@ -128,9 +129,9 @@
     /* translate host to :authority since :authority may be
        omitted */
     grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
-        channeld->mdctx, grpc_mdstr_ref(channeld->authority_key),
-        grpc_mdstr_ref(md->value));
-    grpc_mdelem_unref(md);
+        channeld->mdctx, GRPC_MDSTR_REF(channeld->authority_key),
+        GRPC_MDSTR_REF(md->value));
+    GRPC_MDELEM_UNREF(md);
     return authority;
   } else {
     return md;
@@ -174,10 +175,11 @@
       }
     }
   }
-  calld->on_done_recv(calld->recv_user_data, success);
+  calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
 }
 
-static void hs_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+static void hs_mutate_op(grpc_call_element *elem,
+                         grpc_transport_stream_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -191,7 +193,7 @@
       if (op->type != GRPC_OP_METADATA) continue;
       calld->sent_status = 1;
       grpc_metadata_batch_add_head(&op->data.metadata, &calld->status,
-                                   grpc_mdelem_ref(channeld->status_ok));
+                                   GRPC_MDELEM_REF(channeld->status_ok));
       break;
     }
   }
@@ -200,44 +202,26 @@
     /* substitute our callback for the higher callback */
     calld->recv_ops = op->recv_ops;
     calld->on_done_recv = op->on_done_recv;
-    calld->recv_user_data = op->recv_user_data;
-    op->on_done_recv = hs_on_recv;
-    op->recv_user_data = elem;
+    op->on_done_recv = &calld->hs_on_recv;
   }
 }
 
 static void hs_start_transport_op(grpc_call_element *elem,
-                                  grpc_transport_op *op) {
+                                  grpc_transport_stream_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   hs_mutate_op(elem, op);
   grpc_call_next_op(elem, op);
 }
 
-/* Called on special channel events, such as disconnection or new incoming
-   calls on the server */
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  /* grab pointers to our data from the channel element */
-  channel_data *channeld = elem->channel_data;
-
-  ignore_unused(channeld);
-
-  switch (op->type) {
-    default:
-      /* pass control up or down the stack depending on op->dir */
-      grpc_channel_next_op(elem, op);
-      break;
-  }
-}
-
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   /* initialize members */
   memset(calld, 0, sizeof(*calld));
+  grpc_iomgr_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
   if (initial_op) hs_mutate_op(elem, initial_op);
 }
 
@@ -245,7 +229,7 @@
 static void destroy_call_elem(grpc_call_element *elem) {}
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
                               int is_first, int is_last) {
   /* grab pointers to our data from the channel element */
@@ -280,20 +264,20 @@
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
-  grpc_mdelem_unref(channeld->te_trailers);
-  grpc_mdelem_unref(channeld->status_ok);
-  grpc_mdelem_unref(channeld->status_not_found);
-  grpc_mdelem_unref(channeld->method_post);
-  grpc_mdelem_unref(channeld->http_scheme);
-  grpc_mdelem_unref(channeld->https_scheme);
-  grpc_mdelem_unref(channeld->grpc_scheme);
-  grpc_mdelem_unref(channeld->content_type);
-  grpc_mdstr_unref(channeld->path_key);
-  grpc_mdstr_unref(channeld->authority_key);
-  grpc_mdstr_unref(channeld->host_key);
+  GRPC_MDELEM_UNREF(channeld->te_trailers);
+  GRPC_MDELEM_UNREF(channeld->status_ok);
+  GRPC_MDELEM_UNREF(channeld->status_not_found);
+  GRPC_MDELEM_UNREF(channeld->method_post);
+  GRPC_MDELEM_UNREF(channeld->http_scheme);
+  GRPC_MDELEM_UNREF(channeld->https_scheme);
+  GRPC_MDELEM_UNREF(channeld->grpc_scheme);
+  GRPC_MDELEM_UNREF(channeld->content_type);
+  GRPC_MDSTR_UNREF(channeld->path_key);
+  GRPC_MDSTR_UNREF(channeld->authority_key);
+  GRPC_MDSTR_UNREF(channeld->host_key);
 }
 
 const grpc_channel_filter grpc_http_server_filter = {
-    hs_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "http-server"};
+    hs_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+    init_call_elem,        destroy_call_elem,    sizeof(channel_data),
+    init_channel_elem,     destroy_channel_elem, "http-server"};
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
index 1d2be71..5117723 100644
--- a/src/core/channel/noop_filter.c
+++ b/src/core/channel/noop_filter.c
@@ -45,7 +45,8 @@
 /* used to silence 'variable not used' warnings */
 static void ignore_unused(void *ignored) {}
 
-static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+static void noop_mutate_op(grpc_call_element *elem,
+                           grpc_transport_stream_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -61,35 +62,18 @@
      - a network event (or similar) from below, to receive something
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
-static void noop_start_transport_op(grpc_call_element *elem,
-                                    grpc_transport_op *op) {
+static void noop_start_transport_stream_op(grpc_call_element *elem,
+                                           grpc_transport_stream_op *op) {
   noop_mutate_op(elem, op);
 
   /* pass control down the stack */
   grpc_call_next_op(elem, op);
 }
 
-/* Called on special channel events, such as disconnection or new incoming
-   calls on the server */
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  /* grab pointers to our data from the channel element */
-  channel_data *channeld = elem->channel_data;
-
-  ignore_unused(channeld);
-
-  switch (op->type) {
-    default:
-      /* pass control up or down the stack depending on op->dir */
-      grpc_channel_next_op(elem, op);
-      break;
-  }
-}
-
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -111,7 +95,7 @@
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
                               int is_first, int is_last) {
   /* grab pointers to our data from the channel element */
@@ -135,7 +119,12 @@
   ignore_unused(channeld);
 }
 
-const grpc_channel_filter grpc_no_op_filter = {
-    noop_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "no-op"};
+const grpc_channel_filter grpc_no_op_filter = {noop_start_transport_stream_op,
+                                               grpc_channel_next_op,
+                                               sizeof(call_data),
+                                               init_call_elem,
+                                               destroy_call_elem,
+                                               sizeof(channel_data),
+                                               init_channel_elem,
+                                               destroy_channel_elem,
+                                               "no-op"};
diff --git a/src/core/client_config/README.md b/src/core/client_config/README.md
new file mode 100644
index 0000000..d0700cf
--- /dev/null
+++ b/src/core/client_config/README.md
@@ -0,0 +1,62 @@
+Client Configuration Support for GRPC
+=====================================
+
+This library provides high level configuration machinery to construct client
+channels and load balance between them.
+
+Each grpc_channel is created with a grpc_resolver. It is the resolver's duty
+to resolve a name into configuration data for the channel. Such configuration
+data might include:
+
+- a list of (ip, port) addresses to connect to
+- a load balancing policy to decide which server to send a request to
+- a set of filters to mutate outgoing requests (say, by adding metadata)
+
+The resolver provides this data as a stream of grpc_client_config objects to
+the channel. We represent configuration as a stream so that it can be changed
+by the resolver during execution, by reacting to external events (such as a
+new configuration file being pushed to some store).
+
+
+Load Balancing
+--------------
+
+Load balancing configuration is provided by a grpc_lb_policy object, stored as
+part of grpc_client_config.
+
+The primary job of the load balancing policies is to pick a target server given only the
+initial metadata for a request. It does this by providing a grpc_subchannel
+object to the owning channel.
+
+
+Sub-Channels
+------------
+
+A sub-channel provides a connection to a server for a client channel. It has a
+connectivity state like a regular channel, and so can be connected or
+disconnected. This connectivity state can be used to inform load balancing
+decisions (for example, by avoiding disconnected backends).
+
+Configured sub-channels are fully setup to participate in the grpc data plane.
+Their behavior is specified by a set of grpc channel filters defined at their
+construction. To customize this behavior, resolvers build
+grpc_subchannel_factory objects, which use the decorator pattern to customize
+construction arguments for concrete grpc_subchannel instances.
+
+
+Naming for GRPC
+===============
+
+Names in GRPC are represented by a URI (as defined in
+[RFC 3986](https://tools.ietf.org/html/rfc3986)).
+
+The following schemes are currently supported:
+
+dns:///host:port - dns schemes are currently supported so long as authority is
+                   empty (authority based dns resolution is expected in a future
+                   release)
+
+unix:path        - the unix scheme is used to create and connect to unix domain
+                   sockets - the authority must be empty, and the path
+                   represents the absolute or relative path to the desired
+                   socket
diff --git a/src/core/surface/client.h b/src/core/client_config/client_config.c
similarity index 60%
copy from src/core/surface/client.h
copy to src/core/client_config/client_config.c
index 9db2ccf..4453824 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/client_config.c
@@ -31,11 +31,44 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include "src/core/client_config/client_config.h"
 
-#include "src/core/channel/channel_stack.h"
+#include <string.h>
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+#include <grpc/support/alloc.h>
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+struct grpc_client_config {
+  gpr_refcount refs;
+  grpc_lb_policy *lb_policy;
+};
+
+grpc_client_config *grpc_client_config_create() {
+  grpc_client_config *c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  gpr_ref_init(&c->refs, 1);
+  return c;
+}
+
+void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); }
+
+void grpc_client_config_unref(grpc_client_config *c) {
+  if (gpr_unref(&c->refs)) {
+    GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config");
+    gpr_free(c);
+  }
+}
+
+void grpc_client_config_set_lb_policy(grpc_client_config *c,
+                                      grpc_lb_policy *lb_policy) {
+  if (lb_policy) {
+    GRPC_LB_POLICY_REF(lb_policy, "client_config");
+  }
+  if (c->lb_policy) {
+    GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config");
+  }
+  c->lb_policy = lb_policy;
+}
+
+grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) {
+  return c->lb_policy;
+}
diff --git a/src/core/surface/client.h b/src/core/client_config/client_config.h
similarity index 66%
copy from src/core/surface/client.h
copy to src/core/client_config/client_config.h
index 9db2ccf..47612da 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/client_config.h
@@ -31,11 +31,22 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/lb_policy.h"
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+/** Total configuration for a client. Provided, and updated, by
+    grpc_resolver */
+typedef struct grpc_client_config grpc_client_config;
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+grpc_client_config *grpc_client_config_create();
+void grpc_client_config_ref(grpc_client_config *client_config);
+void grpc_client_config_unref(grpc_client_config *client_config);
+
+void grpc_client_config_set_lb_policy(grpc_client_config *client_config,
+                                      grpc_lb_policy *lb_policy);
+grpc_lb_policy *grpc_client_config_get_lb_policy(
+    grpc_client_config *client_config);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H */
diff --git a/src/core/surface/client.h b/src/core/client_config/connector.c
similarity index 73%
copy from src/core/surface/client.h
copy to src/core/client_config/connector.c
index 9db2ccf..a8cd5fc 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/connector.c
@@ -31,11 +31,19 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include "src/core/client_config/connector.h"
 
-#include "src/core/channel/channel_stack.h"
+void grpc_connector_ref(grpc_connector *connector) {
+  connector->vtable->ref(connector);
+}
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+void grpc_connector_unref(grpc_connector *connector) {
+  connector->vtable->unref(connector);
+}
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+void grpc_connector_connect(grpc_connector *connector,
+                            const grpc_connect_in_args *in_args,
+                            grpc_connect_out_args *out_args,
+                            grpc_iomgr_closure *notify) {
+  connector->vtable->connect(connector, in_args, out_args, notify);
+}
diff --git a/src/core/client_config/connector.h b/src/core/client_config/connector.h
new file mode 100644
index 0000000..edcb10a
--- /dev/null
+++ b/src/core/client_config/connector.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_CLIENT_CONFIG_CONNECTOR_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H
+
+#include "src/core/channel/channel_stack.h"
+#include "src/core/iomgr/sockaddr.h"
+#include "src/core/transport/transport.h"
+
+typedef struct grpc_connector grpc_connector;
+typedef struct grpc_connector_vtable grpc_connector_vtable;
+
+struct grpc_connector {
+  const grpc_connector_vtable *vtable;
+};
+
+typedef struct {
+  /** set of pollsets interested in this connection */
+  grpc_pollset_set *interested_parties;
+  /** address to connect to */
+  const struct sockaddr *addr;
+  int addr_len;
+  /** deadline for connection */
+  gpr_timespec deadline;
+  /** channel arguments (to be passed to transport) */
+  const grpc_channel_args *channel_args;
+  /** metadata context */
+  grpc_mdctx *metadata_context;
+} grpc_connect_in_args;
+
+typedef struct {
+  /** the connected transport */
+  grpc_transport *transport;
+  /** any additional filters (owned by the caller of connect) */
+  const grpc_channel_filter **filters;
+  size_t num_filters;
+} grpc_connect_out_args;
+
+struct grpc_connector_vtable {
+  void (*ref)(grpc_connector *connector);
+  void (*unref)(grpc_connector *connector);
+  void (*connect)(grpc_connector *connector,
+                  const grpc_connect_in_args *in_args,
+                  grpc_connect_out_args *out_args, grpc_iomgr_closure *notify);
+};
+
+void grpc_connector_ref(grpc_connector *connector);
+void grpc_connector_unref(grpc_connector *connector);
+void grpc_connector_connect(grpc_connector *connector,
+                            const grpc_connect_in_args *in_args,
+                            grpc_connect_out_args *out_args,
+                            grpc_iomgr_closure *notify);
+
+#endif
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
new file mode 100644
index 0000000..73da624
--- /dev/null
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -0,0 +1,268 @@
+/*
+ *
+ * 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/lb_policies/pick_first.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include "src/core/transport/connectivity_state.h"
+
+typedef struct pending_pick {
+  struct pending_pick *next;
+  grpc_pollset *pollset;
+  grpc_subchannel **target;
+  grpc_iomgr_closure *on_complete;
+} pending_pick;
+
+typedef struct {
+  /** base policy: must be first */
+  grpc_lb_policy base;
+  /** all our subchannels */
+  grpc_subchannel **subchannels;
+  size_t num_subchannels;
+
+  grpc_iomgr_closure connectivity_changed;
+
+  /** mutex protecting remaining members */
+  gpr_mu mu;
+  /** the selected channel
+      TODO(ctiller): this should be atomically set so we don't
+                     need to take a mutex in the common case */
+  grpc_subchannel *selected;
+  /** have we started picking? */
+  int started_picking;
+  /** which subchannel are we watching? */
+  size_t checking_subchannel;
+  /** what is the connectivity of that channel? */
+  grpc_connectivity_state checking_connectivity;
+  /** list of picks that are waiting on connectivity */
+  pending_pick *pending_picks;
+
+  /** our connectivity state tracker */
+  grpc_connectivity_state_tracker state_tracker;
+} pick_first_lb_policy;
+
+void pf_destroy(grpc_lb_policy *pol) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  size_t i;
+  for (i = 0; i < p->num_subchannels; i++) {
+    GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first");
+  }
+  gpr_free(p->subchannels);
+  gpr_mu_destroy(&p->mu);
+  gpr_free(p);
+}
+
+void pf_shutdown(grpc_lb_policy *pol) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  pending_pick *pp;
+  gpr_mu_lock(&p->mu);
+  while ((pp = p->pending_picks)) {
+    p->pending_picks = pp->next;
+    *pp->target = NULL;
+    grpc_iomgr_add_delayed_callback(pp->on_complete, 0);
+    gpr_free(pp);
+  }
+  gpr_mu_unlock(&p->mu);
+}
+
+void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
+             grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
+             grpc_iomgr_closure *on_complete) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  pending_pick *pp;
+  gpr_mu_lock(&p->mu);
+  if (p->selected) {
+    gpr_mu_unlock(&p->mu);
+    *target = p->selected;
+    on_complete->cb(on_complete->cb_arg, 1);
+  } else {
+    if (!p->started_picking) {
+      p->started_picking = 1;
+      p->checking_subchannel = 0;
+      p->checking_connectivity = GRPC_CHANNEL_IDLE;
+      GRPC_LB_POLICY_REF(pol, "pick_first_connectivity");
+      grpc_subchannel_notify_on_state_change(
+          p->subchannels[p->checking_subchannel], &p->checking_connectivity,
+          &p->connectivity_changed);
+    }
+    grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
+                                         pollset);
+    pp = gpr_malloc(sizeof(*pp));
+    pp->next = p->pending_picks;
+    pp->pollset = pollset;
+    pp->target = target;
+    pp->on_complete = on_complete;
+    p->pending_picks = pp;
+    gpr_mu_unlock(&p->mu);
+  }
+}
+
+static void del_interested_parties_locked(pick_first_lb_policy *p) {
+  pending_pick *pp;
+  for (pp = p->pending_picks; pp; pp = pp->next) {
+    grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel],
+                                         pp->pollset);
+  }
+}
+
+static void add_interested_parties_locked(pick_first_lb_policy *p) {
+  pending_pick *pp;
+  for (pp = p->pending_picks; pp; pp = pp->next) {
+    grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
+                                         pp->pollset);
+  }
+}
+
+static void pf_connectivity_changed(void *arg, int iomgr_success) {
+  pick_first_lb_policy *p = arg;
+  pending_pick *pp;
+  int unref = 0;
+
+  gpr_mu_lock(&p->mu);
+loop:
+  switch (p->checking_connectivity) {
+    case GRPC_CHANNEL_READY:
+      p->selected = p->subchannels[p->checking_subchannel];
+      while ((pp = p->pending_picks)) {
+        p->pending_picks = pp->next;
+        *pp->target = p->selected;
+        grpc_subchannel_del_interested_party(p->selected, pp->pollset);
+        grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
+        gpr_free(pp);
+      }
+      unref = 1;
+      break;
+    case GRPC_CHANNEL_TRANSIENT_FAILURE:
+      del_interested_parties_locked(p);
+      p->checking_subchannel =
+          (p->checking_subchannel + 1) % p->num_subchannels;
+      p->checking_connectivity = grpc_subchannel_check_connectivity(
+          p->subchannels[p->checking_subchannel]);
+      add_interested_parties_locked(p);
+      goto loop;
+    case GRPC_CHANNEL_CONNECTING:
+    case GRPC_CHANNEL_IDLE:
+      grpc_subchannel_notify_on_state_change(
+          p->subchannels[p->checking_subchannel], &p->checking_connectivity,
+          &p->connectivity_changed);
+      break;
+    case GRPC_CHANNEL_FATAL_FAILURE:
+      del_interested_parties_locked(p);
+      GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
+               p->subchannels[p->num_subchannels - 1]);
+      p->num_subchannels--;
+      GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first");
+      if (p->num_subchannels == 0) {
+        while ((pp = p->pending_picks)) {
+          p->pending_picks = pp->next;
+          *pp->target = NULL;
+          grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
+          gpr_free(pp);
+        }
+        unref = 1;
+      } else {
+        p->checking_subchannel %= p->num_subchannels;
+        p->checking_connectivity = grpc_subchannel_check_connectivity(
+            p->subchannels[p->checking_subchannel]);
+        add_interested_parties_locked(p);
+        goto loop;
+      }
+  }
+  gpr_mu_unlock(&p->mu);
+
+  if (unref) {
+    GRPC_LB_POLICY_UNREF(&p->base, "pick_first_connectivity");
+  }
+}
+
+static void pf_broadcast(grpc_lb_policy *pol, grpc_transport_op *op) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  size_t i;
+  size_t n;
+  grpc_subchannel **subchannels;
+
+  gpr_mu_lock(&p->mu);
+  n = p->num_subchannels;
+  subchannels = gpr_malloc(n * sizeof(*subchannels));
+  for (i = 0; i < n; i++) {
+    subchannels[i] = p->subchannels[i];
+    GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast");
+  }
+  gpr_mu_unlock(&p->mu);
+
+  for (i = 0; i < n; i++) {
+    grpc_subchannel_process_transport_op(subchannels[i], op);
+    GRPC_SUBCHANNEL_UNREF(subchannels[i], "pf_broadcast");
+  }
+  gpr_free(subchannels);
+}
+
+static grpc_connectivity_state pf_check_connectivity(grpc_lb_policy *pol) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  grpc_connectivity_state st;
+  gpr_mu_lock(&p->mu);
+  st = grpc_connectivity_state_check(&p->state_tracker);
+  gpr_mu_unlock(&p->mu);
+  return st;
+}
+
+static void pf_notify_on_state_change(grpc_lb_policy *pol,
+                                      grpc_connectivity_state *current,
+                                      grpc_iomgr_closure *notify) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  gpr_mu_lock(&p->mu);
+  grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current,
+                                                 notify);
+  gpr_mu_unlock(&p->mu);
+}
+
+static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
+    pf_destroy,   pf_shutdown,           pf_pick,
+    pf_broadcast, pf_check_connectivity, pf_notify_on_state_change};
+
+grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
+                                                 size_t num_subchannels) {
+  pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
+  GPR_ASSERT(num_subchannels);
+  memset(p, 0, sizeof(*p));
+  grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
+  p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_subchannels);
+  p->num_subchannels = num_subchannels;
+  memcpy(p->subchannels, subchannels,
+         sizeof(grpc_subchannel *) * num_subchannels);
+  grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
+  gpr_mu_init(&p->mu);
+  return &p->base;
+}
diff --git a/src/core/surface/client.h b/src/core/client_config/lb_policies/pick_first.h
similarity index 77%
copy from src/core/surface/client.h
copy to src/core/client_config/lb_policies/pick_first.h
index 9db2ccf..3139498 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/lb_policies/pick_first.h
@@ -31,11 +31,14 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/lb_policy.h"
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+/** Returns a load balancing policy instance that picks up the first subchannel
+ *  from \a subchannels to succesfully connect */
+grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
+                                                 size_t num_subchannels);
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+#endif
diff --git a/src/core/client_config/lb_policy.c b/src/core/client_config/lb_policy.c
new file mode 100644
index 0000000..6d1c788
--- /dev/null
+++ b/src/core/client_config/lb_policy.c
@@ -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.
+ *
+ */
+
+#include "src/core/client_config/lb_policy.h"
+
+void grpc_lb_policy_init(grpc_lb_policy *policy,
+                         const grpc_lb_policy_vtable *vtable) {
+  policy->vtable = vtable;
+  gpr_ref_init(&policy->refs, 1);
+}
+
+#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
+void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
+                        const char *reason) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p   ref %d -> %d %s",
+          policy, (int)policy->refs.count, (int)policy->refs.count + 1, reason);
+#else
+void grpc_lb_policy_ref(grpc_lb_policy *policy) {
+#endif
+  gpr_ref(&policy->refs);
+}
+
+#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
+void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line,
+                          const char *reason) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p unref %d -> %d %s",
+          policy, (int)policy->refs.count, (int)policy->refs.count - 1, reason);
+#else
+void grpc_lb_policy_unref(grpc_lb_policy *policy) {
+#endif
+  if (gpr_unref(&policy->refs)) {
+    policy->vtable->destroy(policy);
+  }
+}
+
+void grpc_lb_policy_shutdown(grpc_lb_policy *policy) {
+  policy->vtable->shutdown(policy);
+}
+
+void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
+                         grpc_metadata_batch *initial_metadata,
+                         grpc_subchannel **target,
+                         grpc_iomgr_closure *on_complete) {
+  policy->vtable->pick(policy, pollset, initial_metadata, target, on_complete);
+}
+
+void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op) {
+  policy->vtable->broadcast(policy, op);
+}
diff --git a/src/core/client_config/lb_policy.h b/src/core/client_config/lb_policy.h
new file mode 100644
index 0000000..a468f76
--- /dev/null
+++ b/src/core/client_config/lb_policy.h
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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_CLIENT_CONFIG_LB_POLICY_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H
+
+#include "src/core/client_config/subchannel.h"
+
+/** A load balancing policy: specified by a vtable and a struct (which
+    is expected to be extended to contain some parameters) */
+typedef struct grpc_lb_policy grpc_lb_policy;
+typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable;
+
+typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel,
+                                   grpc_status_code status, const char *errmsg);
+
+struct grpc_lb_policy {
+  const grpc_lb_policy_vtable *vtable;
+  gpr_refcount refs;
+};
+
+struct grpc_lb_policy_vtable {
+  void (*destroy)(grpc_lb_policy *policy);
+
+  void (*shutdown)(grpc_lb_policy *policy);
+
+  /** implement grpc_lb_policy_pick */
+  void (*pick)(grpc_lb_policy *policy, grpc_pollset *pollset,
+               grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
+               grpc_iomgr_closure *on_complete);
+
+  /** broadcast a transport op to all subchannels */
+  void (*broadcast)(grpc_lb_policy *policy, grpc_transport_op *op);
+
+  /** check the current connectivity of the lb_policy */
+  grpc_connectivity_state (*check_connectivity)(grpc_lb_policy *policy);
+
+  /** call notify when the connectivity state of a channel changes from *state.
+      Updates *state with the new state of the policy */
+  void (*notify_on_state_change)(grpc_lb_policy *policy,
+                                 grpc_connectivity_state *state,
+                                 grpc_iomgr_closure *closure);
+};
+
+#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
+#define GRPC_LB_POLICY_REF(p, r) \
+  grpc_lb_policy_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_LB_POLICY_UNREF(p, r) \
+  grpc_lb_policy_unref((p), __FILE__, __LINE__, (r))
+void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
+                        const char *reason);
+void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line,
+                          const char *reason);
+#else
+#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p))
+#define GRPC_LB_POLICY_UNREF(p, r) grpc_lb_policy_unref((p))
+void grpc_lb_policy_ref(grpc_lb_policy *policy);
+void grpc_lb_policy_unref(grpc_lb_policy *policy);
+#endif
+
+/** called by concrete implementations to initialize the base struct */
+void grpc_lb_policy_init(grpc_lb_policy *policy,
+                         const grpc_lb_policy_vtable *vtable);
+
+/** Start shutting down (fail any pending picks) */
+void grpc_lb_policy_shutdown(grpc_lb_policy *policy);
+
+/** Given initial metadata in \a initial_metadata, find an appropriate
+    target for this rpc, and 'return' it by calling \a on_complete after setting
+    \a target.
+    Picking can be asynchronous. Any IO should be done under \a pollset. */
+void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
+                         grpc_metadata_batch *initial_metadata,
+                         grpc_subchannel **target,
+                         grpc_iomgr_closure *on_complete);
+
+void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op);
+
+#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */
diff --git a/src/core/client_config/resolver.c b/src/core/client_config/resolver.c
new file mode 100644
index 0000000..91e42bb
--- /dev/null
+++ b/src/core/client_config/resolver.c
@@ -0,0 +1,83 @@
+/*
+ *
+ * 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/resolver.h"
+
+void grpc_resolver_init(grpc_resolver *resolver,
+                        const grpc_resolver_vtable *vtable) {
+  resolver->vtable = vtable;
+  gpr_ref_init(&resolver->refs, 1);
+}
+
+#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
+void grpc_resolver_ref(grpc_resolver *resolver, const char *file, int line,
+                       const char *reason) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p   ref %d -> %d %s",
+          resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1,
+          reason);
+#else
+void grpc_resolver_ref(grpc_resolver *resolver) {
+#endif
+  gpr_ref(&resolver->refs);
+}
+
+#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
+void grpc_resolver_unref(grpc_resolver *resolver, const char *file, int line,
+                         const char *reason) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s",
+          resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1,
+          reason);
+#else
+void grpc_resolver_unref(grpc_resolver *resolver) {
+#endif
+  if (gpr_unref(&resolver->refs)) {
+    resolver->vtable->destroy(resolver);
+  }
+}
+
+void grpc_resolver_shutdown(grpc_resolver *resolver) {
+  resolver->vtable->shutdown(resolver);
+}
+
+void grpc_resolver_channel_saw_error(grpc_resolver *resolver,
+                                     struct sockaddr *failing_address,
+                                     int failing_address_len) {
+  resolver->vtable->channel_saw_error(resolver, failing_address,
+                                      failing_address_len);
+}
+
+void grpc_resolver_next(grpc_resolver *resolver,
+                        grpc_client_config **target_config,
+                        grpc_iomgr_closure *on_complete) {
+  resolver->vtable->next(resolver, target_config, on_complete);
+}
diff --git a/src/core/client_config/resolver.h b/src/core/client_config/resolver.h
new file mode 100644
index 0000000..8ad87d7
--- /dev/null
+++ b/src/core/client_config/resolver.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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_CLIENT_CONFIG_RESOLVER_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H
+
+#include "src/core/client_config/client_config.h"
+#include "src/core/iomgr/iomgr.h"
+#include "src/core/iomgr/sockaddr.h"
+
+typedef struct grpc_resolver grpc_resolver;
+typedef struct grpc_resolver_vtable grpc_resolver_vtable;
+
+/** grpc_resolver provides grpc_client_config objects to grpc_channel
+    objects */
+struct grpc_resolver {
+  const grpc_resolver_vtable *vtable;
+  gpr_refcount refs;
+};
+
+struct grpc_resolver_vtable {
+  void (*destroy)(grpc_resolver *resolver);
+  void (*shutdown)(grpc_resolver *resolver);
+  void (*channel_saw_error)(grpc_resolver *resolver,
+                            struct sockaddr *failing_address,
+                            int failing_address_len);
+  void (*next)(grpc_resolver *resolver, grpc_client_config **target_config,
+               grpc_iomgr_closure *on_complete);
+};
+
+#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
+#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_RESOLVER_UNREF(p, r) \
+  grpc_resolver_unref((p), __FILE__, __LINE__, (r))
+void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line,
+                       const char *reason);
+void grpc_resolver_unref(grpc_resolver *policy, const char *file, int line,
+                         const char *reason);
+#else
+#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p))
+#define GRPC_RESOLVER_UNREF(p, r) grpc_resolver_unref((p))
+void grpc_resolver_ref(grpc_resolver *policy);
+void grpc_resolver_unref(grpc_resolver *policy);
+#endif
+
+void grpc_resolver_init(grpc_resolver *resolver,
+                        const grpc_resolver_vtable *vtable);
+
+void grpc_resolver_shutdown(grpc_resolver *resolver);
+
+/** Notification that the channel has seen an error on some address.
+    Can be used as a hint that re-resolution is desirable soon. */
+void grpc_resolver_channel_saw_error(grpc_resolver *resolver,
+                                     struct sockaddr *failing_address,
+                                     int failing_address_len);
+
+/** Get the next client config. Called by the channel to fetch a new
+    configuration. Expected to set *target_config with a new configuration,
+    and then schedule on_complete for execution.
+
+    If resolution is fatally broken, set *target_config to NULL and
+    schedule on_complete. */
+void grpc_resolver_next(grpc_resolver *resolver,
+                        grpc_client_config **target_config,
+                        grpc_iomgr_closure *on_complete);
+
+#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_H */
diff --git a/src/core/surface/client.h b/src/core/client_config/resolver_factory.c
similarity index 72%
copy from src/core/surface/client.h
copy to src/core/client_config/resolver_factory.c
index 9db2ccf..6721977 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/resolver_factory.c
@@ -31,11 +31,20 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include "src/core/client_config/resolver_factory.h"
 
-#include "src/core/channel/channel_stack.h"
+void grpc_resolver_factory_ref(grpc_resolver_factory *factory) {
+  factory->vtable->ref(factory);
+}
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+void grpc_resolver_factory_unref(grpc_resolver_factory *factory) {
+  factory->vtable->unref(factory);
+}
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+/** Create a resolver instance for a name */
+grpc_resolver *grpc_resolver_factory_create_resolver(
+    grpc_resolver_factory *factory, grpc_uri *uri,
+    grpc_subchannel_factory *subchannel_factory) {
+  if (!factory) return NULL;
+  return factory->vtable->create_resolver(factory, uri, subchannel_factory);
+}
diff --git a/src/core/client_config/resolver_factory.h b/src/core/client_config/resolver_factory.h
new file mode 100644
index 0000000..c5d8549
--- /dev/null
+++ b/src/core/client_config/resolver_factory.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * 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_CLIENT_CONFIG_RESOLVER_FACTORY_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H
+
+#include "src/core/client_config/resolver.h"
+#include "src/core/client_config/subchannel_factory.h"
+#include "src/core/client_config/uri_parser.h"
+
+typedef struct grpc_resolver_factory grpc_resolver_factory;
+typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
+
+/** grpc_resolver provides grpc_client_config objects to grpc_channel
+    objects */
+struct grpc_resolver_factory {
+  const grpc_resolver_factory_vtable *vtable;
+};
+
+struct grpc_resolver_factory_vtable {
+  void (*ref)(grpc_resolver_factory *factory);
+  void (*unref)(grpc_resolver_factory *factory);
+
+  grpc_resolver *(*create_resolver)(
+      grpc_resolver_factory *factory, grpc_uri *uri,
+      grpc_subchannel_factory *subchannel_factory);
+};
+
+void grpc_resolver_factory_ref(grpc_resolver_factory *resolver);
+void grpc_resolver_factory_unref(grpc_resolver_factory *resolver);
+
+/** Create a resolver instance for a name */
+grpc_resolver *grpc_resolver_factory_create_resolver(
+    grpc_resolver_factory *factory, grpc_uri *uri,
+    grpc_subchannel_factory *subchannel_factory);
+
+#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_FACTORY_H */
diff --git a/src/core/client_config/resolver_registry.c b/src/core/client_config/resolver_registry.c
new file mode 100644
index 0000000..16be2da
--- /dev/null
+++ b/src/core/client_config/resolver_registry.c
@@ -0,0 +1,124 @@
+/*
+ *
+ * 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/resolver_registry.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#define MAX_RESOLVERS 10
+
+typedef struct {
+  char *scheme;
+  grpc_resolver_factory *factory;
+} registered_resolver;
+
+static registered_resolver g_all_of_the_resolvers[MAX_RESOLVERS];
+static int g_number_of_resolvers = 0;
+
+static char *g_default_resolver_scheme;
+
+void grpc_resolver_registry_init(const char *default_resolver_scheme) {
+  g_number_of_resolvers = 0;
+  g_default_resolver_scheme = gpr_strdup(default_resolver_scheme);
+}
+
+void grpc_resolver_registry_shutdown(void) {
+  int i;
+  for (i = 0; i < g_number_of_resolvers; i++) {
+    gpr_free(g_all_of_the_resolvers[i].scheme);
+    grpc_resolver_factory_unref(g_all_of_the_resolvers[i].factory);
+  }
+  gpr_free(g_default_resolver_scheme);
+}
+
+void grpc_register_resolver_type(const char *scheme,
+                                 grpc_resolver_factory *factory) {
+  int i;
+  for (i = 0; i < g_number_of_resolvers; i++) {
+    GPR_ASSERT(0 != strcmp(scheme, g_all_of_the_resolvers[i].scheme));
+  }
+  GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
+  g_all_of_the_resolvers[g_number_of_resolvers].scheme = gpr_strdup(scheme);
+  grpc_resolver_factory_ref(factory);
+  g_all_of_the_resolvers[g_number_of_resolvers].factory = factory;
+  g_number_of_resolvers++;
+}
+
+static grpc_resolver_factory *lookup_factory(grpc_uri *uri) {
+  int i;
+
+  /* handling NULL uri's here simplifies grpc_resolver_create */
+  if (!uri) return NULL;
+
+  for (i = 0; i < g_number_of_resolvers; i++) {
+    if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i].scheme)) {
+      return g_all_of_the_resolvers[i].factory;
+    }
+  }
+
+  return NULL;
+}
+
+grpc_resolver *grpc_resolver_create(
+    const char *name, grpc_subchannel_factory *subchannel_factory) {
+  grpc_uri *uri;
+  char *tmp;
+  grpc_resolver_factory *factory = NULL;
+  grpc_resolver *resolver;
+
+  uri = grpc_uri_parse(name, 1);
+  factory = lookup_factory(uri);
+  if (factory == NULL && g_default_resolver_scheme != NULL) {
+    grpc_uri_destroy(uri);
+    gpr_asprintf(&tmp, "%s%s", g_default_resolver_scheme, name);
+    uri = grpc_uri_parse(tmp, 1);
+    factory = lookup_factory(uri);
+    if (factory == NULL) {
+      grpc_uri_destroy(grpc_uri_parse(name, 0));
+      grpc_uri_destroy(grpc_uri_parse(tmp, 0));
+      gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", name, tmp);
+    }
+    gpr_free(tmp);
+  } else if (factory == NULL) {
+    grpc_uri_destroy(grpc_uri_parse(name, 0));
+    gpr_log(GPR_ERROR, "don't know how to resolve '%s'", name);
+  }
+  resolver =
+      grpc_resolver_factory_create_resolver(factory, uri, subchannel_factory);
+  grpc_uri_destroy(uri);
+  return resolver;
+}
diff --git a/src/core/client_config/resolver_registry.h b/src/core/client_config/resolver_registry.h
new file mode 100644
index 0000000..31aa476
--- /dev/null
+++ b/src/core/client_config/resolver_registry.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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_CLIENT_CONFIG_RESOLVER_REGISTRY_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H
+
+#include "src/core/client_config/resolver_factory.h"
+
+void grpc_resolver_registry_init(const char *default_prefix);
+void grpc_resolver_registry_shutdown(void);
+
+/** Register a resolver type.
+    URI's of \a scheme will be resolved with the given resolver.
+    If \a priority is greater than zero, then the resolver will be eligible
+    to resolve names that are passed in with no scheme. Higher priority
+    resolvers will be tried before lower priority schemes. */
+void grpc_register_resolver_type(const char *scheme,
+                                 grpc_resolver_factory *factory);
+
+/** Create a resolver given \a name.
+    First tries to parse \a name as a URI. If this succeeds, tries
+    to locate a registered resolver factory based on the URI scheme.
+    If parsing or location fails, prefixes default_prefix from
+    grpc_resolver_registry_init to name, and tries again (if default_prefix
+    was not NULL).
+    If a resolver factory was found, use it to instantiate a resolver and
+    return it.
+    If a resolver factory was not found, return NULL. */
+grpc_resolver *grpc_resolver_create(
+    const char *name, grpc_subchannel_factory *subchannel_factory);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
new file mode 100644
index 0000000..ac401bc
--- /dev/null
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -0,0 +1,246 @@
+/*
+ *
+ * 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/dns_resolver.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/client_config/lb_policies/pick_first.h"
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/support/string.h"
+
+typedef struct {
+  /** base class: must be first */
+  grpc_resolver base;
+  /** refcount */
+  gpr_refcount refs;
+  /** name to resolve */
+  char *name;
+  /** default port to use */
+  char *default_port;
+  /** 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;
+} dns_resolver;
+
+static void dns_destroy(grpc_resolver *r);
+
+static void dns_start_resolving_locked(dns_resolver *r);
+static void dns_maybe_finish_next_locked(dns_resolver *r);
+
+static void dns_shutdown(grpc_resolver *r);
+static void dns_channel_saw_error(grpc_resolver *r,
+                                  struct sockaddr *failing_address,
+                                  int failing_address_len);
+static void dns_next(grpc_resolver *r, grpc_client_config **target_config,
+                     grpc_iomgr_closure *on_complete);
+
+static const grpc_resolver_vtable dns_resolver_vtable = {
+    dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next};
+
+static void dns_shutdown(grpc_resolver *resolver) {
+  dns_resolver *r = (dns_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;
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void dns_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa,
+                                  int len) {
+  dns_resolver *r = (dns_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (!r->resolving) {
+    dns_start_resolving_locked(r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void dns_next(grpc_resolver *resolver,
+                     grpc_client_config **target_config,
+                     grpc_iomgr_closure *on_complete) {
+  dns_resolver *r = (dns_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(!r->next_completion);
+  r->next_completion = on_complete;
+  r->target_config = target_config;
+  if (r->resolved_version == 0 && !r->resolving) {
+    dns_start_resolving_locked(r);
+  } else {
+    dns_maybe_finish_next_locked(r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void dns_on_resolved(void *arg, grpc_resolved_addresses *addresses) {
+  dns_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) {
+    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);
+  r->resolving = 0;
+  if (r->resolved_config) {
+    grpc_client_config_unref(r->resolved_config);
+  }
+  r->resolved_config = config;
+  r->resolved_version++;
+  dns_maybe_finish_next_locked(r);
+  gpr_mu_unlock(&r->mu);
+
+  GRPC_RESOLVER_UNREF(&r->base, "dns-resolving");
+}
+
+static void dns_start_resolving_locked(dns_resolver *r) {
+  GRPC_RESOLVER_REF(&r->base, "dns-resolving");
+  GPR_ASSERT(!r->resolving);
+  r->resolving = 1;
+  grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r);
+}
+
+static void dns_maybe_finish_next_locked(dns_resolver *r) {
+  if (r->next_completion != NULL &&
+      r->resolved_version != r->published_version) {
+    *r->target_config = r->resolved_config;
+    if (r->resolved_config) {
+      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 dns_destroy(grpc_resolver *gr) {
+  dns_resolver *r = (dns_resolver *)gr;
+  gpr_mu_destroy(&r->mu);
+  if (r->resolved_config) {
+    grpc_client_config_unref(r->resolved_config);
+  }
+  grpc_subchannel_factory_unref(r->subchannel_factory);
+  gpr_free(r->name);
+  gpr_free(r->default_port);
+  gpr_free(r);
+}
+
+static grpc_resolver *dns_create(
+    grpc_uri *uri, const char *default_port,
+    grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+                                         size_t num_subchannels),
+    grpc_subchannel_factory *subchannel_factory) {
+  dns_resolver *r;
+  const char *path = uri->path;
+
+  if (0 != strcmp(uri->authority, "")) {
+    gpr_log(GPR_ERROR, "authority based uri's not supported");
+    return NULL;
+  }
+
+  if (path[0] == '/') ++path;
+
+  r = gpr_malloc(sizeof(dns_resolver));
+  memset(r, 0, sizeof(*r));
+  gpr_ref_init(&r->refs, 1);
+  gpr_mu_init(&r->mu);
+  grpc_resolver_init(&r->base, &dns_resolver_vtable);
+  r->name = gpr_strdup(path);
+  r->default_port = gpr_strdup(default_port);
+  r->subchannel_factory = subchannel_factory;
+  r->lb_policy_factory = lb_policy_factory;
+  grpc_subchannel_factory_ref(subchannel_factory);
+  return &r->base;
+}
+
+/*
+ * FACTORY
+ */
+
+static void dns_factory_ref(grpc_resolver_factory *factory) {}
+
+static void dns_factory_unref(grpc_resolver_factory *factory) {}
+
+static grpc_resolver *dns_factory_create_resolver(
+    grpc_resolver_factory *factory, grpc_uri *uri,
+    grpc_subchannel_factory *subchannel_factory) {
+  return dns_create(uri, "https", grpc_create_pick_first_lb_policy,
+                    subchannel_factory);
+}
+
+static const grpc_resolver_factory_vtable dns_factory_vtable = {
+    dns_factory_ref, dns_factory_unref, dns_factory_create_resolver};
+static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable};
+
+grpc_resolver_factory *grpc_dns_resolver_factory_create() {
+  return &dns_resolver_factory;
+}
diff --git a/src/core/surface/client.h b/src/core/client_config/resolvers/dns_resolver.h
similarity index 80%
copy from src/core/surface/client.h
copy to src/core/client_config/resolvers/dns_resolver.h
index 9db2ccf..a3ef316 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/resolvers/dns_resolver.h
@@ -31,11 +31,12 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/resolver_factory.h"
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+/** Create a dns resolver factory */
+grpc_resolver_factory *grpc_dns_resolver_factory_create(void);
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */
diff --git a/src/core/client_config/resolvers/unix_resolver_posix.c b/src/core/client_config/resolvers/unix_resolver_posix.c
new file mode 100644
index 0000000..be515d2
--- /dev/null
+++ b/src/core/client_config/resolvers/unix_resolver_posix.c
@@ -0,0 +1,195 @@
+/*
+ *
+ * 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 <grpc/support/port_platform.h>
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/client_config/resolvers/unix_resolver_posix.h"
+
+#include <string.h>
+#include <sys/un.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/client_config/lb_policies/pick_first.h"
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/support/string.h"
+
+typedef struct {
+  /** base class: must be first */
+  grpc_resolver base;
+  /** refcount */
+  gpr_refcount refs;
+  /** subchannel factory */
+  grpc_subchannel_factory *subchannel_factory;
+  /** load balancing policy factory */
+  grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+                                       size_t num_subchannels);
+
+  /** the address that we've 'resolved' */
+  struct sockaddr_un addr;
+  int addr_len;
+
+  /** mutex guarding the rest of the state */
+  gpr_mu mu;
+  /** have we published? */
+  int published;
+  /** pending next completion, or NULL */
+  grpc_iomgr_closure *next_completion;
+  /** target config address for next completion */
+  grpc_client_config **target_config;
+} unix_resolver;
+
+static void unix_destroy(grpc_resolver *r);
+
+static void unix_maybe_finish_next_locked(unix_resolver *r);
+
+static void unix_shutdown(grpc_resolver *r);
+static void unix_channel_saw_error(grpc_resolver *r,
+                                   struct sockaddr *failing_address,
+                                   int failing_address_len);
+static void unix_next(grpc_resolver *r, grpc_client_config **target_config,
+                      grpc_iomgr_closure *on_complete);
+
+static const grpc_resolver_vtable unix_resolver_vtable = {
+    unix_destroy, unix_shutdown, unix_channel_saw_error, unix_next};
+
+static void unix_shutdown(grpc_resolver *resolver) {
+  unix_resolver *r = (unix_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (r->next_completion != NULL) {
+    *r->target_config = NULL;
+    /* TODO(ctiller): add delayed callback */
+    grpc_iomgr_add_callback(r->next_completion);
+    r->next_completion = NULL;
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void unix_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa,
+                                   int len) {}
+
+static void unix_next(grpc_resolver *resolver,
+                      grpc_client_config **target_config,
+                      grpc_iomgr_closure *on_complete) {
+  unix_resolver *r = (unix_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(!r->next_completion);
+  r->next_completion = on_complete;
+  r->target_config = target_config;
+  unix_maybe_finish_next_locked(r);
+  gpr_mu_unlock(&r->mu);
+}
+
+static void unix_maybe_finish_next_locked(unix_resolver *r) {
+  grpc_client_config *cfg;
+  grpc_lb_policy *lb_policy;
+  grpc_subchannel *subchannel;
+  grpc_subchannel_args args;
+
+  if (r->next_completion != NULL && !r->published) {
+    cfg = grpc_client_config_create();
+    memset(&args, 0, sizeof(args));
+    args.addr = (struct sockaddr *)&r->addr;
+    args.addr_len = r->addr_len;
+    subchannel =
+        grpc_subchannel_factory_create_subchannel(r->subchannel_factory, &args);
+    lb_policy = r->lb_policy_factory(&subchannel, 1);
+    grpc_client_config_set_lb_policy(cfg, lb_policy);
+    GRPC_LB_POLICY_UNREF(lb_policy, "unix");
+    r->published = 1;
+    *r->target_config = cfg;
+    grpc_iomgr_add_callback(r->next_completion);
+    r->next_completion = NULL;
+  }
+}
+
+static void unix_destroy(grpc_resolver *gr) {
+  unix_resolver *r = (unix_resolver *)gr;
+  gpr_mu_destroy(&r->mu);
+  grpc_subchannel_factory_unref(r->subchannel_factory);
+  gpr_free(r);
+}
+
+static grpc_resolver *unix_create(
+    grpc_uri *uri,
+    grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
+                                         size_t num_subchannels),
+    grpc_subchannel_factory *subchannel_factory) {
+  unix_resolver *r;
+
+  if (0 != strcmp(uri->authority, "")) {
+    gpr_log(GPR_ERROR, "authority based uri's not supported");
+    return NULL;
+  }
+
+  r = gpr_malloc(sizeof(unix_resolver));
+  memset(r, 0, sizeof(*r));
+  gpr_ref_init(&r->refs, 1);
+  gpr_mu_init(&r->mu);
+  grpc_resolver_init(&r->base, &unix_resolver_vtable);
+  r->subchannel_factory = subchannel_factory;
+  r->lb_policy_factory = lb_policy_factory;
+
+  r->addr.sun_family = AF_UNIX;
+  strcpy(r->addr.sun_path, uri->path);
+  r->addr_len = strlen(r->addr.sun_path) + sizeof(r->addr.sun_family) + 1;
+
+  grpc_subchannel_factory_ref(subchannel_factory);
+  return &r->base;
+}
+
+/*
+ * FACTORY
+ */
+
+static void unix_factory_ref(grpc_resolver_factory *factory) {}
+
+static void unix_factory_unref(grpc_resolver_factory *factory) {}
+
+static grpc_resolver *unix_factory_create_resolver(
+    grpc_resolver_factory *factory, grpc_uri *uri,
+    grpc_subchannel_factory *subchannel_factory) {
+  return unix_create(uri, grpc_create_pick_first_lb_policy, subchannel_factory);
+}
+
+static const grpc_resolver_factory_vtable unix_factory_vtable = {
+    unix_factory_ref, unix_factory_unref, unix_factory_create_resolver};
+static grpc_resolver_factory unix_resolver_factory = {&unix_factory_vtable};
+
+grpc_resolver_factory *grpc_unix_resolver_factory_create() {
+  return &unix_resolver_factory;
+}
+
+#endif
diff --git a/src/core/surface/client.h b/src/core/client_config/resolvers/unix_resolver_posix.h
similarity index 78%
copy from src/core/surface/client.h
copy to src/core/client_config/resolvers/unix_resolver_posix.h
index 9db2ccf..57ace59 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/resolvers/unix_resolver_posix.h
@@ -31,11 +31,14 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H
 
-#include "src/core/channel/channel_stack.h"
+#include <grpc/support/port_platform.h>
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+#include "src/core/client_config/resolver_factory.h"
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+/** Create a unix resolver factory */
+grpc_resolver_factory *grpc_unix_resolver_factory_create(void);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H */
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
new file mode 100644
index 0000000..35f1726
--- /dev/null
+++ b/src/core/client_config/subchannel.c
@@ -0,0 +1,659 @@
+/*
+ *
+ * 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/subchannel.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/iomgr/alarm.h"
+#include "src/core/transport/connectivity_state.h"
+
+typedef struct {
+  /* all fields protected by subchannel->mu */
+  /** refcount */
+  int refs;
+  /** parent subchannel */
+  grpc_subchannel *subchannel;
+} connection;
+
+typedef struct {
+  grpc_iomgr_closure closure;
+  size_t version;
+  grpc_subchannel *subchannel;
+  grpc_connectivity_state connectivity_state;
+} state_watcher;
+
+typedef struct waiting_for_connect {
+  struct waiting_for_connect *next;
+  grpc_iomgr_closure *notify;
+  grpc_pollset *pollset;
+  grpc_subchannel_call **target;
+  grpc_subchannel *subchannel;
+  grpc_iomgr_closure continuation;
+} waiting_for_connect;
+
+struct grpc_subchannel {
+  grpc_connector *connector;
+
+  /** non-transport related channel filters */
+  const grpc_channel_filter **filters;
+  size_t num_filters;
+  /** channel arguments */
+  grpc_channel_args *args;
+  /** address to connect to */
+  struct sockaddr *addr;
+  size_t addr_len;
+  /** metadata context */
+  grpc_mdctx *mdctx;
+  /** master channel - the grpc_channel instance that ultimately owns
+      this channel_data via its channel stack.
+      We occasionally use this to bump the refcount on the master channel
+      to keep ourselves alive through an asynchronous operation. */
+  grpc_channel *master;
+  /** have we seen a disconnection? */
+  int disconnected;
+
+  /** set during connection */
+  grpc_connect_out_args connecting_result;
+
+  /** callback for connection finishing */
+  grpc_iomgr_closure connected;
+
+  /** pollset_set tracking who's interested in a connection
+      being setup */
+  grpc_pollset_set pollset_set;
+
+  /** mutex protecting remaining elements */
+  gpr_mu mu;
+
+  /** active connection */
+  connection *active;
+  /** version number for the active connection */
+  size_t active_version;
+  /** refcount */
+  int refs;
+  /** are we connecting */
+  int connecting;
+  /** things waiting for a connection */
+  waiting_for_connect *waiting;
+  /** connectivity state tracking */
+  grpc_connectivity_state_tracker state_tracker;
+
+  /** next connect attempt time */
+  gpr_timespec next_attempt;
+  /** amount to backoff each failure */
+  gpr_timespec backoff_delta;
+  /** do we have an active alarm? */
+  int have_alarm;
+  /** our alarm */
+  grpc_alarm alarm;
+};
+
+struct grpc_subchannel_call {
+  connection *connection;
+  gpr_refcount refs;
+};
+
+#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
+#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1))
+
+static grpc_subchannel_call *create_call(connection *con);
+static void connectivity_state_changed_locked(grpc_subchannel *c);
+static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c);
+static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
+static void subchannel_connected(void *subchannel, int iomgr_success);
+
+static void subchannel_ref_locked(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+static int subchannel_unref_locked(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
+static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+static grpc_subchannel *connection_unref_locked(
+    connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
+static void subchannel_destroy(grpc_subchannel *c);
+
+#ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG
+#define SUBCHANNEL_REF_LOCKED(p, r) \
+  subchannel_ref_locked((p), __FILE__, __LINE__, (r))
+#define SUBCHANNEL_UNREF_LOCKED(p, r) \
+  subchannel_unref_locked((p), __FILE__, __LINE__, (r))
+#define CONNECTION_REF_LOCKED(p, r) \
+  connection_ref_locked((p), __FILE__, __LINE__, (r))
+#define CONNECTION_UNREF_LOCKED(p, r) \
+  connection_unref_locked((p), __FILE__, __LINE__, (r))
+#define REF_PASS_ARGS , file, line, reason
+#define REF_LOG(name, p)                                                  \
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p   ref %d -> %d %s", \
+          (name), (p), (p)->refs, (p)->refs + 1, reason)
+#define UNREF_LOG(name, p)                                                \
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \
+          (name), (p), (p)->refs, (p)->refs - 1, reason)
+#else
+#define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p))
+#define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p))
+#define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p))
+#define CONNECTION_UNREF_LOCKED(p, r) connection_unref_locked((p))
+#define REF_PASS_ARGS
+#define REF_LOG(name, p) \
+  do {                   \
+  } while (0)
+#define UNREF_LOG(name, p) \
+  do {                     \
+  } while (0)
+#endif
+
+/*
+ * connection implementation
+ */
+
+static void connection_destroy(connection *c) {
+  GPR_ASSERT(c->refs == 0);
+  grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CONNECTION(c));
+  gpr_free(c);
+}
+
+static void connection_ref_locked(
+    connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  REF_LOG("CONNECTION", c);
+  subchannel_ref_locked(c->subchannel REF_PASS_ARGS);
+  ++c->refs;
+}
+
+static grpc_subchannel *connection_unref_locked(
+    connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  grpc_subchannel *destroy = NULL;
+  UNREF_LOG("CONNECTION", c);
+  if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) {
+    destroy = c->subchannel;
+  }
+  if (--c->refs == 0 && c->subchannel->active != c) {
+    connection_destroy(c);
+  }
+  return destroy;
+}
+
+/*
+ * grpc_subchannel implementation
+ */
+
+static void subchannel_ref_locked(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  REF_LOG("SUBCHANNEL", c);
+  ++c->refs;
+}
+
+static int subchannel_unref_locked(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  UNREF_LOG("SUBCHANNEL", c);
+  return --c->refs == 0;
+}
+
+void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  gpr_mu_lock(&c->mu);
+  subchannel_ref_locked(c REF_PASS_ARGS);
+  gpr_mu_unlock(&c->mu);
+}
+
+void grpc_subchannel_unref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  int destroy;
+  gpr_mu_lock(&c->mu);
+  destroy = subchannel_unref_locked(c REF_PASS_ARGS);
+  gpr_mu_unlock(&c->mu);
+  if (destroy) subchannel_destroy(c);
+}
+
+static void subchannel_destroy(grpc_subchannel *c) {
+  if (c->active != NULL) {
+    connection_destroy(c->active);
+  }
+  gpr_free(c->filters);
+  grpc_channel_args_destroy(c->args);
+  gpr_free(c->addr);
+  grpc_mdctx_unref(c->mdctx);
+  grpc_pollset_set_destroy(&c->pollset_set);
+  grpc_connectivity_state_destroy(&c->state_tracker);
+  grpc_connector_unref(c->connector);
+  gpr_free(c);
+}
+
+void grpc_subchannel_add_interested_party(grpc_subchannel *c,
+                                          grpc_pollset *pollset) {
+  grpc_pollset_set_add_pollset(&c->pollset_set, pollset);
+}
+
+void grpc_subchannel_del_interested_party(grpc_subchannel *c,
+                                          grpc_pollset *pollset) {
+  grpc_pollset_set_del_pollset(&c->pollset_set, pollset);
+}
+
+grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
+                                        grpc_subchannel_args *args) {
+  grpc_subchannel *c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  c->refs = 1;
+  c->connector = connector;
+  grpc_connector_ref(c->connector);
+  c->num_filters = args->filter_count;
+  c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
+  memcpy(c->filters, args->filters,
+         sizeof(grpc_channel_filter *) * c->num_filters);
+  c->addr = gpr_malloc(args->addr_len);
+  memcpy(c->addr, args->addr, args->addr_len);
+  c->addr_len = args->addr_len;
+  c->args = grpc_channel_args_copy(args->args);
+  c->mdctx = args->mdctx;
+  c->master = args->master;
+  grpc_mdctx_ref(c->mdctx);
+  grpc_pollset_set_init(&c->pollset_set);
+  grpc_iomgr_closure_init(&c->connected, subchannel_connected, c);
+  grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE);
+  gpr_mu_init(&c->mu);
+  return c;
+}
+
+static void continue_connect(grpc_subchannel *c) {
+  grpc_connect_in_args args;
+
+  args.interested_parties = &c->pollset_set;
+  args.addr = c->addr;
+  args.addr_len = c->addr_len;
+  args.deadline = compute_connect_deadline(c);
+  args.channel_args = c->args;
+  args.metadata_context = c->mdctx;
+
+  grpc_connector_connect(c->connector, &args, &c->connecting_result,
+                         &c->connected);
+}
+
+static void start_connect(grpc_subchannel *c) {
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
+  c->next_attempt = now;
+  c->backoff_delta = gpr_time_from_seconds(1, GPR_TIMESPAN);
+
+  continue_connect(c);
+}
+
+static void continue_creating_call(void *arg, int iomgr_success) {
+  waiting_for_connect *w4c = arg;
+  grpc_subchannel_create_call(w4c->subchannel, w4c->pollset, w4c->target,
+                              w4c->notify);
+  GRPC_SUBCHANNEL_UNREF(w4c->subchannel, "waiting_for_connect");
+  gpr_free(w4c);
+}
+
+void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset,
+                                 grpc_subchannel_call **target,
+                                 grpc_iomgr_closure *notify) {
+  connection *con;
+  gpr_mu_lock(&c->mu);
+  if (c->active != NULL) {
+    con = c->active;
+    CONNECTION_REF_LOCKED(con, "call");
+    gpr_mu_unlock(&c->mu);
+
+    *target = create_call(con);
+    notify->cb(notify->cb_arg, 1);
+  } else {
+    waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
+    w4c->next = c->waiting;
+    w4c->notify = notify;
+    w4c->pollset = pollset;
+    w4c->target = target;
+    w4c->subchannel = c;
+    /* released when clearing w4c */
+    SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect");
+    grpc_iomgr_closure_init(&w4c->continuation, continue_creating_call, w4c);
+    c->waiting = w4c;
+    grpc_subchannel_add_interested_party(c, pollset);
+    if (!c->connecting) {
+      c->connecting = 1;
+      connectivity_state_changed_locked(c);
+      /* released by connection */
+      SUBCHANNEL_REF_LOCKED(c, "connecting");
+      gpr_mu_unlock(&c->mu);
+
+      start_connect(c);
+    } else {
+      gpr_mu_unlock(&c->mu);
+    }
+  }
+}
+
+grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
+  grpc_connectivity_state state;
+  gpr_mu_lock(&c->mu);
+  state = grpc_connectivity_state_check(&c->state_tracker);
+  gpr_mu_unlock(&c->mu);
+  return state;
+}
+
+void grpc_subchannel_notify_on_state_change(grpc_subchannel *c,
+                                            grpc_connectivity_state *state,
+                                            grpc_iomgr_closure *notify) {
+  int do_connect = 0;
+  gpr_mu_lock(&c->mu);
+  if (grpc_connectivity_state_notify_on_state_change(&c->state_tracker, state,
+                                                     notify)) {
+    do_connect = 1;
+    c->connecting = 1;
+    /* released by connection */
+    SUBCHANNEL_REF_LOCKED(c, "connecting");
+    connectivity_state_changed_locked(c);
+  }
+  gpr_mu_unlock(&c->mu);
+  if (do_connect) {
+    start_connect(c);
+  }
+}
+
+void grpc_subchannel_process_transport_op(grpc_subchannel *c,
+                                          grpc_transport_op *op) {
+  connection *con = NULL;
+  grpc_subchannel *destroy;
+  int cancel_alarm = 0;
+  gpr_mu_lock(&c->mu);
+  if (op->disconnect) {
+    c->disconnected = 1;
+    connectivity_state_changed_locked(c);
+    if (c->have_alarm) {
+      cancel_alarm = 1;
+    }
+  }
+  if (c->active != NULL) {
+    con = c->active;
+    CONNECTION_REF_LOCKED(con, "transport-op");
+  }
+  gpr_mu_unlock(&c->mu);
+
+  if (con != NULL) {
+    grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con);
+    grpc_channel_element *top_elem =
+        grpc_channel_stack_element(channel_stack, 0);
+    top_elem->filter->start_transport_op(top_elem, op);
+
+    gpr_mu_lock(&c->mu);
+    destroy = CONNECTION_UNREF_LOCKED(con, "transport-op");
+    gpr_mu_unlock(&c->mu);
+    if (destroy) {
+      subchannel_destroy(destroy);
+    }
+  }
+
+  if (cancel_alarm) {
+    grpc_alarm_cancel(&c->alarm);
+  }
+}
+
+static void on_state_changed(void *p, int iomgr_success) {
+  state_watcher *sw = p;
+  grpc_subchannel *c = sw->subchannel;
+  gpr_mu *mu = &c->mu;
+  int destroy;
+  grpc_transport_op op;
+  grpc_channel_element *elem;
+  connection *destroy_connection = NULL;
+
+  gpr_mu_lock(mu);
+
+  /* if we failed or there is a version number mismatch, just leave
+     this closure */
+  if (!iomgr_success || sw->subchannel->active_version != sw->version) {
+    goto done;
+  }
+
+  switch (sw->connectivity_state) {
+    case GRPC_CHANNEL_CONNECTING:
+    case GRPC_CHANNEL_READY:
+    case GRPC_CHANNEL_IDLE:
+      /* all is still good: keep watching */
+      memset(&op, 0, sizeof(op));
+      op.connectivity_state = &sw->connectivity_state;
+      op.on_connectivity_state_change = &sw->closure;
+      elem = grpc_channel_stack_element(
+          CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
+      elem->filter->start_transport_op(elem, &op);
+      /* early out */
+      gpr_mu_unlock(mu);
+      return;
+    case GRPC_CHANNEL_FATAL_FAILURE:
+    case GRPC_CHANNEL_TRANSIENT_FAILURE:
+      /* things have gone wrong, deactivate and enter idle */
+      if (sw->subchannel->active->refs == 0) {
+        destroy_connection = sw->subchannel->active;
+      }
+      sw->subchannel->active = NULL;
+      grpc_connectivity_state_set(&c->state_tracker,
+                                  GRPC_CHANNEL_TRANSIENT_FAILURE);
+      break;
+  }
+
+done:
+  connectivity_state_changed_locked(c);
+  destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher");
+  gpr_free(sw);
+  gpr_mu_unlock(mu);
+  if (destroy) {
+    subchannel_destroy(c);
+  }
+  if (destroy_connection != NULL) {
+    connection_destroy(destroy_connection);
+  }
+}
+
+static void publish_transport(grpc_subchannel *c) {
+  size_t channel_stack_size;
+  connection *con;
+  grpc_channel_stack *stk;
+  size_t num_filters;
+  const grpc_channel_filter **filters;
+  waiting_for_connect *w4c;
+  grpc_transport_op op;
+  state_watcher *sw;
+  connection *destroy_connection = NULL;
+  grpc_channel_element *elem;
+
+  /* build final filter list */
+  num_filters = c->num_filters + c->connecting_result.num_filters + 1;
+  filters = gpr_malloc(sizeof(*filters) * num_filters);
+  memcpy(filters, c->filters, sizeof(*filters) * c->num_filters);
+  memcpy(filters + c->num_filters, c->connecting_result.filters,
+         sizeof(*filters) * c->connecting_result.num_filters);
+  filters[num_filters - 1] = &grpc_connected_channel_filter;
+
+  /* construct channel stack */
+  channel_stack_size = grpc_channel_stack_size(filters, num_filters);
+  con = gpr_malloc(sizeof(connection) + channel_stack_size);
+  stk = (grpc_channel_stack *)(con + 1);
+  con->refs = 0;
+  con->subchannel = c;
+  grpc_channel_stack_init(filters, num_filters, c->master, c->args, c->mdctx,
+                          stk);
+  grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
+  gpr_free(c->connecting_result.filters);
+  memset(&c->connecting_result, 0, sizeof(c->connecting_result));
+
+  /* initialize state watcher */
+  sw = gpr_malloc(sizeof(*sw));
+  grpc_iomgr_closure_init(&sw->closure, on_state_changed, sw);
+  sw->subchannel = c;
+  sw->connectivity_state = GRPC_CHANNEL_READY;
+
+  gpr_mu_lock(&c->mu);
+
+  if (c->disconnected) {
+    gpr_mu_unlock(&c->mu);
+    gpr_free(sw);
+    gpr_free(filters);
+    grpc_channel_stack_destroy(stk);
+    return;
+  }
+
+  /* publish */
+  if (c->active != NULL && c->active->refs == 0) {
+    destroy_connection = c->active;
+  }
+  c->active = con;
+  c->active_version++;
+  sw->version = c->active_version;
+  c->connecting = 0;
+
+  /* watch for changes; subchannel ref for connecting is donated
+     to the state watcher */
+  memset(&op, 0, sizeof(op));
+  op.connectivity_state = &sw->connectivity_state;
+  op.on_connectivity_state_change = &sw->closure;
+  SUBCHANNEL_REF_LOCKED(c, "state_watcher");
+  GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting"));
+  elem =
+      grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
+  elem->filter->start_transport_op(elem, &op);
+
+  /* signal completion */
+  connectivity_state_changed_locked(c);
+  while ((w4c = c->waiting)) {
+    c->waiting = w4c->next;
+    grpc_iomgr_add_callback(&w4c->continuation);
+  }
+
+  gpr_mu_unlock(&c->mu);
+
+  gpr_free(filters);
+
+  if (destroy_connection != NULL) {
+    connection_destroy(destroy_connection);
+  }
+}
+
+static void on_alarm(void *arg, int iomgr_success) {
+  grpc_subchannel *c = arg;
+  gpr_mu_lock(&c->mu);
+  c->have_alarm = 0;
+  if (c->disconnected) {
+    iomgr_success = 0;
+  }
+  connectivity_state_changed_locked(c);
+  gpr_mu_unlock(&c->mu);
+  if (iomgr_success) {
+    continue_connect(c);
+  } else {
+    GRPC_SUBCHANNEL_UNREF(c, "connecting");
+  }
+}
+
+static void subchannel_connected(void *arg, int iomgr_success) {
+  grpc_subchannel *c = arg;
+  if (c->connecting_result.transport != NULL) {
+    publish_transport(c);
+  } else {
+    gpr_mu_lock(&c->mu);
+    connectivity_state_changed_locked(c);
+    GPR_ASSERT(!c->have_alarm);
+    c->have_alarm = 1;
+    c->next_attempt = gpr_time_add(c->next_attempt, c->backoff_delta);
+    c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta);
+    grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now(GPR_CLOCK_REALTIME));
+    gpr_mu_unlock(&c->mu);
+  }
+}
+
+static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {
+  return gpr_time_add(c->next_attempt, c->backoff_delta);
+}
+
+static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
+  if (c->disconnected) {
+    return GRPC_CHANNEL_FATAL_FAILURE;
+  }
+  if (c->connecting) {
+    if (c->have_alarm) {
+      return GRPC_CHANNEL_TRANSIENT_FAILURE;
+    }
+    return GRPC_CHANNEL_CONNECTING;
+  }
+  if (c->active) {
+    return GRPC_CHANNEL_READY;
+  }
+  return GRPC_CHANNEL_IDLE;
+}
+
+static void connectivity_state_changed_locked(grpc_subchannel *c) {
+  grpc_connectivity_state current = compute_connectivity_locked(c);
+  grpc_connectivity_state_set(&c->state_tracker, current);
+}
+
+/*
+ * grpc_subchannel_call implementation
+ */
+
+void grpc_subchannel_call_ref(
+    grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  gpr_ref(&c->refs);
+}
+
+void grpc_subchannel_call_unref(
+    grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  if (gpr_unref(&c->refs)) {
+    gpr_mu *mu = &c->connection->subchannel->mu;
+    grpc_subchannel *destroy;
+    grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c));
+    gpr_mu_lock(mu);
+    destroy = CONNECTION_UNREF_LOCKED(c->connection, "call");
+    gpr_mu_unlock(mu);
+    gpr_free(c);
+    if (destroy != NULL) {
+      subchannel_destroy(destroy);
+    }
+  }
+}
+
+void grpc_subchannel_call_process_op(grpc_subchannel_call *call,
+                                     grpc_transport_stream_op *op) {
+  grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);
+  grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0);
+  top_elem->filter->start_transport_stream_op(top_elem, op);
+}
+
+grpc_subchannel_call *create_call(connection *con) {
+  grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
+  grpc_subchannel_call *call =
+      gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
+  grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call);
+  call->connection = con;
+  gpr_ref_init(&call->refs, 1);
+  grpc_call_stack_init(chanstk, NULL, NULL, callstk);
+  return call;
+}
diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h
new file mode 100644
index 0000000..a23a623
--- /dev/null
+++ b/src/core/client_config/subchannel.h
@@ -0,0 +1,124 @@
+/*
+ *
+ * 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_CLIENT_CONFIG_SUBCHANNEL_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H
+
+#include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/connector.h"
+
+/** A (sub-)channel that knows how to connect to exactly one target
+    address. Provides a target for load balancing. */
+typedef struct grpc_subchannel grpc_subchannel;
+typedef struct grpc_subchannel_call grpc_subchannel_call;
+typedef struct grpc_subchannel_args grpc_subchannel_args;
+
+#ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG
+#define GRPC_SUBCHANNEL_REF(p, r) \
+  grpc_subchannel_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_UNREF(p, r) \
+  grpc_subchannel_unref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_CALL_REF(p, r) \
+  grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) \
+  grpc_subchannel_call_unref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \
+  , const char *file, int line, const char *reason
+#else
+#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p))
+#define GRPC_SUBCHANNEL_UNREF(p, r) grpc_subchannel_unref((p))
+#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
+#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) grpc_subchannel_call_unref((p))
+#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS
+#endif
+
+void grpc_subchannel_ref(
+    grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_unref(
+    grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_call_ref(
+    grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_call_unref(
+    grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+
+/** construct a call (possibly asynchronously) */
+void grpc_subchannel_create_call(grpc_subchannel *subchannel,
+                                 grpc_pollset *pollset,
+                                 grpc_subchannel_call **target,
+                                 grpc_iomgr_closure *notify);
+
+/** process a transport level op */
+void grpc_subchannel_process_transport_op(grpc_subchannel *subchannel,
+                                          grpc_transport_op *op);
+
+/** poll the current connectivity state of a channel */
+grpc_connectivity_state grpc_subchannel_check_connectivity(
+    grpc_subchannel *channel);
+
+/** call notify when the connectivity state of a channel changes from *state.
+    Updates *state with the new state of the channel */
+void grpc_subchannel_notify_on_state_change(grpc_subchannel *channel,
+                                            grpc_connectivity_state *state,
+                                            grpc_iomgr_closure *notify);
+
+void grpc_subchannel_add_interested_party(grpc_subchannel *channel,
+                                          grpc_pollset *pollset);
+void grpc_subchannel_del_interested_party(grpc_subchannel *channel,
+                                          grpc_pollset *pollset);
+
+/** continue processing a transport op */
+void grpc_subchannel_call_process_op(grpc_subchannel_call *subchannel_call,
+                                     grpc_transport_stream_op *op);
+
+struct grpc_subchannel_args {
+  /** Channel filters for this channel - wrapped factories will likely
+      want to mutate this */
+  const grpc_channel_filter **filters;
+  /** The number of filters in the above array */
+  size_t filter_count;
+  /** Channel arguments to be supplied to the newly created channel */
+  const grpc_channel_args *args;
+  /** Address to connect to */
+  struct sockaddr *addr;
+  size_t addr_len;
+  /** metadata context to use */
+  grpc_mdctx *mdctx;
+  /** master channel */
+  grpc_channel *master;
+};
+
+/** create a subchannel given a connector */
+grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
+                                        grpc_subchannel_args *args);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */
diff --git a/src/core/surface/client.h b/src/core/client_config/subchannel_factory.c
similarity index 76%
copy from src/core/surface/client.h
copy to src/core/client_config/subchannel_factory.c
index 9db2ccf..f713865 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/subchannel_factory.c
@@ -31,11 +31,16 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include "src/core/client_config/subchannel_factory.h"
 
-#include "src/core/channel/channel_stack.h"
+void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory) {
+  factory->vtable->ref(factory);
+}
+void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory) {
+  factory->vtable->unref(factory);
+}
 
-extern const grpc_channel_filter grpc_client_surface_filter;
-
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+grpc_subchannel *grpc_subchannel_factory_create_subchannel(
+    grpc_subchannel_factory *factory, grpc_subchannel_args *args) {
+  return factory->vtable->create_subchannel(factory, args);
+}
diff --git a/src/core/client_config/subchannel_factory.h b/src/core/client_config/subchannel_factory.h
new file mode 100644
index 0000000..d7eae1c
--- /dev/null
+++ b/src/core/client_config/subchannel_factory.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
+
+#include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/subchannel.h"
+
+typedef struct grpc_subchannel_factory grpc_subchannel_factory;
+typedef struct grpc_subchannel_factory_vtable grpc_subchannel_factory_vtable;
+
+/** Constructor for new configured channels.
+    Creating decorators around this type is encouraged to adapt behavior. */
+struct grpc_subchannel_factory {
+  const grpc_subchannel_factory_vtable *vtable;
+};
+
+struct grpc_subchannel_factory_vtable {
+  void (*ref)(grpc_subchannel_factory *factory);
+  void (*unref)(grpc_subchannel_factory *factory);
+  grpc_subchannel *(*create_subchannel)(grpc_subchannel_factory *factory,
+                                        grpc_subchannel_args *args);
+};
+
+void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory);
+void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory);
+
+/** Create a new grpc_subchannel */
+grpc_subchannel *grpc_subchannel_factory_create_subchannel(
+    grpc_subchannel_factory *factory, grpc_subchannel_args *args);
+
+#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */
diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c
new file mode 100644
index 0000000..410a61c
--- /dev/null
+++ b/src/core/client_config/uri_parser.c
@@ -0,0 +1,149 @@
+/*
+ *
+ * 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/uri_parser.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+static grpc_uri *bad_uri(const char *uri_text, int pos, const char *section,
+                         int suppress_errors) {
+  char *line_prefix;
+  int pfx_len;
+
+  if (!suppress_errors) {
+    gpr_asprintf(&line_prefix, "bad uri.%s: '", section);
+    pfx_len = strlen(line_prefix) + pos;
+    gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text);
+    gpr_free(line_prefix);
+
+    line_prefix = gpr_malloc(pfx_len + 1);
+    memset(line_prefix, ' ', pfx_len);
+    line_prefix[pfx_len] = 0;
+    gpr_log(GPR_ERROR, "%s^ here", line_prefix);
+    gpr_free(line_prefix);
+  }
+
+  return NULL;
+}
+
+static char *copy_fragment(const char *src, int begin, int end) {
+  char *out = gpr_malloc(end - begin + 1);
+  memcpy(out, src + begin, end - begin);
+  out[end - begin] = 0;
+  return out;
+}
+
+grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
+  grpc_uri *uri;
+  int scheme_begin = 0;
+  int scheme_end = -1;
+  int authority_begin = -1;
+  int authority_end = -1;
+  int path_begin = -1;
+  int path_end = -1;
+  int i;
+
+  for (i = scheme_begin; uri_text[i] != 0; i++) {
+    if (uri_text[i] == ':') {
+      scheme_end = i;
+      break;
+    }
+    if (uri_text[i] >= 'a' && uri_text[i] <= 'z') continue;
+    if (uri_text[i] >= 'A' && uri_text[i] <= 'Z') continue;
+    if (i != scheme_begin) {
+      if (uri_text[i] >= '0' && uri_text[i] <= '9') continue;
+      if (uri_text[i] == '+') continue;
+      if (uri_text[i] == '-') continue;
+      if (uri_text[i] == '.') continue;
+    }
+    break;
+  }
+  if (scheme_end == -1) {
+    return bad_uri(uri_text, i, "scheme", suppress_errors);
+  }
+
+  if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') {
+    authority_begin = scheme_end + 3;
+    for (i = authority_begin; uri_text[i] != 0 && authority_end == -1; i++) {
+      if (uri_text[i] == '/') {
+        authority_end = i;
+      }
+      if (uri_text[i] == '?') {
+        return bad_uri(uri_text, i, "query_not_supported", suppress_errors);
+      }
+      if (uri_text[i] == '#') {
+        return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors);
+      }
+    }
+    if (authority_end == -1 && uri_text[i] == 0) {
+      authority_end = i;
+    }
+    if (authority_end == -1) {
+      return bad_uri(uri_text, i, "authority", suppress_errors);
+    }
+    /* TODO(ctiller): parse the authority correctly */
+    path_begin = authority_end;
+  } else {
+    path_begin = scheme_end + 1;
+  }
+
+  for (i = path_begin; uri_text[i] != 0; i++) {
+    if (uri_text[i] == '?') {
+      return bad_uri(uri_text, i, "query_not_supported", suppress_errors);
+    }
+    if (uri_text[i] == '#') {
+      return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors);
+    }
+  }
+  path_end = i;
+
+  uri = gpr_malloc(sizeof(*uri));
+  memset(uri, 0, sizeof(*uri));
+  uri->scheme = copy_fragment(uri_text, scheme_begin, scheme_end);
+  uri->authority = copy_fragment(uri_text, authority_begin, authority_end);
+  uri->path = copy_fragment(uri_text, path_begin, path_end);
+
+  return uri;
+}
+
+void grpc_uri_destroy(grpc_uri *uri) {
+  if (!uri) return;
+  gpr_free(uri->scheme);
+  gpr_free(uri->authority);
+  gpr_free(uri->path);
+  gpr_free(uri);
+}
diff --git a/src/core/surface/client.h b/src/core/client_config/uri_parser.h
similarity index 80%
copy from src/core/surface/client.h
copy to src/core/client_config/uri_parser.h
index 9db2ccf..ce4e6ae 100644
--- a/src/core/surface/client.h
+++ b/src/core/client_config/uri_parser.h
@@ -31,11 +31,19 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H
+#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H
 
-#include "src/core/channel/channel_stack.h"
+typedef struct {
+  char *scheme;
+  char *authority;
+  char *path;
+} grpc_uri;
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+/** parse a uri, return NULL on failure */
+grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors);
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+/** destroy a uri */
+void grpc_uri_destroy(grpc_uri *uri);
+
+#endif
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index 4db48df..e426241 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -32,21 +32,39 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <grpc/compression.h>
 
-const char *grpc_compression_algorithm_name(
-    grpc_compression_algorithm algorithm) {
+int grpc_compression_algorithm_parse(const char* name,
+                                     grpc_compression_algorithm *algorithm) {
+  if (strcmp(name, "none") == 0) {
+    *algorithm = GRPC_COMPRESS_NONE;
+  } else if (strcmp(name, "gzip") == 0) {
+    *algorithm = GRPC_COMPRESS_GZIP;
+  } else if (strcmp(name, "deflate") == 0) {
+    *algorithm = GRPC_COMPRESS_DEFLATE;
+  } else {
+    return 0;
+  }
+  return 1;
+}
+
+int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
+                                    char **name) {
   switch (algorithm) {
     case GRPC_COMPRESS_NONE:
-      return "none";
+      *name = "none";
+      break;
     case GRPC_COMPRESS_DEFLATE:
-      return "deflate";
+      *name = "deflate";
+      break;
     case GRPC_COMPRESS_GZIP:
-      return "gzip";
-    case GRPC_COMPRESS_ALGORITHMS_COUNT:
-      return "error";
+      *name = "gzip";
+      break;
+    default:
+      return 0;
   }
-  return "error";
+  return 1;
 }
 
 /* TODO(dgq): Add the ability to specify parameters to the individual
@@ -65,3 +83,15 @@
       abort();
   }
 }
+
+grpc_compression_level grpc_compression_level_for_algorithm(
+    grpc_compression_algorithm algorithm) {
+  grpc_compression_level clevel;
+  for (clevel = GRPC_COMPRESS_LEVEL_NONE; clevel < GRPC_COMPRESS_LEVEL_COUNT;
+       ++clevel) {
+    if (grpc_compression_algorithm_for_level(clevel) == algorithm) {
+      return clevel;
+    }
+  }
+  abort();
+}
diff --git a/src/core/compression/message_compress.h b/src/core/compression/message_compress.h
index aba701a..b3eb8f5 100644
--- a/src/core/compression/message_compress.h
+++ b/src/core/compression/message_compress.h
@@ -49,4 +49,4 @@
 int grpc_msg_decompress(grpc_compression_algorithm algorithm,
                         gpr_slice_buffer *input, gpr_slice_buffer *output);
 
-#endif  /* GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H */
+#endif /* GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H */
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index fa7aabc..65997d5 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -60,14 +60,26 @@
   int use_ssl;
   grpc_httpcli_response_cb on_response;
   void *user_data;
+  grpc_httpcli_context *context;
+  grpc_pollset *pollset;
+  grpc_iomgr_object iomgr_obj;
 } internal_request;
 
 static grpc_httpcli_get_override g_get_override = NULL;
 static grpc_httpcli_post_override g_post_override = NULL;
 
+void grpc_httpcli_context_init(grpc_httpcli_context *context) {
+  grpc_pollset_set_init(&context->pollset_set);
+}
+
+void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
+  grpc_pollset_set_destroy(&context->pollset_set);
+}
+
 static void next_address(internal_request *req);
 
 static void finish(internal_request *req, int success) {
+  grpc_pollset_set_del_pollset(&req->context->pollset_set, req->pollset);
   req->on_response(req->user_data, success ? &req->parser.r : NULL);
   grpc_httpcli_parser_destroy(&req->parser);
   if (req->addresses != NULL) {
@@ -78,6 +90,7 @@
   }
   gpr_slice_unref(req->request_text);
   gpr_free(req->host);
+  grpc_iomgr_unregister_object(&req->iomgr_obj);
   gpr_free(req);
 }
 
@@ -152,6 +165,7 @@
 
 static void on_secure_transport_setup_done(void *rp,
                                            grpc_security_status status,
+                                           grpc_endpoint *wrapped_endpoint,
                                            grpc_endpoint *secure_endpoint) {
   internal_request *req = rp;
   if (status != GRPC_SECURITY_OK) {
@@ -185,7 +199,7 @@
                GRPC_SECURITY_OK);
     grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done,
                                 req);
-    grpc_security_connector_unref(&sc->base);
+    GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
   } else {
     start_write(req);
   }
@@ -198,8 +212,9 @@
     return;
   }
   addr = &req->addresses->addrs[req->next_address++];
-  grpc_tcp_client_connect(on_connected, req, (struct sockaddr *)&addr->addr,
-                          addr->len, req->deadline);
+  grpc_tcp_client_connect(on_connected, req, &req->context->pollset_set,
+                          (struct sockaddr *)&addr->addr, addr->len,
+                          req->deadline);
 }
 
 static void on_resolved(void *arg, grpc_resolved_addresses *addresses) {
@@ -213,10 +228,12 @@
   next_address(req);
 }
 
-void grpc_httpcli_get(const grpc_httpcli_request *request,
+void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset,
+                      const grpc_httpcli_request *request,
                       gpr_timespec deadline,
                       grpc_httpcli_response_cb on_response, void *user_data) {
   internal_request *req;
+  char *name;
   if (g_get_override &&
       g_get_override(request, deadline, on_response, user_data)) {
     return;
@@ -229,19 +246,27 @@
   req->user_data = user_data;
   req->deadline = deadline;
   req->use_ssl = request->use_ssl;
+  req->context = context;
+  req->pollset = pollset;
+  gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
+  grpc_iomgr_register_object(&req->iomgr_obj, name);
+  gpr_free(name);
   if (req->use_ssl) {
     req->host = gpr_strdup(request->host);
   }
 
+  grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset);
   grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
                        on_resolved, req);
 }
 
-void grpc_httpcli_post(const grpc_httpcli_request *request,
+void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
+                       const grpc_httpcli_request *request,
                        const char *body_bytes, size_t body_size,
                        gpr_timespec deadline,
                        grpc_httpcli_response_cb on_response, void *user_data) {
   internal_request *req;
+  char *name;
   if (g_post_override && g_post_override(request, body_bytes, body_size,
                                          deadline, on_response, user_data)) {
     return;
@@ -255,10 +280,16 @@
   req->user_data = user_data;
   req->deadline = deadline;
   req->use_ssl = request->use_ssl;
+  req->context = context;
+  req->pollset = pollset;
+  gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
+  grpc_iomgr_register_object(&req->iomgr_obj, name);
+  gpr_free(name);
   if (req->use_ssl) {
     req->host = gpr_strdup(request->host);
   }
 
+  grpc_pollset_set_add_pollset(&req->context->pollset_set, req->pollset);
   grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
                        on_resolved, req);
 }
diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h
index 255c5ed..ab98178 100644
--- a/src/core/httpcli/httpcli.h
+++ b/src/core/httpcli/httpcli.h
@@ -38,6 +38,8 @@
 
 #include <grpc/support/time.h>
 
+#include "src/core/iomgr/pollset_set.h"
+
 /* User agent this library reports */
 #define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0"
 /* Maximum length of a header string of the form 'Key: Value\r\n' */
@@ -49,6 +51,13 @@
   char *value;
 } grpc_httpcli_header;
 
+/* Tracks in-progress http requests
+   TODO(ctiller): allow caching and capturing multiple requests for the
+                  same content and combining them */
+typedef struct grpc_httpcli_context {
+  grpc_pollset_set pollset_set;
+} grpc_httpcli_context;
+
 /* A request */
 typedef struct grpc_httpcli_request {
   /* The host name to connect to */
@@ -76,26 +85,45 @@
   char *body;
 } grpc_httpcli_response;
 
-/* Callback for grpc_httpcli_get */
+/* Callback for grpc_httpcli_get and grpc_httpcli_post. */
 typedef void (*grpc_httpcli_response_cb)(void *user_data,
                                          const grpc_httpcli_response *response);
 
+void grpc_httpcli_context_init(grpc_httpcli_context *context);
+void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
+
 /* Asynchronously perform a HTTP GET.
+   'context' specifies the http context under which to do the get
+   'pollset' indicates a grpc_pollset that is interested in the result
+     of the get - work on this pollset may be used to progress the get
+     operation
    'request' contains request parameters - these are caller owned and can be
      destroyed once the call returns
    'deadline' contains a deadline for the request (or gpr_inf_future)
-   'em' points to a caller owned event manager that must be alive for the
-     lifetime of the request
    'on_response' is a callback to report results to (and 'user_data' is a user
      supplied pointer to pass to said call) */
-void grpc_httpcli_get(const grpc_httpcli_request *request,
+void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset,
+                      const grpc_httpcli_request *request,
                       gpr_timespec deadline,
                       grpc_httpcli_response_cb on_response, void *user_data);
 
 /* Asynchronously perform a HTTP POST.
-   When there is no body, pass in NULL as body_bytes.
+   'context' specifies the http context under which to do the post
+   'pollset' indicates a grpc_pollset that is interested in the result
+     of the post - work on this pollset may be used to progress the post
+     operation
+   'request' contains request parameters - these are caller owned and can be
+     destroyed once the call returns
+   'body_bytes' and 'body_size' specify the payload for the post.
+     When there is no body, pass in NULL as body_bytes.
+   'deadline' contains a deadline for the request (or gpr_inf_future)
+   'em' points to a caller owned event manager that must be alive for the
+     lifetime of the request
+   'on_response' is a callback to report results to (and 'user_data' is a user
+     supplied pointer to pass to said call)
    Does not support ?var1=val1&var2=val2 in the path. */
-void grpc_httpcli_post(const grpc_httpcli_request *request,
+void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
+                       const grpc_httpcli_request *request,
                        const char *body_bytes, size_t body_size,
                        gpr_timespec deadline,
                        grpc_httpcli_response_cb on_response, void *user_data);
@@ -115,4 +143,4 @@
 void grpc_httpcli_set_override(grpc_httpcli_get_override get,
                                grpc_httpcli_post_override post);
 
-#endif  /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H */
+#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H */
diff --git a/src/core/iomgr/alarm.c b/src/core/iomgr/alarm.c
index 5860834..5b9a37e 100644
--- a/src/core/iomgr/alarm.c
+++ b/src/core/iomgr/alarm.c
@@ -102,7 +102,8 @@
 
 void grpc_alarm_list_shutdown(void) {
   int i;
-  while (run_some_expired_alarms(NULL, gpr_inf_future, NULL, 0))
+  while (run_some_expired_alarms(NULL, gpr_inf_future(GPR_CLOCK_REALTIME), NULL,
+                                 0))
     ;
   for (i = 0; i < NUM_SHARDS; i++) {
     shard_type *shard = &g_shards[i];
@@ -127,6 +128,7 @@
   gpr_timespec ts;
   ts.tv_sec = d;
   ts.tv_nsec = 1e9 * (d - ts.tv_sec);
+  ts.clock_type = GPR_TIMESPAN;
   return ts;
 }
 
diff --git a/src/core/iomgr/alarm.h b/src/core/iomgr/alarm.h
index e5262e2..c067a0b 100644
--- a/src/core/iomgr/alarm.h
+++ b/src/core/iomgr/alarm.h
@@ -41,9 +41,9 @@
 typedef struct grpc_alarm {
   gpr_timespec deadline;
   gpr_uint32 heap_index; /* INVALID_HEAP_INDEX if not in heap */
+  int triggered;
   struct grpc_alarm *next;
   struct grpc_alarm *prev;
-  int triggered;
   grpc_iomgr_cb_func cb;
   void *cb_arg;
 } grpc_alarm;
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 28ed770..6ad377c 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -74,6 +74,7 @@
   gpr_mu_lock(&fd_freelist_mu);
   fd->freelist_next = fd_freelist;
   fd_freelist = fd;
+  grpc_iomgr_unregister_object(&fd->iomgr_object);
   gpr_mu_unlock(&fd_freelist_mu);
 }
 
@@ -100,6 +101,7 @@
       &r->inactive_watcher_root;
   r->freelist_next = NULL;
   r->read_watcher = r->write_watcher = NULL;
+  r->on_done_closure = NULL;
   return r;
 }
 
@@ -109,16 +111,36 @@
   gpr_free(fd);
 }
 
+#ifdef GRPC_FD_REF_COUNT_DEBUG
+#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__)
+#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
+static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file,
+                   int line) {
+  gpr_log(GPR_DEBUG, "FD %d %p   ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
+          gpr_atm_no_barrier_load(&fd->refst),
+          gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line);
+#else
+#define REF_BY(fd, n, reason) ref_by(fd, n)
+#define UNREF_BY(fd, n, reason) unref_by(fd, n)
 static void ref_by(grpc_fd *fd, int n) {
+#endif
   GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
 }
 
+#ifdef GRPC_FD_REF_COUNT_DEBUG
+static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file,
+                     int line) {
+  gpr_atm old;
+  gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
+          gpr_atm_no_barrier_load(&fd->refst),
+          gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line);
+#else
 static void unref_by(grpc_fd *fd, int n) {
-  gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
+  gpr_atm old;
+#endif
+  old = gpr_atm_full_fetch_add(&fd->refst, -n);
   if (old == n) {
-    grpc_iomgr_add_callback(&fd->on_done_closure);
     freelist_fd(fd);
-    grpc_iomgr_unregister_object(&fd->iomgr_object);
   } else {
     GPR_ASSERT(old > n);
   }
@@ -135,12 +157,9 @@
   gpr_mu_destroy(&fd_freelist_mu);
 }
 
-static void do_nothing(void *ignored, int success) {}
-
 grpc_fd *grpc_fd_create(int fd, const char *name) {
   grpc_fd *r = alloc_fd(fd);
   grpc_iomgr_register_object(&r->iomgr_object, name);
-  grpc_pollset_add_fd(grpc_backup_pollset(), r);
   return r;
 }
 
@@ -178,24 +197,47 @@
   }
 }
 
-void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) {
-  grpc_iomgr_closure_init(&fd->on_done_closure, on_done ? on_done : do_nothing,
-                          user_data);
+static int has_watchers(grpc_fd *fd) {
+  return fd->read_watcher != NULL || fd->write_watcher != NULL ||
+         fd->inactive_watcher_root.next != &fd->inactive_watcher_root;
+}
+
+void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done,
+                    const char *reason) {
+  fd->on_done_closure = on_done;
   shutdown(fd->fd, SHUT_RDWR);
-  ref_by(fd, 1); /* remove active status, but keep referenced */
+  REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
   gpr_mu_lock(&fd->watcher_mu);
-  wake_all_watchers_locked(fd);
+  if (!has_watchers(fd)) {
+    close(fd->fd);
+    if (fd->on_done_closure) {
+      grpc_iomgr_add_callback(fd->on_done_closure);
+    }
+  } else {
+    wake_all_watchers_locked(fd);
+  }
   gpr_mu_unlock(&fd->watcher_mu);
-  unref_by(fd, 2); /* drop the reference */
+  UNREF_BY(fd, 2, reason); /* drop the reference */
 }
 
 /* increment refcount by two to avoid changing the orphan bit */
+#ifdef GRPC_FD_REF_COUNT_DEBUG
+void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) {
+  ref_by(fd, 2, reason, file, line);
+}
+
+void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file,
+                   int line) {
+  unref_by(fd, 2, reason, file, line);
+}
+#else
 void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
 
 void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
+#endif
 
 static void process_callback(grpc_iomgr_closure *closure, int success,
-                          int allow_synchronous_callback) {
+                             int allow_synchronous_callback) {
   if (allow_synchronous_callback) {
     closure->cb(closure->cb_arg, success);
   } else {
@@ -235,7 +277,7 @@
       GPR_ASSERT(gpr_atm_no_barrier_load(st) == READY);
       gpr_atm_rel_store(st, NOT_READY);
       process_callback(closure, !gpr_atm_acq_load(&fd->shutdown),
-                    allow_synchronous_callback);
+                       allow_synchronous_callback);
       return;
     default: /* WAITING */
       /* upcallptr was set to a different closure.  This is an error! */
@@ -279,7 +321,7 @@
   /* only one set_ready can be active at once (but there may be a racing
      notify_on) */
   int success;
-  grpc_iomgr_closure* closure;
+  grpc_iomgr_closure *closure;
   size_t ncb = 0;
 
   gpr_mu_lock(&fd->set_state_mu);
@@ -319,17 +361,25 @@
   gpr_uint32 mask = 0;
   /* keep track of pollers that have requested our events, in case they change
    */
-  grpc_fd_ref(fd);
+  GRPC_FD_REF(fd, "poll");
 
   gpr_mu_lock(&fd->watcher_mu);
+  /* if we are shutdown, then don't add to the watcher set */
+  if (gpr_atm_no_barrier_load(&fd->shutdown)) {
+    watcher->fd = NULL;
+    watcher->pollset = NULL;
+    gpr_mu_unlock(&fd->watcher_mu);
+    GRPC_FD_UNREF(fd, "poll");
+    return 0;
+  }
   /* if there is nobody polling for read, but we need to, then start doing so */
-  if (!fd->read_watcher && gpr_atm_acq_load(&fd->readst) > READY) {
+  if (read_mask && !fd->read_watcher && gpr_atm_acq_load(&fd->readst) > READY) {
     fd->read_watcher = watcher;
     mask |= read_mask;
   }
   /* if there is nobody polling for write, but we need to, then start doing so
    */
-  if (!fd->write_watcher && gpr_atm_acq_load(&fd->writest) > READY) {
+  if (write_mask && !fd->write_watcher && gpr_atm_acq_load(&fd->writest) > READY) {
     fd->write_watcher = watcher;
     mask |= write_mask;
   }
@@ -351,6 +401,10 @@
   int kick = 0;
   grpc_fd *fd = watcher->fd;
 
+  if (fd == NULL) {
+    return;
+  }
+
   gpr_mu_lock(&fd->watcher_mu);
   if (watcher == fd->read_watcher) {
     /* remove read watcher, kick if we still need a read */
@@ -372,9 +426,15 @@
   if (kick) {
     maybe_wake_one_watcher_locked(fd);
   }
+  if (grpc_fd_is_orphaned(fd) && !has_watchers(fd)) {
+    close(fd->fd);
+    if (fd->on_done_closure != NULL) {
+      grpc_iomgr_add_callback(fd->on_done_closure);
+    }
+  }
   gpr_mu_unlock(&fd->watcher_mu);
 
-  grpc_fd_unref(fd);
+  GRPC_FD_UNREF(fd, "poll");
 }
 
 void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback) {
diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
index 0fa7185..94d0019 100644
--- a/src/core/iomgr/fd_posix.h
+++ b/src/core/iomgr/fd_posix.h
@@ -62,12 +62,12 @@
   gpr_atm shutdown;
 
   /* The watcher list.
-     
+
      The following watcher related fields are protected by watcher_mu.
-     
+
      An fd_watcher is an ephemeral object created when an fd wants to
      begin polling, and destroyed after the poll.
-     
+
      It denotes the fd's interest in whether to read poll or write poll
      or both or neither on this fd.
 
@@ -93,7 +93,7 @@
 
   struct grpc_fd *freelist_next;
 
-  grpc_iomgr_closure on_done_closure;
+  grpc_iomgr_closure *on_done_closure;
   grpc_iomgr_closure *shutdown_closures[2];
 
   grpc_iomgr_object iomgr_object;
@@ -109,7 +109,8 @@
    If on_done is NULL, no callback will be made.
    Requires: *fd initialized; no outstanding notify_on_read or
    notify_on_write. */
-void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data);
+void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done,
+                    const char *reason);
 
 /* Begin polling on an fd.
    Registers that the given pollset is interested in this fd - so that if read
@@ -159,10 +160,19 @@
 void grpc_fd_become_writable(grpc_fd *fd, int allow_synchronous_callback);
 
 /* Reference counting for fds */
+#ifdef GRPC_FD_REF_COUNT_DEBUG
+void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line);
+void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line);
+#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd, reason, __FILE__, __LINE__)
+#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd, reason, __FILE__, __LINE__)
+#else
 void grpc_fd_ref(grpc_fd *fd);
 void grpc_fd_unref(grpc_fd *fd);
+#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd)
+#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd)
+#endif
 
 void grpc_fd_global_init(void);
 void grpc_fd_global_shutdown(void);
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H */
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 0c62bfc..8741241 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -127,7 +127,6 @@
     grpc_maybe_call_delayed_callbacks(NULL, 1);
     do_iocp_work();
   }
-  gpr_log(GPR_DEBUG, "iocp_loop is done");
 
   gpr_event_set(&g_iocp_done, (void *)1);
 }
@@ -158,7 +157,7 @@
   BOOL success;
   gpr_event_set(&g_shutdown_iocp, (void *)1);
   grpc_iocp_kick();
-  gpr_event_wait(&g_iocp_done, gpr_inf_future);
+  gpr_event_wait(&g_iocp_done, gpr_inf_future(GPR_CLOCK_REALTIME));
   success = CloseHandle(g_iocp);
   GPR_ASSERT(success);
 }
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index 4503fdd..9df6476 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -34,7 +34,6 @@
 #ifndef GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H
 #define GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H
 
-#include <windows.h>
 #include <grpc/support/sync.h>
 
 #include "src/core/iomgr/socket_windows.h"
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
index fa8dcc5..0244f68 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -57,9 +57,9 @@
 static void background_callback_executor(void *ignored) {
   gpr_mu_lock(&g_mu);
   while (!g_shutdown) {
-    gpr_timespec deadline = gpr_inf_future;
-    gpr_timespec short_deadline =
-        gpr_time_add(gpr_now(), gpr_time_from_millis(100));
+    gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+    gpr_timespec short_deadline = gpr_time_add(
+        gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN));
     if (g_cbs_head) {
       grpc_iomgr_closure *closure = g_cbs_head;
       g_cbs_head = closure->next;
@@ -67,7 +67,8 @@
       gpr_mu_unlock(&g_mu);
       closure->cb(closure->cb_arg, closure->success);
       gpr_mu_lock(&g_mu);
-    } else if (grpc_alarm_check(&g_mu, gpr_now(), &deadline)) {
+    } else if (grpc_alarm_check(&g_mu, gpr_now(GPR_CLOCK_REALTIME),
+                                &deadline)) {
     } else {
       gpr_mu_unlock(&g_mu);
       gpr_sleep_until(gpr_time_min(short_deadline, deadline));
@@ -89,7 +90,7 @@
   gpr_thd_id id;
   gpr_mu_init(&g_mu);
   gpr_cv_init(&g_rcv);
-  grpc_alarm_list_init(gpr_now());
+  grpc_alarm_list_init(gpr_now(GPR_CLOCK_REALTIME));
   g_root_object.next = g_root_object.prev = &g_root_object;
   g_root_object.name = "root";
   grpc_iomgr_platform_init();
@@ -109,16 +110,29 @@
 void grpc_iomgr_shutdown(void) {
   grpc_iomgr_object *obj;
   grpc_iomgr_closure *closure;
-  gpr_timespec shutdown_deadline =
-      gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
-
+  gpr_timespec shutdown_deadline = gpr_time_add(
+      gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN));
+  gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
 
   gpr_mu_lock(&g_mu);
   g_shutdown = 1;
-  while (g_cbs_head || g_root_object.next != &g_root_object) {
-    size_t nobjs = count_objects();
-    gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", nobjs,
-            g_cbs_head ? " and executing final callbacks" : "");
+  while (g_cbs_head != NULL || g_root_object.next != &g_root_object) {
+    if (gpr_time_cmp(
+            gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time),
+            gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) {
+      if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
+        gpr_log(GPR_DEBUG,
+                "Waiting for %d iomgr objects to be destroyed and executing "
+                "final callbacks",
+                count_objects());
+      } else if (g_cbs_head != NULL) {
+        gpr_log(GPR_DEBUG, "Executing final iomgr callbacks");
+      } else {
+        gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
+                count_objects());
+      }
+      last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
+    }
     if (g_cbs_head) {
       do {
         closure = g_cbs_head;
@@ -131,12 +145,16 @@
       } while (g_cbs_head);
       continue;
     }
-    if (nobjs > 0) {
+    if (grpc_alarm_check(&g_mu, gpr_inf_future(GPR_CLOCK_REALTIME), NULL)) {
+      gpr_log(GPR_DEBUG, "got late alarm");
+      continue;
+    }
+    if (g_root_object.next != &g_root_object) {
       int timeout = 0;
-      gpr_timespec short_deadline = gpr_time_add(gpr_now(),
-                                                 gpr_time_from_millis(100));
+      gpr_timespec short_deadline = gpr_time_add(
+          gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN));
       while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
-        if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
+        if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
           timeout = 1;
           break;
         }
@@ -147,7 +165,7 @@
                 "memory leaks are likely",
                 count_objects());
         for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
-          gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s", obj->name);
+          gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s %p", obj->name, obj);
         }
         break;
       }
@@ -156,10 +174,12 @@
   gpr_mu_unlock(&g_mu);
 
   grpc_kick_poller();
-  gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future);
+  gpr_event_wait(&g_background_callback_executor_done,
+                 gpr_inf_future(GPR_CLOCK_REALTIME));
+
+  grpc_alarm_list_shutdown();
 
   grpc_iomgr_platform_shutdown();
-  grpc_alarm_list_shutdown();
   gpr_mu_destroy(&g_mu);
   gpr_cv_destroy(&g_rcv);
 }
@@ -174,15 +194,14 @@
 }
 
 void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
-  gpr_free(obj->name);
   gpr_mu_lock(&g_mu);
   obj->next->prev = obj->prev;
   obj->prev->next = obj->next;
   gpr_cv_signal(&g_rcv);
   gpr_mu_unlock(&g_mu);
+  gpr_free(obj->name);
 }
 
-
 void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
                              void *cb_arg) {
   closure->cb = cb;
@@ -190,9 +209,21 @@
   closure->next = NULL;
 }
 
+static void assert_not_scheduled_locked(grpc_iomgr_closure *closure) {
+#ifndef NDEBUG
+  grpc_iomgr_closure *c;
+
+  for (c = g_cbs_head; c; c = c->next) {
+    GPR_ASSERT(c != closure);
+  }
+#endif
+}
+
 void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *closure, int success) {
   closure->success = success;
+  GPR_ASSERT(closure->cb);
   gpr_mu_lock(&g_mu);
+  assert_not_scheduled_locked(closure);
   closure->next = NULL;
   if (!g_cbs_tail) {
     g_cbs_head = g_cbs_tail = closure;
@@ -200,15 +231,16 @@
     g_cbs_tail->next = closure;
     g_cbs_tail = closure;
   }
+  if (g_shutdown) {
+    gpr_cv_signal(&g_rcv);
+  }
   gpr_mu_unlock(&g_mu);
 }
 
-
 void grpc_iomgr_add_callback(grpc_iomgr_closure *closure) {
   grpc_iomgr_add_delayed_callback(closure, 1 /* GPR_TRUE */);
 }
 
-
 int grpc_maybe_call_delayed_callbacks(gpr_mu *drop_mu, int success) {
   int n = 0;
   gpr_mu *retake_mu = NULL;
diff --git a/src/core/iomgr/iomgr.h b/src/core/iomgr/iomgr.h
index a10e481..6d4a829 100644
--- a/src/core/iomgr/iomgr.h
+++ b/src/core/iomgr/iomgr.h
@@ -73,4 +73,8 @@
  * Can be called from within a callback or from anywhere else */
 void grpc_iomgr_add_callback(grpc_iomgr_closure *closure);
 
+/** As per grpc_iomgr_add_callback, with the ability to set the success
+    argument. */
+void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *iocb, int success);
+
 #endif  /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */
diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h
index 067af87..c40188b 100644
--- a/src/core/iomgr/pollset.h
+++ b/src/core/iomgr/pollset.h
@@ -52,23 +52,24 @@
 #include "src/core/iomgr/pollset_windows.h"
 #endif
 
-
 void grpc_pollset_init(grpc_pollset *pollset);
 void grpc_pollset_shutdown(grpc_pollset *pollset,
                            void (*shutdown_done)(void *arg),
                            void *shutdown_done_arg);
 void grpc_pollset_destroy(grpc_pollset *pollset);
 
-
 /* Do some work on a pollset.
    May involve invoking asynchronous callbacks, or actually polling file
    descriptors.
    Requires GRPC_POLLSET_MU(pollset) locked.
-   May unlock GRPC_POLLSET_MU(pollset) during its execution. */
+   May unlock GRPC_POLLSET_MU(pollset) during its execution.
+   
+   Returns true if some work has been done, and false if the deadline
+   got attained. */
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline);
 
-/* Break a pollset out of polling work
+/* Break one polling thread out of polling work for this pollset.
    Requires GRPC_POLLSET_MU(pollset) locked. */
 void grpc_pollset_kick(grpc_pollset *pollset);
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
diff --git a/src/core/iomgr/pollset_kick.h b/src/core/iomgr/pollset_kick.h
deleted file mode 100644
index cc9357d..0000000
--- a/src/core/iomgr/pollset_kick.h
+++ /dev/null
@@ -1,74 +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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_H
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-#include "src/core/iomgr/pollset_kick_posix.h"
-#endif
-
-#ifdef GPR_WIN32
-#include "src/core/iomgr/pollset_kick_windows.h"
-#endif
-
-/* This is an abstraction around the typical pipe mechanism for waking up a
-   thread sitting in a poll() style call. */
-
-void grpc_pollset_kick_global_init(void);
-void grpc_pollset_kick_global_destroy(void);
-
-void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state);
-void grpc_pollset_kick_destroy(grpc_pollset_kick_state *kick_state);
-
-/* Guarantees a pure posix implementation rather than a specialized one, if
- * applicable. Intended for testing. */
-void grpc_pollset_kick_global_init_fallback_fd(void);
-
-/* Must be called before entering poll(). If return value is -1, this consumed
-   an existing kick. Otherwise the return value is an FD to add to the poll set.
- */
-int grpc_pollset_kick_pre_poll(grpc_pollset_kick_state *kick_state);
-
-/* Consume an existing kick. Must be called after poll returns that the fd was
-   readable, and before calling kick_post_poll. */
-void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state);
-
-/* Must be called after pre_poll, and after consume if applicable */
-void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state);
-
-void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state);
-
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_H */
diff --git a/src/core/iomgr/pollset_kick.c b/src/core/iomgr/pollset_kick_posix.c
similarity index 81%
rename from src/core/iomgr/pollset_kick.c
rename to src/core/iomgr/pollset_kick_posix.c
index f0211b8..5102178 100644
--- a/src/core/iomgr/pollset_kick.c
+++ b/src/core/iomgr/pollset_kick_posix.c
@@ -34,7 +34,7 @@
 #include <grpc/support/port_platform.h>
 
 #ifdef GPR_POSIX_SOCKET
-#include "src/core/iomgr/pollset_kick.h"
+#include "src/core/iomgr/pollset_kick_posix.h"
 
 #include <errno.h>
 #include <string.h>
@@ -73,7 +73,7 @@
   return info;
 }
 
-static void destroy_wfd(grpc_kick_fd_info* wfd) {
+static void destroy_wfd(grpc_kick_fd_info *wfd) {
   grpc_wakeup_fd_destroy(&wfd->wakeup_fd);
   gpr_free(wfd);
 }
@@ -96,41 +96,49 @@
 void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state) {
   gpr_mu_init(&kick_state->mu);
   kick_state->kicked = 0;
-  kick_state->fd_info = NULL;
+  kick_state->fd_list.next = kick_state->fd_list.prev = &kick_state->fd_list;
 }
 
 void grpc_pollset_kick_destroy(grpc_pollset_kick_state *kick_state) {
   gpr_mu_destroy(&kick_state->mu);
-  GPR_ASSERT(kick_state->fd_info == NULL);
+  GPR_ASSERT(kick_state->fd_list.next == &kick_state->fd_list);
 }
 
-int grpc_pollset_kick_pre_poll(grpc_pollset_kick_state *kick_state) {
+grpc_kick_fd_info *grpc_pollset_kick_pre_poll(
+    grpc_pollset_kick_state *kick_state) {
+  grpc_kick_fd_info *fd_info;
   gpr_mu_lock(&kick_state->mu);
   if (kick_state->kicked) {
     kick_state->kicked = 0;
     gpr_mu_unlock(&kick_state->mu);
-    return -1;
+    return NULL;
   }
-  kick_state->fd_info = allocate_wfd();
+  fd_info = allocate_wfd();
+  fd_info->next = &kick_state->fd_list;
+  fd_info->prev = fd_info->next->prev;
+  fd_info->next->prev = fd_info->prev->next = fd_info;
   gpr_mu_unlock(&kick_state->mu);
-  return GRPC_WAKEUP_FD_GET_READ_FD(&kick_state->fd_info->wakeup_fd);
+  return fd_info;
 }
 
-void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state) {
-  grpc_wakeup_fd_consume_wakeup(&kick_state->fd_info->wakeup_fd);
+void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state,
+                               grpc_kick_fd_info *fd_info) {
+  grpc_wakeup_fd_consume_wakeup(&fd_info->wakeup_fd);
 }
 
-void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state) {
+void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state,
+                                 grpc_kick_fd_info *fd_info) {
   gpr_mu_lock(&kick_state->mu);
-  free_wfd(kick_state->fd_info);
-  kick_state->fd_info = NULL;
+  fd_info->next->prev = fd_info->prev;
+  fd_info->prev->next = fd_info->next;
+  free_wfd(fd_info);
   gpr_mu_unlock(&kick_state->mu);
 }
 
 void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state) {
   gpr_mu_lock(&kick_state->mu);
-  if (kick_state->fd_info != NULL) {
-    grpc_wakeup_fd_wakeup(&kick_state->fd_info->wakeup_fd);
+  if (kick_state->fd_list.next != &kick_state->fd_list) {
+    grpc_wakeup_fd_wakeup(&kick_state->fd_list.next->wakeup_fd);
   } else {
     kick_state->kicked = 1;
   }
@@ -157,5 +165,4 @@
   gpr_mu_destroy(&fd_freelist_mu);
 }
 
-
-#endif  /* GPR_POSIX_SOCKET */
+#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/iomgr/pollset_kick_posix.h b/src/core/iomgr/pollset_kick_posix.h
index 4276991..77e32a8 100644
--- a/src/core/iomgr/pollset_kick_posix.h
+++ b/src/core/iomgr/pollset_kick_posix.h
@@ -37,15 +37,57 @@
 #include "src/core/iomgr/wakeup_fd_posix.h"
 #include <grpc/support/sync.h>
 
+/* pollset kicking allows breaking a thread out of polling work for
+   a given pollset.
+   writing a byte to a pipe is used as a posix-ly portable base
+   mechanism, and eventfds are utilized on Linux for better performance. */
+
 typedef struct grpc_kick_fd_info {
   grpc_wakeup_fd_info wakeup_fd;
+  /* used for polling list and free list */
   struct grpc_kick_fd_info *next;
+  /* only used when polling */
+  struct grpc_kick_fd_info *prev;
 } grpc_kick_fd_info;
 
 typedef struct grpc_pollset_kick_state {
   gpr_mu mu;
   int kicked;
-  struct grpc_kick_fd_info *fd_info;
+  struct grpc_kick_fd_info fd_list;
 } grpc_pollset_kick_state;
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_POSIX_H */
+#define GRPC_POLLSET_KICK_GET_FD(kick_fd_info) \
+  GRPC_WAKEUP_FD_GET_READ_FD(&(kick_fd_info)->wakeup_fd)
+
+/* This is an abstraction around the typical pipe mechanism for waking up a
+   thread sitting in a poll() style call. */
+
+void grpc_pollset_kick_global_init(void);
+void grpc_pollset_kick_global_destroy(void);
+
+void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state);
+void grpc_pollset_kick_destroy(grpc_pollset_kick_state *kick_state);
+
+/* Guarantees a pure posix implementation rather than a specialized one, if
+ * applicable. Intended for testing. */
+void grpc_pollset_kick_global_init_fallback_fd(void);
+
+/* Must be called before entering poll(). If return value is NULL, this consumed
+   an existing kick. Otherwise the return value is an FD to add to the poll set.
+ */
+grpc_kick_fd_info *grpc_pollset_kick_pre_poll(
+    grpc_pollset_kick_state *kick_state);
+
+/* Consume an existing kick. Must be called after poll returns that the fd was
+   readable, and before calling kick_post_poll. */
+void grpc_pollset_kick_consume(grpc_pollset_kick_state *kick_state,
+                               grpc_kick_fd_info *fd_info);
+
+/* Must be called after pre_poll, and after consume if applicable */
+void grpc_pollset_kick_post_poll(grpc_pollset_kick_state *kick_state,
+                                 grpc_kick_fd_info *fd_info);
+
+/* Actually kick */
+void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state);
+
+#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_POSIX_H */
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index 40b7935..d697b59 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -50,27 +50,46 @@
 } pollset_hdr;
 
 static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset,
-                                                grpc_fd *fd) {
+                                                grpc_fd *fd,
+                                                int and_unlock_pollset) {
   pollset_hdr *h = pollset->data.ptr;
   struct epoll_event ev;
   int err;
+  grpc_fd_watcher watcher;
 
-  ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
-  ev.data.ptr = fd;
-  err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev);
-  if (err < 0) {
-    /* FDs may be added to a pollset multiple times, so EEXIST is normal. */
-    if (errno != EEXIST) {
-      gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd,
-              strerror(errno));
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
+
+  /* We pretend to be polling whilst adding an fd to keep the fd from being
+     closed during the add. This may result in a spurious wakeup being assigned
+     to this pollset whilst adding, but that should be benign. */
+  GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, 0, 0, &watcher) == 0);
+  if (watcher.fd != NULL) {
+    ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
+    ev.data.ptr = fd;
+    err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev);
+    if (err < 0) {
+      /* FDs may be added to a pollset multiple times, so EEXIST is normal. */
+      if (errno != EEXIST) {
+        gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd,
+                strerror(errno));
+      }
     }
   }
+  grpc_fd_end_poll(&watcher, 0, 0);
 }
 
 static void multipoll_with_epoll_pollset_del_fd(grpc_pollset *pollset,
-                                                grpc_fd *fd) {
+                                                grpc_fd *fd,
+                                                int and_unlock_pollset) {
   pollset_hdr *h = pollset->data.ptr;
   int err;
+
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
+
   /* Note that this can race with concurrent poll, but that should be fine since
    * at worst it creates a spurious read event on a reused grpc_fd object. */
   err = epoll_ctl(h->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL);
@@ -83,7 +102,7 @@
 /* TODO(klempner): We probably want to turn this down a bit */
 #define GRPC_EPOLL_MAX_EVENTS 1000
 
-static int multipoll_with_epoll_pollset_maybe_work(
+static void multipoll_with_epoll_pollset_maybe_work(
     grpc_pollset *pollset, gpr_timespec deadline, gpr_timespec now,
     int allow_synchronous_callback) {
   struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
@@ -97,17 +116,11 @@
    * here.
    */
 
-  if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
-    timeout_ms = -1;
-  } else {
-    timeout_ms = gpr_time_to_millis(gpr_time_sub(deadline, now));
-    if (timeout_ms <= 0) {
-      return 1;
-    }
-  }
   pollset->counter += 1;
   gpr_mu_unlock(&pollset->mu);
 
+  timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
+
   do {
     ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms);
     if (ep_rv < 0) {
@@ -140,13 +153,11 @@
 
   gpr_mu_lock(&pollset->mu);
   pollset->counter -= 1;
-  /* TODO(klempner): This should signal once per event rather than broadcast,
-   * although it probably doesn't matter because threads will generally be
-   * blocked in epoll_wait rather than being blocked on the cv. */
-  gpr_cv_broadcast(&pollset->cv);
-  return 1;
 }
 
+static void multipoll_with_epoll_pollset_finish_shutdown(
+    grpc_pollset *pollset) {}
+
 static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
   pollset_hdr *h = pollset->data.ptr;
   grpc_wakeup_fd_destroy(&h->wakeup_fd);
@@ -160,8 +171,11 @@
 }
 
 static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
-    multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd,
-    multipoll_with_epoll_pollset_maybe_work, epoll_kick,
+    multipoll_with_epoll_pollset_add_fd,
+    multipoll_with_epoll_pollset_del_fd,
+    multipoll_with_epoll_pollset_maybe_work,
+    epoll_kick,
+    multipoll_with_epoll_pollset_finish_shutdown,
     multipoll_with_epoll_pollset_destroy};
 
 static void epoll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
@@ -180,7 +194,7 @@
     abort();
   }
   for (i = 0; i < nfds; i++) {
-    multipoll_with_epoll_pollset_add_fd(pollset, fds[i]);
+    multipoll_with_epoll_pollset_add_fd(pollset, fds[i], 0);
   }
 
   grpc_wakeup_fd_create(&h->wakeup_fd);
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index d781c9b..0084e83 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -66,23 +66,29 @@
 } pollset_hdr;
 
 static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset,
-                                               grpc_fd *fd) {
+                                               grpc_fd *fd,
+                                               int and_unlock_pollset) {
   size_t i;
   pollset_hdr *h = pollset->data.ptr;
   /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */
   for (i = 0; i < h->fd_count; i++) {
-    if (h->fds[i] == fd) return;
+    if (h->fds[i] == fd) goto exit;
   }
   if (h->fd_count == h->fd_capacity) {
     h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2);
     h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity);
   }
   h->fds[h->fd_count++] = fd;
-  grpc_fd_ref(fd);
+  GRPC_FD_REF(fd, "multipoller");
+exit:  
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
 }
 
 static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset,
-                                               grpc_fd *fd) {
+                                               grpc_fd *fd,
+                                               int and_unlock_pollset) {
   /* will get removed next poll cycle */
   pollset_hdr *h = pollset->data.ptr;
   if (h->del_count == h->del_capacity) {
@@ -90,7 +96,10 @@
     h->dels = gpr_realloc(h->dels, sizeof(grpc_fd *) * h->del_capacity);
   }
   h->dels[h->del_count++] = fd;
-  grpc_fd_ref(fd);
+  GRPC_FD_REF(fd, "multipoller_del");
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
 }
 
 static void end_polling(grpc_pollset *pollset) {
@@ -103,26 +112,17 @@
   }
 }
 
-static int multipoll_with_poll_pollset_maybe_work(
+static void multipoll_with_poll_pollset_maybe_work(
     grpc_pollset *pollset, gpr_timespec deadline, gpr_timespec now,
     int allow_synchronous_callback) {
   int timeout;
   int r;
   size_t i, np, nf, nd;
   pollset_hdr *h;
+  grpc_kick_fd_info *kfd;
 
-  if (pollset->counter) {
-    return 0;
-  }
   h = pollset->data.ptr;
-  if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
-    timeout = -1;
-  } else {
-    timeout = gpr_time_to_millis(gpr_time_sub(deadline, now));
-    if (timeout <= 0) {
-      return 1;
-    }
-  }
+  timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
   if (h->pfd_capacity < h->fd_count + 1) {
     h->pfd_capacity = GPR_MAX(h->pfd_capacity * 3 / 2, h->fd_count + 1);
     gpr_free(h->pfds);
@@ -132,11 +132,12 @@
   }
   nf = 0;
   np = 1;
-  h->pfds[0].fd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
-  if (h->pfds[0].fd < 0) {
+  kfd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
+  if (kfd == NULL) {
     /* Already kicked */
-    return 1;
+    return;
   }
+  h->pfds[0].fd = GRPC_POLLSET_KICK_GET_FD(kfd);
   h->pfds[0].events = POLLIN;
   h->pfds[0].revents = POLLOUT;
   for (i = 0; i < h->fd_count; i++) {
@@ -145,7 +146,7 @@
       if (h->fds[i] == h->dels[nd]) remove = 1;
     }
     if (remove) {
-      grpc_fd_unref(h->fds[i]);
+      GRPC_FD_UNREF(h->fds[i], "multipoller");
     } else {
       h->fds[nf++] = h->fds[i];
       h->watchers[np].fd = h->fds[i];
@@ -157,14 +158,14 @@
   h->pfd_count = np;
   h->fd_count = nf;
   for (nd = 0; nd < h->del_count; nd++) {
-    grpc_fd_unref(h->dels[nd]);
+    GRPC_FD_UNREF(h->dels[nd], "multipoller_del");
   }
   h->del_count = 0;
   if (h->pfd_count == 0) {
     end_polling(pollset);
-    return 0;
+    return;
   }
-  pollset->counter = 1;
+  pollset->counter++;
   gpr_mu_unlock(&pollset->mu);
 
   for (i = 1; i < np; i++) {
@@ -184,9 +185,12 @@
     /* do nothing */
   } else {
     if (h->pfds[0].revents & POLLIN) {
-      grpc_pollset_kick_consume(&pollset->kick_state);
+      grpc_pollset_kick_consume(&pollset->kick_state, kfd);
     }
     for (i = 1; i < np; i++) {
+      if (h->watchers[i].fd == NULL) {
+        continue;
+      }
       if (h->pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
         grpc_fd_become_readable(h->watchers[i].fd, allow_synchronous_callback);
       }
@@ -195,28 +199,33 @@
       }
     }
   }
-  grpc_pollset_kick_post_poll(&pollset->kick_state);
+  grpc_pollset_kick_post_poll(&pollset->kick_state, kfd);
 
   gpr_mu_lock(&pollset->mu);
-  pollset->counter = 0;
-  gpr_cv_broadcast(&pollset->cv);
-  return 1;
+  pollset->counter--;
 }
 
 static void multipoll_with_poll_pollset_kick(grpc_pollset *p) {
   grpc_pollset_force_kick(p);
 }
 
-static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
+static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
   size_t i;
   pollset_hdr *h = pollset->data.ptr;
   GPR_ASSERT(pollset->counter == 0);
   for (i = 0; i < h->fd_count; i++) {
-    grpc_fd_unref(h->fds[i]);
+    GRPC_FD_UNREF(h->fds[i], "multipoller");
   }
   for (i = 0; i < h->del_count; i++) {
-    grpc_fd_unref(h->dels[i]);
+    GRPC_FD_UNREF(h->dels[i], "multipoller_del");
   }
+  h->fd_count = 0;
+  h->del_count = 0;
+}
+
+static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
+  pollset_hdr *h = pollset->data.ptr;
+  multipoll_with_poll_pollset_finish_shutdown(pollset);
   gpr_free(h->pfds);
   gpr_free(h->watchers);
   gpr_free(h->fds);
@@ -225,8 +234,11 @@
 }
 
 static const grpc_pollset_vtable multipoll_with_poll_pollset = {
-    multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd,
-    multipoll_with_poll_pollset_maybe_work, multipoll_with_poll_pollset_kick,
+    multipoll_with_poll_pollset_add_fd,
+    multipoll_with_poll_pollset_del_fd,
+    multipoll_with_poll_pollset_maybe_work,
+    multipoll_with_poll_pollset_kick,
+    multipoll_with_poll_pollset_finish_shutdown,
     multipoll_with_poll_pollset_destroy};
 
 void grpc_poll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
@@ -247,7 +259,7 @@
   h->dels = NULL;
   for (i = 0; i < nfds; i++) {
     h->fds[i] = fds[i];
-    grpc_fd_ref(fds[i]);
+    GRPC_FD_REF(fds[i], "multipoller");
   }
 }
 
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index d2f6152..efb301d 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -54,31 +54,8 @@
 #include <grpc/support/tls.h>
 #include <grpc/support/useful.h>
 
-static grpc_pollset g_backup_pollset;
-static int g_shutdown_backup_poller;
-static gpr_event g_backup_poller_done;
-static gpr_event g_backup_pollset_shutdown_done;
-
 GPR_TLS_DECL(g_current_thread_poller);
 
-static void backup_poller(void *p) {
-  gpr_timespec delta = gpr_time_from_millis(100);
-  gpr_timespec last_poll = gpr_now();
-
-  gpr_mu_lock(&g_backup_pollset.mu);
-  while (g_shutdown_backup_poller == 0) {
-    gpr_timespec next_poll = gpr_time_add(last_poll, delta);
-    grpc_pollset_work(&g_backup_pollset, gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
-    gpr_mu_unlock(&g_backup_pollset.mu);
-    gpr_sleep_until(next_poll);
-    gpr_mu_lock(&g_backup_pollset.mu);
-    last_poll = next_poll;
-  }
-  gpr_mu_unlock(&g_backup_pollset.mu);
-
-  gpr_event_set(&g_backup_poller_done, (void *)1);
-}
-
 void grpc_pollset_kick(grpc_pollset *p) {
   if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p && p->counter) {
     p->vtable->kick(p);
@@ -99,44 +76,14 @@
 
 /* global state management */
 
-grpc_pollset *grpc_backup_pollset(void) { return &g_backup_pollset; }
-
 void grpc_pollset_global_init(void) {
-  gpr_thd_id id;
-
   gpr_tls_init(&g_current_thread_poller);
 
   /* Initialize kick fd state */
   grpc_pollset_kick_global_init();
-
-  /* initialize the backup pollset */
-  grpc_pollset_init(&g_backup_pollset);
-
-  /* start the backup poller thread */
-  g_shutdown_backup_poller = 0;
-  gpr_event_init(&g_backup_poller_done);
-  gpr_event_init(&g_backup_pollset_shutdown_done);
-  gpr_thd_new(&id, backup_poller, NULL, NULL);
-}
-
-static void on_backup_pollset_shutdown_done(void *arg) {
-  gpr_event_set(&g_backup_pollset_shutdown_done, (void *)1);
 }
 
 void grpc_pollset_global_shutdown(void) {
-  /* terminate the backup poller thread */
-  gpr_mu_lock(&g_backup_pollset.mu);
-  g_shutdown_backup_poller = 1;
-  gpr_mu_unlock(&g_backup_pollset.mu);
-  gpr_event_wait(&g_backup_poller_done, gpr_inf_future);
-
-  grpc_pollset_shutdown(&g_backup_pollset, on_backup_pollset_shutdown_done,
-                        NULL);
-  gpr_event_wait(&g_backup_pollset_shutdown_done, gpr_inf_future);
-
-  /* destroy the backup pollset */
-  grpc_pollset_destroy(&g_backup_pollset);
-
   /* destroy the kick pipes */
   grpc_pollset_kick_global_destroy();
 
@@ -145,36 +92,51 @@
 
 /* main interface */
 
-static void become_empty_pollset(grpc_pollset *pollset);
-static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd);
+static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null);
 
 void grpc_pollset_init(grpc_pollset *pollset) {
   gpr_mu_init(&pollset->mu);
-  gpr_cv_init(&pollset->cv);
   grpc_pollset_kick_init(&pollset->kick_state);
   pollset->in_flight_cbs = 0;
   pollset->shutting_down = 0;
-  become_empty_pollset(pollset);
+  pollset->called_shutdown = 0;
+  become_basic_pollset(pollset, NULL);
 }
 
 void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
   gpr_mu_lock(&pollset->mu);
-  pollset->vtable->add_fd(pollset, fd);
-  gpr_cv_broadcast(&pollset->cv);
+  pollset->vtable->add_fd(pollset, fd, 1);
+  /* the following (enabled only in debug) will reacquire and then release
+     our lock - meaning that if the unlocking flag passed to del_fd above is
+     not respected, the code will deadlock (in a way that we have a chance of
+     debugging) */
+#ifndef NDEBUG
+  gpr_mu_lock(&pollset->mu);
   gpr_mu_unlock(&pollset->mu);
+#endif
 }
 
 void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
   gpr_mu_lock(&pollset->mu);
-  pollset->vtable->del_fd(pollset, fd);
-  gpr_cv_broadcast(&pollset->cv);
+  pollset->vtable->del_fd(pollset, fd, 1);
+  /* the following (enabled only in debug) will reacquire and then release
+     our lock - meaning that if the unlocking flag passed to del_fd above is
+     not respected, the code will deadlock (in a way that we have a chance of
+     debugging) */
+#ifndef NDEBUG
+  gpr_mu_lock(&pollset->mu);
   gpr_mu_unlock(&pollset->mu);
+#endif
+}
+
+static void finish_shutdown(grpc_pollset *pollset) {
+  pollset->vtable->finish_shutdown(pollset);
+  pollset->shutdown_done_cb(pollset->shutdown_done_arg);
 }
 
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
   /* pollset->mu already held */
-  gpr_timespec now = gpr_now();
-  int r;
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   if (gpr_time_cmp(now, deadline) > 0) {
     return 0;
   }
@@ -188,14 +150,15 @@
     return 1;
   }
   gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset);
-  r = pollset->vtable->maybe_work(pollset, deadline, now, 1);
+  pollset->vtable->maybe_work(pollset, deadline, now, 1);
   gpr_tls_set(&g_current_thread_poller, 0);
   if (pollset->shutting_down) {
     if (pollset->counter > 0) {
       grpc_pollset_kick(pollset);
-    } else if (pollset->in_flight_cbs == 0) {
+    } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) {
+      pollset->called_shutdown = 1;
       gpr_mu_unlock(&pollset->mu);
-      pollset->shutdown_done_cb(pollset->shutdown_done_arg);
+      finish_shutdown(pollset);
       /* Continuing to access pollset here is safe -- it is the caller's
        * responsibility to not destroy when it has outstanding calls to
        * grpc_pollset_work.
@@ -203,27 +166,30 @@
       gpr_mu_lock(&pollset->mu);
     }
   }
-  return r;
+  return 1;
 }
 
 void grpc_pollset_shutdown(grpc_pollset *pollset,
                            void (*shutdown_done)(void *arg),
                            void *shutdown_done_arg) {
-  int in_flight_cbs;
-  int counter;
+  int call_shutdown = 0;
   gpr_mu_lock(&pollset->mu);
+  GPR_ASSERT(!pollset->shutting_down);
   pollset->shutting_down = 1;
-  in_flight_cbs = pollset->in_flight_cbs;
-  counter = pollset->counter;
+  if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 &&
+      pollset->counter == 0) {
+    pollset->called_shutdown = 1;
+    call_shutdown = 1;
+  }
   pollset->shutdown_done_cb = shutdown_done;
   pollset->shutdown_done_arg = shutdown_done_arg;
-  if (counter > 0) {
+  if (pollset->counter > 0) {
     grpc_pollset_kick(pollset);
   }
   gpr_mu_unlock(&pollset->mu);
 
-  if (in_flight_cbs == 0 && counter == 0) {
-    shutdown_done(shutdown_done_arg);
+  if (call_shutdown) {
+    finish_shutdown(pollset);
   }
 }
 
@@ -233,41 +199,30 @@
   pollset->vtable->destroy(pollset);
   grpc_pollset_kick_destroy(&pollset->kick_state);
   gpr_mu_destroy(&pollset->mu);
-  gpr_cv_destroy(&pollset->cv);
+}
+
+int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
+                                         gpr_timespec now) {
+  gpr_timespec timeout;
+  static const int max_spin_polling_us = 10;
+  if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) {
+    return -1;
+  }
+  if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros(
+                                                   max_spin_polling_us,
+                                                   GPR_TIMESPAN))) <= 0) {
+    return 0;
+  }
+  timeout = gpr_time_sub(deadline, now);
+  return gpr_time_to_millis(gpr_time_add(
+      timeout, gpr_time_from_nanos(GPR_NS_PER_SEC - 1, GPR_TIMESPAN)));
 }
 
 /*
- * empty_pollset - a vtable that provides polling for NO file descriptors
+ * basic_pollset - a vtable that provides polling for zero or one file
+ *                 descriptor via poll()
  */
 
-static void empty_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
-  become_unary_pollset(pollset, fd);
-}
-
-static void empty_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {}
-
-static int empty_pollset_maybe_work(grpc_pollset *pollset,
-                                    gpr_timespec deadline, gpr_timespec now,
-                                    int allow_synchronous_callback) {
-  return 0;
-}
-
-static void empty_pollset_destroy(grpc_pollset *pollset) {}
-
-static const grpc_pollset_vtable empty_pollset = {
-    empty_pollset_add_fd, empty_pollset_del_fd, empty_pollset_maybe_work,
-    kick_using_pollset_kick, empty_pollset_destroy};
-
-static void become_empty_pollset(grpc_pollset *pollset) {
-  pollset->vtable = &empty_pollset;
-}
-
-/*
- * unary_poll_pollset - a vtable that provides polling for one file descriptor
- *                      via poll()
- */
-
-
 typedef struct grpc_unary_promote_args {
   const grpc_pollset_vtable *original_vtable;
   grpc_pollset *pollset;
@@ -275,7 +230,7 @@
   grpc_iomgr_closure promotion_closure;
 } grpc_unary_promote_args;
 
-static void unary_poll_do_promote(void *args, int success) {
+static void basic_do_promote(void *args, int success) {
   grpc_unary_promote_args *up_args = args;
   const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
   grpc_pollset *pollset = up_args->pollset;
@@ -293,7 +248,7 @@
 
   gpr_mu_lock(&pollset->mu);
   /* First we need to ensure that nobody is polling concurrently */
-  while (pollset->counter != 0) {
+  if (pollset->counter != 0) {
     grpc_pollset_kick(pollset);
     grpc_iomgr_add_callback(&up_args->promotion_closure);
     gpr_mu_unlock(&pollset->mu);
@@ -309,46 +264,48 @@
   pollset->in_flight_cbs--;
   if (pollset->shutting_down) {
     /* We don't care about this pollset anymore. */
-    if (pollset->in_flight_cbs == 0 && pollset->counter == 0) {
+    if (pollset->in_flight_cbs == 0 && pollset->counter == 0 && !pollset->called_shutdown) {
+      pollset->called_shutdown = 1;
       do_shutdown_cb = 1;
     }
   } else if (grpc_fd_is_orphaned(fd)) {
     /* Don't try to add it to anything, we'll drop our ref on it below */
   } else if (pollset->vtable != original_vtable) {
-    pollset->vtable->add_fd(pollset, fd);
+    pollset->vtable->add_fd(pollset, fd, 0);
   } else if (fd != pollset->data.ptr) {
     grpc_fd *fds[2];
     fds[0] = pollset->data.ptr;
     fds[1] = fd;
 
-    if (!grpc_fd_is_orphaned(fds[0])) {
+    if (fds[0] && !grpc_fd_is_orphaned(fds[0])) {
       grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds));
-      grpc_fd_unref(fds[0]);
+      GRPC_FD_UNREF(fds[0], "basicpoll");
     } else {
       /* old fd is orphaned and we haven't cleaned it up until now, so remain a
        * unary poller */
       /* Note that it is possible that fds[1] is also orphaned at this point.
        * That's okay, we'll correct it at the next add or poll. */
-      grpc_fd_unref(fds[0]);
+      if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll");
       pollset->data.ptr = fd;
-      grpc_fd_ref(fd);
+      GRPC_FD_REF(fd, "basicpoll");
     }
   }
 
-  gpr_cv_broadcast(&pollset->cv);
   gpr_mu_unlock(&pollset->mu);
 
   if (do_shutdown_cb) {
     pollset->shutdown_done_cb(pollset->shutdown_done_arg);
   }
 
-  /* Matching ref in unary_poll_pollset_add_fd */
-  grpc_fd_unref(fd);
+  /* Matching ref in basic_pollset_add_fd */
+  GRPC_FD_UNREF(fd, "basicpoll_add");
 }
 
-static void unary_poll_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
+static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd,
+                                 int and_unlock_pollset) {
   grpc_unary_promote_args *up_args;
-  if (fd == pollset->data.ptr) return;
+  GPR_ASSERT(fd);
+  if (fd == pollset->data.ptr) goto exit;
 
   if (!pollset->counter) {
     /* Fast path -- no in flight cbs */
@@ -358,92 +315,110 @@
     fds[0] = pollset->data.ptr;
     fds[1] = fd;
 
-    if (!grpc_fd_is_orphaned(fds[0])) {
+    if (fds[0] == NULL) {
+      pollset->data.ptr = fd;
+      GRPC_FD_REF(fd, "basicpoll");
+    } else if (!grpc_fd_is_orphaned(fds[0])) {
       grpc_platform_become_multipoller(pollset, fds, GPR_ARRAY_SIZE(fds));
-      grpc_fd_unref(fds[0]);
+      GRPC_FD_UNREF(fds[0], "basicpoll");
     } else {
       /* old fd is orphaned and we haven't cleaned it up until now, so remain a
        * unary poller */
-      grpc_fd_unref(fds[0]);
+      GRPC_FD_UNREF(fds[0], "basicpoll");
       pollset->data.ptr = fd;
-      grpc_fd_ref(fd);
+      GRPC_FD_REF(fd, "basicpoll");
     }
-    return;
+    goto exit;
   }
 
   /* Now we need to promote. This needs to happen when we're not polling. Since
    * this may be called from poll, the wait needs to happen asynchronously. */
-  grpc_fd_ref(fd);
+  GRPC_FD_REF(fd, "basicpoll_add");
   pollset->in_flight_cbs++;
   up_args = gpr_malloc(sizeof(*up_args));
   up_args->pollset = pollset;
   up_args->fd = fd;
   up_args->original_vtable = pollset->vtable;
-  up_args->promotion_closure.cb = unary_poll_do_promote;
+  up_args->promotion_closure.cb = basic_do_promote;
   up_args->promotion_closure.cb_arg = up_args;
   grpc_iomgr_add_callback(&up_args->promotion_closure);
 
   grpc_pollset_kick(pollset);
-}
 
-static void unary_poll_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
-  if (fd == pollset->data.ptr) {
-    grpc_fd_unref(pollset->data.ptr);
-    become_empty_pollset(pollset);
+exit:
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
   }
 }
 
-static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
-                                         gpr_timespec deadline,
-                                         gpr_timespec now,
-                                         int allow_synchronous_callback) {
+static void basic_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd,
+                                 int and_unlock_pollset) {
+  GPR_ASSERT(fd);
+  if (fd == pollset->data.ptr) {
+    GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
+    pollset->data.ptr = NULL;
+  }
+
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
+}
+
+static void basic_pollset_maybe_work(grpc_pollset *pollset,
+                                     gpr_timespec deadline, gpr_timespec now,
+                                     int allow_synchronous_callback) {
   struct pollfd pfd[2];
   grpc_fd *fd;
   grpc_fd_watcher fd_watcher;
+  grpc_kick_fd_info *kfd;
   int timeout;
   int r;
+  int nfds;
 
-  if (pollset->counter) {
-    return 0;
-  }
   if (pollset->in_flight_cbs) {
     /* Give do_promote priority so we don't starve it out */
-    return 0;
+    gpr_mu_unlock(&pollset->mu);
+    gpr_mu_lock(&pollset->mu);
+    return;
   }
   fd = pollset->data.ptr;
-  if (grpc_fd_is_orphaned(fd)) {
-    grpc_fd_unref(fd);
-    become_empty_pollset(pollset);
-    return 0;
+  if (fd && grpc_fd_is_orphaned(fd)) {
+    GRPC_FD_UNREF(fd, "basicpoll");
+    fd = pollset->data.ptr = NULL;
   }
-  if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
-    timeout = -1;
-  } else {
-    timeout = gpr_time_to_millis(gpr_time_sub(deadline, now));
-    if (timeout <= 0) {
-      return 1;
-    }
-  }
-  pfd[0].fd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
-  if (pfd[0].fd < 0) {
+  timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
+  kfd = grpc_pollset_kick_pre_poll(&pollset->kick_state);
+  if (kfd == NULL) {
     /* Already kicked */
-    return 1;
+    return;
   }
+  pfd[0].fd = GRPC_POLLSET_KICK_GET_FD(kfd);
   pfd[0].events = POLLIN;
   pfd[0].revents = 0;
-  pfd[1].fd = fd->fd;
-  pfd[1].revents = 0;
-  pollset->counter = 1;
-  gpr_mu_unlock(&pollset->mu);
-
-  pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
+  nfds = 1;
+  pollset->counter++;
+  if (fd) {
+    pfd[1].fd = fd->fd;
+    pfd[1].revents = 0;
+    gpr_mu_unlock(&pollset->mu);
+    pfd[1].events =
+        grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
+    if (pfd[1].events != 0) {
+      nfds++;
+    }
+  } else {
+    gpr_mu_unlock(&pollset->mu);
+  }
 
   /* poll fd count (argument 2) is shortened by one if we have no events
      to poll on - such that it only includes the kicker */
-  r = poll(pfd, GPR_ARRAY_SIZE(pfd) - (pfd[1].events == 0), timeout);
+  r = poll(pfd, nfds, timeout);
   GRPC_TIMER_MARK(GRPC_PTAG_POLL_FINISHED, r);
 
-  grpc_fd_end_poll(&fd_watcher, pfd[1].revents & POLLIN, pfd[1].revents & POLLOUT);
+  if (fd) {
+    grpc_fd_end_poll(&fd_watcher, pfd[1].revents & POLLIN,
+                     pfd[1].revents & POLLOUT);
+  }
 
   if (r < 0) {
     if (errno != EINTR) {
@@ -453,39 +428,43 @@
     /* do nothing */
   } else {
     if (pfd[0].revents & POLLIN) {
-      grpc_pollset_kick_consume(&pollset->kick_state);
+      grpc_pollset_kick_consume(&pollset->kick_state, kfd);
     }
-    if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
-      grpc_fd_become_readable(fd, allow_synchronous_callback);
-    }
-    if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) {
-      grpc_fd_become_writable(fd, allow_synchronous_callback);
+    if (nfds > 1) {
+      if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
+        grpc_fd_become_readable(fd, allow_synchronous_callback);
+      }
+      if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) {
+        grpc_fd_become_writable(fd, allow_synchronous_callback);
+      }
     }
   }
 
-  grpc_pollset_kick_post_poll(&pollset->kick_state);
+  grpc_pollset_kick_post_poll(&pollset->kick_state, kfd);
 
   gpr_mu_lock(&pollset->mu);
-  pollset->counter = 0;
-  gpr_cv_broadcast(&pollset->cv);
-  return 1;
+  pollset->counter--;
 }
 
-static void unary_poll_pollset_destroy(grpc_pollset *pollset) {
+static void basic_pollset_destroy(grpc_pollset *pollset) {
   GPR_ASSERT(pollset->counter == 0);
-  grpc_fd_unref(pollset->data.ptr);
+  if (pollset->data.ptr != NULL) {
+    GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
+    pollset->data.ptr = NULL;
+  }
 }
 
-static const grpc_pollset_vtable unary_poll_pollset = {
-    unary_poll_pollset_add_fd, unary_poll_pollset_del_fd,
-    unary_poll_pollset_maybe_work, kick_using_pollset_kick,
-    unary_poll_pollset_destroy};
+static const grpc_pollset_vtable basic_pollset = {
+    basic_pollset_add_fd,    basic_pollset_del_fd,  basic_pollset_maybe_work,
+    kick_using_pollset_kick, basic_pollset_destroy, basic_pollset_destroy};
 
-static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd) {
-  pollset->vtable = &unary_poll_pollset;
+static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
+  pollset->vtable = &basic_pollset;
   pollset->counter = 0;
-  pollset->data.ptr = fd;
-  grpc_fd_ref(fd);
+  pollset->data.ptr = fd_or_null;
+  if (fd_or_null) {
+    GRPC_FD_REF(fd_or_null, "basicpoll");
+  }
 }
 
 #endif /* GPR_POSIX_POLLSET */
diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h
index 088ec91..37de127 100644
--- a/src/core/iomgr/pollset_posix.h
+++ b/src/core/iomgr/pollset_posix.h
@@ -36,7 +36,7 @@
 
 #include <grpc/support/sync.h>
 
-#include "src/core/iomgr/pollset_kick.h"
+#include "src/core/iomgr/pollset_kick_posix.h"
 
 typedef struct grpc_pollset_vtable grpc_pollset_vtable;
 
@@ -52,11 +52,11 @@
      few fds, and an epoll() based implementation for many fds */
   const grpc_pollset_vtable *vtable;
   gpr_mu mu;
-  gpr_cv cv;
   grpc_pollset_kick_state kick_state;
   int counter;
   int in_flight_cbs;
   int shutting_down;
+  int called_shutdown;
   void (*shutdown_done_cb)(void *arg);
   void *shutdown_done_arg;
   union {
@@ -66,16 +66,18 @@
 } grpc_pollset;
 
 struct grpc_pollset_vtable {
-  void (*add_fd)(grpc_pollset *pollset, struct grpc_fd *fd);
-  void (*del_fd)(grpc_pollset *pollset, struct grpc_fd *fd);
-  int (*maybe_work)(grpc_pollset *pollset, gpr_timespec deadline,
-                    gpr_timespec now, int allow_synchronous_callback);
+  void (*add_fd)(grpc_pollset *pollset, struct grpc_fd *fd,
+                 int and_unlock_pollset);
+  void (*del_fd)(grpc_pollset *pollset, struct grpc_fd *fd,
+                 int and_unlock_pollset);
+  void (*maybe_work)(grpc_pollset *pollset, gpr_timespec deadline,
+                     gpr_timespec now, int allow_synchronous_callback);
   void (*kick)(grpc_pollset *pollset);
+  void (*finish_shutdown)(grpc_pollset *pollset);
   void (*destroy)(grpc_pollset *pollset);
 };
 
 #define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)
-#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv)
 
 /* Add an fd to a pollset */
 void grpc_pollset_add_fd(grpc_pollset *pollset, struct grpc_fd *fd);
@@ -94,11 +96,14 @@
 /* Call after polling has been kicked to leave the kicked state */
 void grpc_kick_drain(grpc_pollset *p);
 
-/* All fds get added to a backup pollset to ensure that progress is made
-   regardless of applications listening to events. Relying on this is slow
-   however (the backup pollset only listens every 100ms or so) - so it's not
-   to be relied on. */
-grpc_pollset *grpc_backup_pollset(void);
+/* Convert a timespec to milliseconds:
+   - very small or negative poll times are clamped to zero to do a 
+     non-blocking poll (which becomes spin polling)
+   - other small values are rounded up to one millisecond
+   - longer than a millisecond polls are rounded up to the next nearest 
+     millisecond to avoid spinning
+   - infinite timeouts are converted to -1 */
+int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now);
 
 /* turn a pollset into a multipoller: platform specific */
 typedef void (*grpc_platform_become_multipoller_type)(grpc_pollset *pollset,
diff --git a/src/core/surface/client.h b/src/core/iomgr/pollset_set.h
similarity index 61%
copy from src/core/surface/client.h
copy to src/core/iomgr/pollset_set.h
index 9db2ccf..6d73951 100644
--- a/src/core/surface/client.h
+++ b/src/core/iomgr/pollset_set.h
@@ -31,11 +31,29 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H
+#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/iomgr/pollset.h"
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+/* A grpc_pollset_set is a set of pollsets that are interested in an
+   action. Adding a pollset to a pollset_set automatically adds any
+   fd's (etc) that have been registered with the set_set to that pollset.
+   Registering fd's automatically adds them to all current pollsets. */
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+#ifdef GPR_POSIX_SOCKET
+#include "src/core/iomgr/pollset_set_posix.h"
+#endif
+
+#ifdef GPR_WIN32
+#include "src/core/iomgr/pollset_set_windows.h"
+#endif
+
+void grpc_pollset_set_init(grpc_pollset_set *pollset_set);
+void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set);
+void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset);
+void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset);
+
+#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
diff --git a/src/core/iomgr/pollset_set_posix.c b/src/core/iomgr/pollset_set_posix.c
new file mode 100644
index 0000000..5ff7df1
--- /dev/null
+++ b/src/core/iomgr/pollset_set_posix.c
@@ -0,0 +1,125 @@
+/*
+ *
+ * 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 <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/iomgr/pollset_set.h"
+
+void grpc_pollset_set_init(grpc_pollset_set *pollset_set) {
+  memset(pollset_set, 0, sizeof(*pollset_set));
+  gpr_mu_init(&pollset_set->mu);
+}
+
+void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
+  size_t i;
+  gpr_mu_destroy(&pollset_set->mu);
+  for (i = 0; i < pollset_set->fd_count; i++) {
+    GRPC_FD_UNREF(pollset_set->fds[i], "pollset");
+  }
+  gpr_free(pollset_set->pollsets);
+  gpr_free(pollset_set->fds);
+}
+
+void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset) {
+  size_t i;
+  gpr_mu_lock(&pollset_set->mu);
+  if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
+    pollset_set->pollset_capacity =
+        GPR_MAX(8, 2 * pollset_set->pollset_capacity);
+    pollset_set->pollsets =
+        gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity *
+                                               sizeof(*pollset_set->pollsets));
+  }
+  pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
+  for (i = 0; i < pollset_set->fd_count; i++) {
+    grpc_pollset_add_fd(pollset, pollset_set->fds[i]);
+  }
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset) {
+  size_t i;
+  gpr_mu_lock(&pollset_set->mu);
+  for (i = 0; i < pollset_set->pollset_count; i++) {
+    if (pollset_set->pollsets[i] == pollset) {
+      pollset_set->pollset_count--;
+      GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i],
+               pollset_set->pollsets[pollset_set->pollset_count]);
+      break;
+    }
+  }
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+void grpc_pollset_set_add_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) {
+  size_t i;
+  gpr_mu_lock(&pollset_set->mu);
+  if (pollset_set->fd_count == pollset_set->fd_capacity) {
+    pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity);
+    pollset_set->fds = gpr_realloc(
+        pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds));
+  }
+  GRPC_FD_REF(fd, "pollset_set");
+  pollset_set->fds[pollset_set->fd_count++] = fd;
+  for (i = 0; i < pollset_set->pollset_count; i++) {
+    grpc_pollset_add_fd(pollset_set->pollsets[i], fd);
+  }
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) {
+  size_t i;
+  gpr_mu_lock(&pollset_set->mu);
+  for (i = 0; i < pollset_set->fd_count; i++) {
+    if (pollset_set->fds[i] == fd) {
+      pollset_set->fd_count--;
+      GPR_SWAP(grpc_fd *, pollset_set->fds[i],
+               pollset_set->fds[pollset_set->fd_count]);
+      GRPC_FD_UNREF(fd, "pollset_set");
+      break;
+    }
+  }
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/surface/client.h b/src/core/iomgr/pollset_set_posix.h
similarity index 72%
copy from src/core/surface/client.h
copy to src/core/iomgr/pollset_set_posix.h
index 9db2ccf..e88740b 100644
--- a/src/core/surface/client.h
+++ b/src/core/iomgr/pollset_set_posix.h
@@ -31,11 +31,25 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
+#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/iomgr/fd_posix.h"
+#include "src/core/iomgr/pollset_posix.h"
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+typedef struct grpc_pollset_set {
+  gpr_mu mu;
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+  size_t pollset_count;
+  size_t pollset_capacity;
+  grpc_pollset **pollsets;
+
+  size_t fd_count;
+  size_t fd_capacity;
+  grpc_fd **fds;
+} grpc_pollset_set;
+
+void grpc_pollset_set_add_fd(grpc_pollset_set *pollset_set, grpc_fd *fd);
+void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd);
+
+#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/iomgr/pollset_kick_windows.h b/src/core/iomgr/pollset_set_windows.c
similarity index 75%
rename from src/core/iomgr/pollset_kick_windows.h
rename to src/core/iomgr/pollset_set_windows.c
index c675c11..b9c209c 100644
--- a/src/core/iomgr/pollset_kick_windows.h
+++ b/src/core/iomgr/pollset_set_windows.c
@@ -31,18 +31,20 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_WINDOWS_H
+#include <grpc/support/port_platform.h>
 
-#include <grpc/support/sync.h>
+#ifdef GPR_WINSOCK_SOCKET
 
-/* There isn't really any such thing as a pollset under Windows, due to the
-   nature of the IO completion ports. */
+#include "src/core/iomgr/pollset_set.h"
 
-struct grpc_kick_fd_info;
+void grpc_pollset_set_init(grpc_pollset_set *pollset_set) {}
 
-typedef struct grpc_pollset_kick_state {
-  int unused;
-} grpc_pollset_kick_state;
+void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {}
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_KICK_WINDOWS_H */
+void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset) {}
+
+void grpc_pollset_set_del_pollset(grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset) {}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h b/src/core/iomgr/pollset_set_windows.h
similarity index 86%
copy from src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
copy to src/core/iomgr/pollset_set_windows.h
index 28c7374..cada0d2 100644
--- a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
+++ b/src/core/iomgr/pollset_set_windows.h
@@ -31,10 +31,9 @@
  *
  */
 
-#import <Foundation/Foundation.h>
+#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
+#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
 
-#import "GRPCMethodName.h"
+typedef struct grpc_pollset_set { void *unused; } grpc_pollset_set;
 
-@interface GRPCMethodName (HTTP2Encoding)
-- (NSString *)HTTP2Path;
-@end
+#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index b1f4c09..24226cc 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -39,6 +39,7 @@
 
 #include "src/core/iomgr/alarm_internal.h"
 #include "src/core/iomgr/iomgr_internal.h"
+#include "src/core/iomgr/pollset.h"
 #include "src/core/iomgr/pollset_windows.h"
 
 /* There isn't really any such thing as a pollset under Windows, due to the
@@ -47,6 +48,7 @@
    won't actually do any polling, and return as quickly as possible. */
 
 void grpc_pollset_init(grpc_pollset *pollset) {
+  memset(pollset, 0, sizeof(*pollset));
   gpr_mu_init(&pollset->mu);
   gpr_cv_init(&pollset->cv);
 }
@@ -54,6 +56,10 @@
 void grpc_pollset_shutdown(grpc_pollset *pollset,
                            void (*shutdown_done)(void *arg),
                            void *shutdown_done_arg) {
+  gpr_mu_lock(&pollset->mu);
+  pollset->shutting_down = 1;
+  gpr_cv_broadcast(&pollset->cv);
+  gpr_mu_unlock(&pollset->mu);
   shutdown_done(shutdown_done_arg);
 }
 
@@ -64,19 +70,22 @@
 
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
   gpr_timespec now;
-  now = gpr_now();
+  now = gpr_now(GPR_CLOCK_REALTIME);
   if (gpr_time_cmp(now, deadline) > 0) {
     return 0 /* GPR_FALSE */;
   }
-  if (grpc_maybe_call_delayed_callbacks(NULL, 1 /* GPR_TRUE */)) {
+  if (grpc_maybe_call_delayed_callbacks(&pollset->mu, 1 /* GPR_TRUE */)) {
     return 1 /* GPR_TRUE */;
   }
-  if (grpc_alarm_check(NULL, now, &deadline)) {
+  if (grpc_alarm_check(&pollset->mu, now, &deadline)) {
     return 1 /* GPR_TRUE */;
   }
-  return 0 /* GPR_FALSE */;
+  if (!pollset->shutting_down) {
+    gpr_cv_wait(&pollset->cv, &pollset->mu, deadline);
+  }
+  return 1 /* GPR_TRUE */;
 }
 
-void grpc_pollset_kick(grpc_pollset *p) { }
+void grpc_pollset_kick(grpc_pollset *p) { gpr_cv_signal(&p->cv); }
 
-#endif  /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h
index e1115ba..c9b8d3f 100644
--- a/src/core/iomgr/pollset_windows.h
+++ b/src/core/iomgr/pollset_windows.h
@@ -34,23 +34,20 @@
 #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H
 #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H
 
-#include <windows.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/iomgr/pollset_kick.h"
 #include "src/core/iomgr/socket_windows.h"
 
 /* There isn't really any such thing as a pollset under Windows, due to the
    nature of the IO completion ports. A Windows "pollset" is merely a mutex
-   and a condition variable, as this is the minimal set of features we need
-   implemented for the rest of grpc. But we won't use them directly. */
+   and a condition variable, used to synchronize with the IOCP. */
 
 typedef struct grpc_pollset {
   gpr_mu mu;
   gpr_cv cv;
+  int shutting_down;
 } grpc_pollset;
 
 #define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)
-#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv)
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c
index 20d8c58..dbf884c 100644
--- a/src/core/iomgr/resolve_address_posix.c
+++ b/src/core/iomgr/resolve_address_posix.c
@@ -155,9 +155,9 @@
   grpc_resolve_cb cb = r->cb;
   gpr_free(r->name);
   gpr_free(r->default_port);
+  cb(arg, resolved);
   grpc_iomgr_unregister_object(&r->iomgr_object);
   gpr_free(r);
-  cb(arg, resolved);
 }
 
 void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h
index c0385ea..be55db8 100644
--- a/src/core/iomgr/sockaddr_win32.h
+++ b/src/core/iomgr/sockaddr_win32.h
@@ -34,8 +34,8 @@
 #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H
 #define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H
 
-#include <ws2tcpip.h>
 #include <winsock2.h>
+#include <ws2tcpip.h>
 #include <mswsock.h>
 
 #ifdef __MINGW32__
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index fbf3fdc..f6ddfff 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -37,6 +37,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
 #include "src/core/iomgr/iocp_windows.h"
 #include "src/core/iomgr/iomgr_internal.h"
@@ -45,11 +46,14 @@
 #include "src/core/iomgr/socket_windows.h"
 
 grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) {
+  char *final_name;
   grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket));
   memset(r, 0, sizeof(grpc_winsocket));
   r->socket = socket;
   gpr_mu_init(&r->state_mu);
-  grpc_iomgr_register_object(&r->iomgr_object, name);
+  gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
+  grpc_iomgr_register_object(&r->iomgr_object, final_name);
+  gpr_free(final_name);
   grpc_iocp_add_socket(r);
   return r;
 }
@@ -58,22 +62,27 @@
    operations to abort them. We need to do that this way because of the
    various callsites of that function, which happens to be in various
    mutex hold states, and that'd be unsafe to call them directly. */
-int grpc_winsocket_shutdown(grpc_winsocket *socket) {
+int grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
   int callbacks_set = 0;
-  gpr_mu_lock(&socket->state_mu);
-  if (socket->read_info.cb) {
+  SOCKET socket;
+  gpr_mu_lock(&winsocket->state_mu);
+  socket = winsocket->socket;
+  if (winsocket->read_info.cb) {
     callbacks_set++;
-    grpc_iomgr_closure_init(&socket->shutdown_closure, socket->read_info.cb,
-                            socket->read_info.opaque);
-    grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
+    grpc_iomgr_closure_init(&winsocket->shutdown_closure,
+                            winsocket->read_info.cb,
+                            winsocket->read_info.opaque);
+    grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
   }
-  if (socket->write_info.cb) {
+  if (winsocket->write_info.cb) {
     callbacks_set++;
-    grpc_iomgr_closure_init(&socket->shutdown_closure, socket->write_info.cb,
-                            socket->write_info.opaque);
-    grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
+    grpc_iomgr_closure_init(&winsocket->shutdown_closure,
+                            winsocket->write_info.cb,
+                            winsocket->write_info.opaque);
+    grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
   }
-  gpr_mu_unlock(&socket->state_mu);
+  gpr_mu_unlock(&winsocket->state_mu);
+  closesocket(socket);
   return callbacks_set;
 }
 
@@ -84,14 +93,12 @@
    an "idle" socket which is neither trying to read or write, we'd start leaking
    both memory and sockets. */
 void grpc_winsocket_orphan(grpc_winsocket *winsocket) {
-  SOCKET socket = winsocket->socket;
   grpc_iomgr_unregister_object(&winsocket->iomgr_object);
   if (winsocket->read_info.outstanding || winsocket->write_info.outstanding) {
     grpc_iocp_socket_orphan(winsocket);
   } else {
     grpc_winsocket_destroy(winsocket);
   }
-  closesocket(socket);
 }
 
 void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
index 7080919..346fde8 100644
--- a/src/core/iomgr/socket_windows.h
+++ b/src/core/iomgr/socket_windows.h
@@ -34,7 +34,8 @@
 #ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H
 #define GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H
 
-#include <windows.h>
+#include <grpc/support/port_platform.h>
+#include <winsock2.h>
 
 #include <grpc/support/sync.h>
 #include <grpc/support/atm.h>
diff --git a/src/core/iomgr/tcp_client.h b/src/core/iomgr/tcp_client.h
index 2e91497..0fa08b5 100644
--- a/src/core/iomgr/tcp_client.h
+++ b/src/core/iomgr/tcp_client.h
@@ -35,14 +35,18 @@
 #define GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H
 
 #include "src/core/iomgr/endpoint.h"
+#include "src/core/iomgr/pollset_set.h"
 #include "src/core/iomgr/sockaddr.h"
 #include <grpc/support/time.h>
 
 /* Asynchronously connect to an address (specified as (addr, len)), and call
    cb with arg and the completed connection when done (or call cb with arg and
-   NULL on failure) */
+   NULL on failure). 
+   interested_parties points to a set of pollsets that would be interested
+   in this connection being established (in order to continue their work) */
 void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
-                             void *arg, const struct sockaddr *addr,
-                             int addr_len, gpr_timespec deadline);
+                             void *arg, grpc_pollset_set *interested_parties,
+                             const struct sockaddr *addr, int addr_len,
+                             gpr_timespec deadline);
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_CLIENT_H */
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index 668a651..dc0489e 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -63,6 +63,7 @@
   grpc_alarm alarm;
   int refs;
   grpc_iomgr_closure write_closure;
+  grpc_pollset_set *interested_parties;
 } async_connect;
 
 static int prepare_socket(const struct sockaddr *addr, int fd) {
@@ -113,8 +114,7 @@
   void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
   void *cb_arg = ac->cb_arg;
 
-  grpc_alarm_cancel(&ac->alarm);
-
+  gpr_mu_lock(&ac->mu);
   if (success) {
     do {
       so_error_size = sizeof(so_error);
@@ -140,6 +140,7 @@
            opened too many network connections.  The "easy" fix:
            don't do that! */
         gpr_log(GPR_ERROR, "kernel out of buffers");
+        gpr_mu_unlock(&ac->mu);
         grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
         return;
       } else {
@@ -154,6 +155,7 @@
         goto finish;
       }
     } else {
+      grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
       ep = grpc_tcp_create(ac->fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
       goto finish;
     }
@@ -165,28 +167,34 @@
   abort();
 
 finish:
-  gpr_mu_lock(&ac->mu);
-  if (!ep) {
-    grpc_fd_orphan(ac->fd, NULL, NULL);
+  if (ep == NULL) {
+    grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
+    grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
+  } else {
+    ac->fd = NULL;
   }
   done = (--ac->refs == 0);
   gpr_mu_unlock(&ac->mu);
   if (done) {
     gpr_mu_destroy(&ac->mu);
     gpr_free(ac);
+  } else {
+    grpc_alarm_cancel(&ac->alarm);
   }
   cb(cb_arg, ep);
 }
 
 void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
-                             void *arg, const struct sockaddr *addr,
-                             int addr_len, gpr_timespec deadline) {
+                             void *arg, grpc_pollset_set *interested_parties,
+                             const struct sockaddr *addr, int addr_len,
+                             gpr_timespec deadline) {
   int fd;
   grpc_dualstack_mode dsmode;
   int err;
   async_connect *ac;
   struct sockaddr_in6 addr6_v4mapped;
   struct sockaddr_in addr4_copy;
+  grpc_fd *fdobj;
   char *name;
   char *addr_str;
 
@@ -218,31 +226,37 @@
   grpc_sockaddr_to_string(&addr_str, addr, 1);
   gpr_asprintf(&name, "tcp-client:%s", addr_str);
 
+  fdobj = grpc_fd_create(fd, name);
+
   if (err >= 0) {
-    gpr_log(GPR_DEBUG, "instant connect");
-    cb(arg, grpc_tcp_create(grpc_fd_create(fd, name),
-                            GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
+    cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
     goto done;
   }
 
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
     gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
-    close(fd);
+    grpc_fd_orphan(fdobj, NULL, "tcp_client_connect_error");
     cb(arg, NULL);
     goto done;
   }
 
+  grpc_pollset_set_add_fd(interested_parties, fdobj);
+
   ac = gpr_malloc(sizeof(async_connect));
   ac->cb = cb;
   ac->cb_arg = arg;
-  ac->fd = grpc_fd_create(fd, name);
+  ac->fd = fdobj;
+  ac->interested_parties = interested_parties;
   gpr_mu_init(&ac->mu);
   ac->refs = 2;
   ac->write_closure.cb = on_writable;
   ac->write_closure.cb_arg = ac;
 
-  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
+  gpr_mu_lock(&ac->mu);
+  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
+                  gpr_now(GPR_CLOCK_REALTIME));
   grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
+  gpr_mu_unlock(&ac->mu);
 
 done:
   gpr_free(name);
diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c
index 2a040ff..1674145 100644
--- a/src/core/iomgr/tcp_client_windows.c
+++ b/src/core/iomgr/tcp_client_windows.c
@@ -52,7 +52,7 @@
 #include "src/core/iomgr/socket_windows.h"
 
 typedef struct {
-  void(*cb)(void *arg, grpc_endpoint *tcp);
+  void (*cb)(void *arg, grpc_endpoint *tcp);
   void *cb_arg;
   gpr_mu mu;
   grpc_winsocket *socket;
@@ -86,7 +86,7 @@
   SOCKET sock = ac->socket->socket;
   grpc_endpoint *ep = NULL;
   grpc_winsocket_callback_info *info = &ac->socket->write_info;
-  void(*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
+  void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
   void *cb_arg = ac->cb_arg;
   int aborted;
 
@@ -99,8 +99,7 @@
     DWORD transfered_bytes = 0;
     DWORD flags;
     BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
-                                              &transfered_bytes, FALSE,
-                                              &flags);
+                                              &transfered_bytes, FALSE, &flags);
     info->outstanding = 0;
     GPR_ASSERT(transfered_bytes == 0);
     if (!wsa_success) {
@@ -138,9 +137,10 @@
 
 /* Tries to issue one async connection, then schedules both an IOCP
    notification request for the connection, and one timeout alert. */
-void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
-                             void *arg, const struct sockaddr *addr,
-                             int addr_len, gpr_timespec deadline) {
+void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
+                             void *arg, grpc_pollset_set *interested_parties,
+                             const struct sockaddr *addr, int addr_len,
+                             gpr_timespec deadline) {
   SOCKET sock = INVALID_SOCKET;
   BOOL success;
   int status;
@@ -175,9 +175,9 @@
 
   /* Grab the function pointer for ConnectEx for that specific socket.
      It may change depending on the interface. */
-  status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
-                    &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx),
-                    &ioctl_num_bytes, NULL, NULL);
+  status =
+      WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+               &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);
 
   if (status != 0) {
     message = "Unable to retrieve ConnectEx pointer: %s";
@@ -186,8 +186,7 @@
 
   grpc_sockaddr_make_wildcard6(0, &local_address);
 
-  status = bind(sock, (struct sockaddr *) &local_address,
-                sizeof(local_address));
+  status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
   if (status != 0) {
     message = "Unable to bind socket: %s";
     goto failure;
@@ -216,7 +215,8 @@
   ac->refs = 2;
   ac->aborted = 0;
 
-  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
+  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
+                  gpr_now(GPR_CLOCK_REALTIME));
   socket->write_info.outstanding = 1;
   grpc_socket_notify_on_write(socket, on_connect, ac);
   return;
@@ -233,4 +233,4 @@
   cb(arg, NULL);
 }
 
-#endif  /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 2f19f9d..b6d6efc 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -266,7 +266,7 @@
   grpc_endpoint base;
   grpc_fd *em_fd;
   int fd;
-  int iov_size;            /* Number of slices to allocate per read attempt */
+  int iov_size; /* Number of slices to allocate per read attempt */
   int finished_edge;
   size_t slice_size;
   gpr_refcount refcount;
@@ -295,7 +295,7 @@
 static void grpc_tcp_unref(grpc_tcp *tcp) {
   int refcount_zero = gpr_unref(&tcp->refcount);
   if (refcount_zero) {
-    grpc_fd_orphan(tcp->em_fd, NULL, NULL);
+    grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan");
     gpr_free(tcp);
   }
 }
@@ -313,9 +313,7 @@
     size_t i;
     gpr_log(GPR_DEBUG, "read: status=%d", status);
     for (i = 0; i < nslices; i++) {
-      char *dump =
-          gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
-                      GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+      char *dump = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
       gpr_log(GPR_DEBUG, "READ: %s", dump);
       gpr_free(dump);
     }
@@ -412,8 +410,7 @@
       ++tcp->iov_size;
     }
     GPR_ASSERT(slice_state_has_available(&read_state));
-    slice_state_transfer_ownership(&read_state, &final_slices,
-                                   &final_nslices);
+    slice_state_transfer_ownership(&read_state, &final_slices, &final_nslices);
     call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK);
     slice_state_destroy(&read_state);
     grpc_tcp_unref(tcp);
@@ -541,9 +538,7 @@
     size_t i;
 
     for (i = 0; i < nslices; i++) {
-      char *data =
-          gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
-                      GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+      char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
       gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data);
       gpr_free(data);
     }
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index c49f3e1..5854031 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -85,6 +85,7 @@
   } addr;
   int addr_len;
   grpc_iomgr_closure read_closure;
+  grpc_iomgr_closure destroyed_closure;
 } server_port;
 
 static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
@@ -101,13 +102,15 @@
   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;
@@ -116,14 +119,19 @@
   /* 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_tcp_server *grpc_tcp_server_create(void) {
   grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_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);
@@ -136,7 +144,6 @@
   s->shutdown_complete(s->shutdown_complete_arg);
 
   gpr_mu_destroy(&s->mu);
-  gpr_cv_destroy(&s->cv);
 
   gpr_free(s->ports);
   gpr_free(s);
@@ -156,40 +163,60 @@
 
 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_tcp_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, "tcp_listener_shutdown");
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(s);
+  }
+}
+
 void grpc_tcp_server_destroy(
     grpc_tcp_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 */
-  for (i = 0; i < s->nports; i++) {
-    grpc_fd_shutdown(s->ports[i].emfd);
-  }
-  /* wait while that happens */
-  /* TODO(ctiller): make this asynchronous also */
-  while (s->active_ports) {
-    gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
-  }
-
-  /* delete ALL the things */
-  if (s->nports) {
+  if (s->active_ports) {
     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);
-      }
-      grpc_fd_orphan(sp->emfd, destroyed_port, s);
+      grpc_fd_shutdown(s->ports[i].emfd);
     }
     gpr_mu_unlock(&s->mu);
   } else {
     gpr_mu_unlock(&s->mu);
-    finish_shutdown(s);
+    deactivated_all_ports(s);
   }
 }
 
@@ -274,6 +301,8 @@
 /* event manager callback when reads are ready */
 static void on_read(void *arg, int success) {
   server_port *sp = arg;
+  grpc_fd *fdobj;
+  size_t i;
 
   if (!success) {
     goto error;
@@ -306,12 +335,18 @@
     grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
     gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
 
+    fdobj = grpc_fd_create(fd, name);
+    /* TODO(ctiller): revise this when we have server-side sharding
+       of channels -- we certainly should not be automatically adding every
+       incoming channel to every pollset owned by the server */
+    for (i = 0; i < sp->server->pollset_count; i++) {
+      grpc_pollset_add_fd(sp->server->pollsets[i], fdobj);
+    }
     sp->server->cb(sp->server->cb_arg,
-                   grpc_tcp_create(grpc_fd_create(fd, name),
-                                   GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
+                   grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
 
-    gpr_free(addr_str);
     gpr_free(name);
+    gpr_free(addr_str);
   }
 
   abort();
@@ -319,9 +354,11 @@
 error:
   gpr_mu_lock(&sp->server->mu);
   if (0 == --sp->server->active_ports) {
-    gpr_cv_broadcast(&sp->server->cv);
+    gpr_mu_unlock(&sp->server->mu);
+    deactivated_all_ports(sp->server);
+  } else {
+    gpr_mu_unlock(&sp->server->mu);
   }
-  gpr_mu_unlock(&sp->server->mu);
 }
 
 static int add_socket_to_server(grpc_tcp_server *s, int fd,
@@ -452,6 +489,8 @@
   GPR_ASSERT(s->active_ports == 0);
   s->cb = cb;
   s->cb_arg = cb_arg;
+  s->pollsets = pollsets;
+  s->pollset_count = pollset_count;
   for (i = 0; i < s->nports; i++) {
     for (j = 0; j < pollset_count; j++) {
       grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd);
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index d70968d..187009b 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -108,14 +108,15 @@
   size_t i;
   gpr_mu_lock(&s->mu);
   /* First, shutdown all fd's. This will queue abortion calls for all
-     of the pending accepts. */
+     of the pending accepts due to the normal operation mechanism. */
   for (i = 0; i < s->nports; i++) {
     server_port *sp = &s->ports[i];
+    sp->shutting_down = 1;
     grpc_winsocket_shutdown(sp->socket);
   }
   /* This happens asynchronously. Wait while that happens. */
   while (s->active_ports) {
-    gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
+    gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&s->mu);
 
@@ -242,63 +243,52 @@
   SOCKET sock = sp->new_socket;
   grpc_winsocket_callback_info *info = &sp->socket->read_info;
   grpc_endpoint *ep = NULL;
+  DWORD transfered_bytes;
+  DWORD flags;
+  BOOL wsa_success;
 
-  /* The shutdown sequence is done in two parts. This is the second
-     part here, acknowledging the IOCP notification, and doing nothing
-     else, especially not queuing a new accept. */
-  if (sp->shutting_down) {
-    GPR_ASSERT(from_iocp);
-    sp->shutting_down = 0;
-    sp->socket->read_info.outstanding = 0;
-    gpr_mu_lock(&sp->server->mu);
-    if (0 == --sp->server->active_ports) {
-      gpr_cv_broadcast(&sp->server->cv);
-    }
-    gpr_mu_unlock(&sp->server->mu);
-    return;
-  }
+  /* The general mechanism for shutting down is to queue abortion calls. While
+     this is necessary in the read/write case, it's useless for the accept
+     case. Let's do nothing. */
+  if (!from_iocp) return;
 
-  if (from_iocp) {
-    /* The IOCP notified us of a completed operation. Let's grab the results,
-       and act accordingly. */
-    DWORD transfered_bytes = 0;
-    DWORD flags;
-    BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
-                                              &transfered_bytes, FALSE, &flags);
-    if (!wsa_success) {
+  /* The IOCP notified us of a completed operation. Let's grab the results,
+      and act accordingly. */
+  transfered_bytes = 0;
+  wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
+                                            &transfered_bytes, FALSE, &flags);
+  if (!wsa_success) {
+    if (sp->shutting_down) {
+      /* During the shutdown case, we ARE expecting an error. So that's swell,
+         and we can wake up the shutdown thread. */
+      sp->shutting_down = 0;
+      sp->socket->read_info.outstanding = 0;
+      gpr_mu_lock(&sp->server->mu);
+      if (0 == --sp->server->active_ports) {
+        gpr_cv_broadcast(&sp->server->cv);
+      }
+      gpr_mu_unlock(&sp->server->mu);
+      return;
+    } else {
       char *utf8_message = gpr_format_message(WSAGetLastError());
       gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
       gpr_free(utf8_message);
       closesocket(sock);
-    } else {
-	  /* TODO(ctiller): add sockaddr address to label */
-      ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
     }
   } else {
-    /* If we're not notified from the IOCP, it means we are asked to shutdown.
-       This will initiate that shutdown. Calling closesocket will trigger an
-       IOCP notification, that will call this function a second time, from
-       the IOCP thread. Of course, this only works if the socket was, in fact,
-       listening. If that's not the case, we'd wait indefinitely. That's a bit
-       of a degenerate case, but it can happen if you create a server, but
-       don't start it. So let's support that by recursing once. */
-    sp->shutting_down = 1;
-    sp->new_socket = INVALID_SOCKET;
-    if (sock != INVALID_SOCKET) {
-      closesocket(sock);
-    } else {
-      on_accept(sp, 1);
+    if (!sp->shutting_down) {
+      /* TODO(ctiller): add sockaddr address to label */
+      ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
     }
-    return;
   }
 
   /* The only time we should call our callback, is where we successfully
      managed to accept a connection, and created an endpoint. */
   if (ep) sp->server->cb(sp->server->cb_arg, ep);
   /* As we were notified from the IOCP of one and exactly one accept,
-      the former socked we created has now either been destroy or assigned
-      to the new connection. We need to create a new one for the next
-      connection. */
+     the former socked we created has now either been destroy or assigned
+     to the new connection. We need to create a new one for the next
+     connection. */
   start_accept(sp);
 }
 
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 15759c3..1bf81a7 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -148,9 +148,11 @@
   GPR_ASSERT(tcp->socket->read_info.outstanding);
 
   if (socket->read_info.wsa_error != 0) {
-    char *utf8_message = gpr_format_message(info->wsa_error);
-    gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
-    gpr_free(utf8_message);
+    if (socket->read_info.wsa_error != WSAECONNRESET) {
+      char *utf8_message = gpr_format_message(info->wsa_error);
+      gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
+      gpr_free(utf8_message);
+    }
     status = GRPC_ENDPOINT_CB_ERROR;
   } else {
     if (info->bytes_transfered != 0) {
@@ -259,9 +261,11 @@
   GPR_ASSERT(tcp->socket->write_info.outstanding);
 
   if (info->wsa_error != 0) {
-    char *utf8_message = gpr_format_message(info->wsa_error);
-    gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
-    gpr_free(utf8_message);
+    if (info->wsa_error != WSAECONNRESET) {
+      char *utf8_message = gpr_format_message(info->wsa_error);
+      gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
+      gpr_free(utf8_message);
+    }
     status = GRPC_ENDPOINT_CB_ERROR;
   } else {
     GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
@@ -325,9 +329,11 @@
       ret = GRPC_ENDPOINT_WRITE_DONE;
       GPR_ASSERT(bytes_sent == tcp->write_slices.length);
     } else {
-      char *utf8_message = gpr_format_message(info->wsa_error);
-      gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
-      gpr_free(utf8_message);
+      if (socket->read_info.wsa_error != WSAECONNRESET) {
+        char *utf8_message = gpr_format_message(info->wsa_error);
+        gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
+        gpr_free(utf8_message);
+      }
     }
     if (allocated) gpr_free(allocated);
     gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
diff --git a/src/core/json/json.h b/src/core/json/json.h
index 69cbac1..cac18ad 100644
--- a/src/core/json/json.h
+++ b/src/core/json/json.h
@@ -53,14 +53,14 @@
 } grpc_json;
 
 /* The next two functions are going to parse the input string, and
- * destroy it in the process, in order to use its space to store
+ * modify it in the process, in order to use its space to store
  * all of the keys and values for the returned object tree.
  *
  * They assume UTF-8 input stream, and will output UTF-8 encoded
  * strings in the tree. The input stream's UTF-8 isn't validated,
  * as in, what you input is what you get as an output.
  *
- * All the keys and values in the grpc_json_t objects will be strings
+ * All the keys and values in the grpc_json objects will be strings
  * pointing at your input buffer.
  *
  * Delete the allocated tree afterward using grpc_json_destroy().
diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c
index 5ea4e95..c14094c 100644
--- a/src/core/json/json_reader.c
+++ b/src/core/json/json_reader.c
@@ -151,7 +151,7 @@
           case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
           case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = json_reader_set_number(reader);
+            success = (gpr_uint32)json_reader_set_number(reader);
             if (!success) return GRPC_JSON_PARSE_ERROR;
             json_reader_string_clear(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
@@ -177,7 +177,7 @@
           case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
           case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = json_reader_set_number(reader);
+            success = (gpr_uint32)json_reader_set_number(reader);
             if (!success) return GRPC_JSON_PARSE_ERROR;
             json_reader_string_clear(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
@@ -410,8 +410,8 @@
             } else {
               return GRPC_JSON_PARSE_ERROR;
             }
-            reader->unicode_char <<= 4;
-            reader->unicode_char |= c;
+            reader->unicode_char = (gpr_uint16)(reader->unicode_char << 4);
+            reader->unicode_char = (gpr_uint16)(reader->unicode_char | c);
 
             switch (reader->state) {
               case GRPC_JSON_STATE_STRING_ESCAPE_U1:
@@ -438,8 +438,8 @@
                   if (reader->unicode_high_surrogate == 0)
                     return GRPC_JSON_PARSE_ERROR;
                   utf32 = 0x10000;
-                  utf32 += (reader->unicode_high_surrogate - 0xd800) * 0x400;
-                  utf32 += reader->unicode_char - 0xdc00;
+                  utf32 += (gpr_uint32)((reader->unicode_high_surrogate - 0xd800) * 0x400);
+                  utf32 += (gpr_uint32)(reader->unicode_char - 0xdc00);
                   json_reader_string_add_utf32(reader, utf32);
                   reader->unicode_high_surrogate = 0;
                 } else {
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
index 13f8169..03c1099 100644
--- a/src/core/json/json_string.c
+++ b/src/core/json/json_string.c
@@ -83,7 +83,7 @@
   if (state->free_space >= needed) return;
   needed -= state->free_space;
   /* Round up by 256 bytes. */
-  needed = (needed + 0xff) & ~0xff;
+  needed = (needed + 0xff) & ~0xffU;
   state->output = gpr_realloc(state->output, state->allocated + needed);
   state->free_space += needed;
   state->allocated += needed;
@@ -128,7 +128,7 @@
   json_reader_userdata* state = userdata;
   GPR_ASSERT(state->string_ptr < state->input);
   GPR_ASSERT(c <= 0xff);
-  *state->string_ptr++ = (char)c;
+  *state->string_ptr++ = (gpr_uint8)c;
 }
 
 /* We are converting a UTF-32 character into UTF-8 here,
@@ -138,22 +138,22 @@
   if (c <= 0x7f) {
     json_reader_string_add_char(userdata, c);
   } else if (c <= 0x7ff) {
-    int b1 = 0xc0 | ((c >> 6) & 0x1f);
-    int b2 = 0x80 | (c & 0x3f);
+    gpr_uint32 b1 = 0xc0 | ((c >> 6) & 0x1f);
+    gpr_uint32 b2 = 0x80 | (c & 0x3f);
     json_reader_string_add_char(userdata, b1);
     json_reader_string_add_char(userdata, b2);
   } else if (c <= 0xffff) {
-    int b1 = 0xe0 | ((c >> 12) & 0x0f);
-    int b2 = 0x80 | ((c >> 6) & 0x3f);
-    int b3 = 0x80 | (c & 0x3f);
+    gpr_uint32 b1 = 0xe0 | ((c >> 12) & 0x0f);
+    gpr_uint32 b2 = 0x80 | ((c >> 6) & 0x3f);
+    gpr_uint32 b3 = 0x80 | (c & 0x3f);
     json_reader_string_add_char(userdata, b1);
     json_reader_string_add_char(userdata, b2);
     json_reader_string_add_char(userdata, b3);
   } else if (c <= 0x1fffff) {
-    int b1 = 0xf0 | ((c >> 18) & 0x07);
-    int b2 = 0x80 | ((c >> 12) & 0x3f);
-    int b3 = 0x80 | ((c >> 6) & 0x3f);
-    int b4 = 0x80 | (c & 0x3f);
+    gpr_uint32 b1 = 0xf0 | ((c >> 18) & 0x07);
+    gpr_uint32 b2 = 0x80 | ((c >> 12) & 0x3f);
+    gpr_uint32 b3 = 0x80 | ((c >> 6) & 0x3f);
+    gpr_uint32 b4 = 0x80 | (c & 0x3f);
     json_reader_string_add_char(userdata, b1);
     json_reader_string_add_char(userdata, b2);
     json_reader_string_add_char(userdata, b3);
diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c
index a40bf17..bed9a9b 100644
--- a/src/core/json/json_writer.c
+++ b/src/core/json/json_writer.c
@@ -66,7 +66,7 @@
       "                "
       "                ";
 
-  unsigned spaces = writer->depth * writer->indent;
+  unsigned spaces = (unsigned)(writer->depth * writer->indent);
 
   if (writer->indent == 0) return;
 
@@ -78,7 +78,7 @@
   while (spaces >= (sizeof(spacesstr) - 1)) {
     json_writer_output_string_with_len(writer, spacesstr,
                                        sizeof(spacesstr) - 1);
-    spaces -= (sizeof(spacesstr) - 1);
+    spaces -= (unsigned)(sizeof(spacesstr) - 1);
   }
 
   if (spaces == 0) return;
@@ -119,7 +119,7 @@
       break;
     } else if ((c >= 32) && (c <= 126)) {
       if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
-      json_writer_output_char(writer, c);
+      json_writer_output_char(writer, (char)c);
     } else if ((c < 32) || (c == 127)) {
       switch (c) {
         case '\b':
@@ -160,7 +160,7 @@
       }
       for (i = 0; i < extra; i++) {
         utf32 <<= 6;
-        c = *string++;
+        c = (gpr_uint8)(*string++);
         /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
         if ((c & 0xc0) != 0x80) {
           valid = 0;
@@ -193,10 +193,10 @@
          * That range is exactly 20 bits.
          */
         utf32 -= 0x10000;
-        json_writer_escape_utf16(writer, 0xd800 | (utf32 >> 10));
-        json_writer_escape_utf16(writer, 0xdc00 | (utf32 & 0x3ff));
+        json_writer_escape_utf16(writer, (gpr_uint16)(0xd800 | (utf32 >> 10)));
+        json_writer_escape_utf16(writer, (gpr_uint16)(0xdc00 | (utf32 & 0x3ff)));
       } else {
-        json_writer_escape_utf16(writer, utf32);
+        json_writer_escape_utf16(writer, (gpr_uint16)utf32);
       }
     }
   }
diff --git a/src/core/profiling/timers_preciseclock.h b/src/core/profiling/timers_preciseclock.h
index 163d52b..5c251b4 100644
--- a/src/core/profiling/timers_preciseclock.h
+++ b/src/core/profiling/timers_preciseclock.h
@@ -82,7 +82,7 @@
   gpr_timespec clock;
 };
 static void grpc_precise_clock_now(grpc_precise_clock* clk) {
-  clk->clock = gpr_now();
+  clk->clock = gpr_now(GPR_CLOCK_REALTIME);
 }
 #define GRPC_PRECISE_CLOCK_FORMAT "%ld.%09d"
 #define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \
diff --git a/src/core/security/base64.c b/src/core/security/base64.c
index 3b8fea8..8dfaef8 100644
--- a/src/core/security/base64.c
+++ b/src/core/security/base64.c
@@ -120,7 +120,68 @@
 }
 
 gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
-  size_t b64_len = strlen(b64);
+  return grpc_base64_decode_with_len(b64, strlen(b64), url_safe);
+}
+
+static void decode_one_char(const unsigned char *codes, unsigned char *result,
+                            size_t *result_offset) {
+  gpr_uint32 packed = (codes[0] << 2) | (codes[1] >> 4);
+  result[(*result_offset)++] = (unsigned char)packed;
+}
+
+static void decode_two_chars(const unsigned char *codes, unsigned char *result,
+                             size_t *result_offset) {
+  gpr_uint32 packed = (codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2);
+  result[(*result_offset)++] = (unsigned char)(packed >> 8);
+  result[(*result_offset)++] = (unsigned char)(packed);
+}
+
+static int decode_group(const unsigned char *codes, size_t num_codes,
+                        unsigned char *result, size_t *result_offset) {
+  GPR_ASSERT(num_codes <= 4);
+
+  /* Short end groups that may not have padding. */
+  if (num_codes == 1) {
+    gpr_log(GPR_ERROR, "Invalid group. Must be at least 2 bytes.");
+    return 0;
+  }
+  if (num_codes == 2) {
+    decode_one_char(codes, result, result_offset);
+    return 1;
+  }
+  if (num_codes == 3) {
+    decode_two_chars(codes, result, result_offset);
+    return 1;
+  }
+
+  /* Regular 4 byte groups with padding or not. */
+  GPR_ASSERT(num_codes == 4);
+  if (codes[0] == GRPC_BASE64_PAD_BYTE || codes[1] == GRPC_BASE64_PAD_BYTE) {
+    gpr_log(GPR_ERROR, "Invalid padding detected.");
+    return 0;
+  }
+  if (codes[2] == GRPC_BASE64_PAD_BYTE) {
+    if (codes[3] == GRPC_BASE64_PAD_BYTE) {
+      decode_one_char(codes, result, result_offset);
+    } else {
+      gpr_log(GPR_ERROR, "Invalid padding detected.");
+      return 0;
+    }
+  } else if (codes[3] == GRPC_BASE64_PAD_BYTE) {
+    decode_two_chars(codes, result, result_offset);
+  } else {
+    /* No padding. */
+    gpr_uint32 packed =
+        (codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3];
+    result[(*result_offset)++] = (unsigned char)(packed >> 16);
+    result[(*result_offset)++] = (unsigned char)(packed >> 8);
+    result[(*result_offset)++] = (unsigned char)(packed);
+  }
+  return 1;
+}
+
+gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
+                                      int url_safe) {
   gpr_slice result = gpr_slice_malloc(b64_len);
   unsigned char *current = GPR_SLICE_START_PTR(result);
   size_t result_size = 0;
@@ -128,7 +189,7 @@
   size_t num_codes = 0;
 
   while (b64_len--) {
-    unsigned char c = *b64++;
+    unsigned char c = (unsigned char)(*b64++);
     signed char code;
     if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue;
     if (url_safe) {
@@ -149,45 +210,17 @@
         goto fail;
       }
     } else {
-      codes[num_codes++] = code;
+      codes[num_codes++] = (unsigned char)code;
       if (num_codes == 4) {
-        if (codes[0] == GRPC_BASE64_PAD_BYTE ||
-            codes[1] == GRPC_BASE64_PAD_BYTE) {
-          gpr_log(GPR_ERROR, "Invalid padding detected.");
-          goto fail;
-        }
-        if (codes[2] == GRPC_BASE64_PAD_BYTE) {
-          if (codes[3] == GRPC_BASE64_PAD_BYTE) {
-            /* Double padding. */
-            gpr_uint32 packed = (codes[0] << 2) | (codes[1] >> 4);
-            current[result_size++] = (unsigned char)packed;
-          } else {
-            gpr_log(GPR_ERROR, "Invalid padding detected.");
-            goto fail;
-          }
-        } else if (codes[3] == GRPC_BASE64_PAD_BYTE) {
-          /* Single padding. */
-          gpr_uint32 packed =
-              (codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2);
-          current[result_size++] = (unsigned char)(packed >> 8);
-          current[result_size++] = (unsigned char)(packed);
-        } else {
-          /* No padding. */
-          gpr_uint32 packed =
-              (codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3];
-          current[result_size++] = (unsigned char)(packed >> 16);
-          current[result_size++] = (unsigned char)(packed >> 8);
-          current[result_size++] = (unsigned char)(packed);
-        }
+        if (!decode_group(codes, num_codes, current, &result_size)) goto fail;
         num_codes = 0;
       }
     }
   }
 
-  if (num_codes != 0) {
-    gpr_log(GPR_ERROR, "Invalid base64.");
-    gpr_slice_unref(result);
-    return gpr_empty_slice();
+  if (num_codes != 0 &&
+      !decode_group(codes, num_codes, current, &result_size)) {
+    goto fail;
   }
   GPR_SLICE_SET_LENGTH(result, result_size);
   return result;
diff --git a/src/core/security/base64.h b/src/core/security/base64.h
index 6a7cd8e..b9abc07 100644
--- a/src/core/security/base64.h
+++ b/src/core/security/base64.h
@@ -45,4 +45,8 @@
    slice in case of failure. */
 gpr_slice grpc_base64_decode(const char *b64, int url_safe);
 
+/* Same as above except that the length is provided by the caller. */
+gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
+                                      int url_safe);
+
 #endif  /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 0867bd7..9e49a80 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -53,9 +53,15 @@
   grpc_credentials *creds;
   grpc_mdstr *host;
   grpc_mdstr *method;
-  grpc_transport_op op;
+  /* pollset bound to this call; if we need to make external
+     network requests, they should be done under this pollset
+     so that work can progress when this call wants work to
+     progress */
+  grpc_pollset *pollset;
+  grpc_transport_stream_op op;
   size_t op_md_idx;
   int sent_initial_metadata;
+  gpr_uint8 security_context_set;
   grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
 } call_data;
 
@@ -72,7 +78,7 @@
 static void bubble_up_error(grpc_call_element *elem, const char *error_msg) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
-  grpc_transport_op_add_cancellation(
+  grpc_transport_stream_op_add_cancellation(
       &calld->op, GRPC_STATUS_UNAUTHENTICATED,
       grpc_mdstr_from_string(chand->md_ctx, error_msg));
   grpc_call_next_op(elem, &calld->op);
@@ -85,7 +91,7 @@
   grpc_call_element *elem = (grpc_call_element *)user_data;
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
-  grpc_transport_op *op = &calld->op;
+  grpc_transport_stream_op *op = &calld->op;
   grpc_metadata_batch *mdb;
   size_t i;
   if (status != GRPC_CREDENTIALS_OK) {
@@ -126,7 +132,7 @@
 }
 
 static void send_security_metadata(grpc_call_element *elem,
-                                   grpc_transport_op *op) {
+                                   grpc_transport_stream_op *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   grpc_client_security_context *ctx =
@@ -161,8 +167,9 @@
   service_url =
       build_service_url(chand->security_connector->base.url_scheme, calld);
   calld->op = *op; /* Copy op (originates from the caller's stack). */
-  grpc_credentials_get_request_metadata(calld->creds, service_url,
-                                        on_credentials_metadata, elem);
+  GPR_ASSERT(calld->pollset);
+  grpc_credentials_get_request_metadata(
+      calld->creds, calld->pollset, service_url, on_credentials_metadata, elem);
   gpr_free(service_url);
 }
 
@@ -187,14 +194,32 @@
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
 static void auth_start_transport_op(grpc_call_element *elem,
-                                    grpc_transport_op *op) {
+                                    grpc_transport_stream_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   grpc_linked_mdelem *l;
   size_t i;
+  grpc_client_security_context* sec_ctx = NULL;
 
-  /* TODO(jboeuf): write the call auth context. */
+  if (calld->security_context_set == 0) {
+    calld->security_context_set = 1;
+    GPR_ASSERT(op->context);
+    if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
+      op->context[GRPC_CONTEXT_SECURITY].value =
+          grpc_client_security_context_create();
+      op->context[GRPC_CONTEXT_SECURITY].destroy =
+          grpc_client_security_context_destroy;
+    }
+    sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
+    GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
+    sec_ctx->auth_context = GRPC_AUTH_CONTEXT_REF(
+        chand->security_connector->base.auth_context, "client_auth_filter");
+  }
+
+  if (op->bind_pollset) {
+    calld->pollset = op->bind_pollset;
+  }
 
   if (op->send_ops && !calld->sent_initial_metadata) {
     size_t nops = op->send_ops->nops;
@@ -209,11 +234,11 @@
         /* Pointer comparison is OK for md_elems created from the same context.
          */
         if (md->key == chand->authority_string) {
-          if (calld->host != NULL) grpc_mdstr_unref(calld->host);
-          calld->host = grpc_mdstr_ref(md->value);
+          if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
+          calld->host = GRPC_MDSTR_REF(md->value);
         } else if (md->key == chand->path_string) {
-          if (calld->method != NULL) grpc_mdstr_unref(calld->method);
-          calld->method = grpc_mdstr_ref(md->value);
+          if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
+          calld->method = GRPC_MDSTR_REF(md->value);
         }
       }
       if (calld->host != NULL) {
@@ -243,22 +268,17 @@
   grpc_call_next_op(elem, op);
 }
 
-/* Called on special channel events, such as disconnection or new incoming
-   calls on the server */
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  grpc_channel_next_op(elem, op);
-}
-
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   call_data *calld = elem->call_data;
   calld->creds = NULL;
   calld->host = NULL;
   calld->method = NULL;
+  calld->pollset = NULL;
   calld->sent_initial_metadata = 0;
+  calld->security_context_set = 0;
 
   GPR_ASSERT(!initial_op || !initial_op->send_ops);
 }
@@ -268,15 +288,15 @@
   call_data *calld = elem->call_data;
   grpc_credentials_unref(calld->creds);
   if (calld->host != NULL) {
-    grpc_mdstr_unref(calld->host);
+    GRPC_MDSTR_UNREF(calld->host);
   }
   if (calld->method != NULL) {
-    grpc_mdstr_unref(calld->method);
+    GRPC_MDSTR_UNREF(calld->method);
   }
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
                               int is_last) {
@@ -287,22 +307,19 @@
   /* The first and the last filters tend to be implemented differently to
      handle the case that there's no 'next' filter to call on the up or down
      path */
-  GPR_ASSERT(!is_first);
   GPR_ASSERT(!is_last);
   GPR_ASSERT(sc != NULL);
 
   /* initialize members */
   GPR_ASSERT(sc->is_client_side);
   chand->security_connector =
-      (grpc_channel_security_connector *)grpc_security_connector_ref(sc);
+      (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
+          sc, "client_auth_filter");
   chand->md_ctx = metadata_context;
-  chand->authority_string =
-      grpc_mdstr_from_string(chand->md_ctx, ":authority");
+  chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
   chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
-  chand->error_msg_key =
-      grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
-  chand->status_key =
-      grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
+  chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
+  chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
 }
 
 /* Destructor for channel data */
@@ -310,22 +327,23 @@
   /* grab pointers to our data from the channel element */
   channel_data *chand = elem->channel_data;
   grpc_channel_security_connector *ctx = chand->security_connector;
-  if (ctx != NULL) grpc_security_connector_unref(&ctx->base);
+  if (ctx != NULL)
+    GRPC_SECURITY_CONNECTOR_UNREF(&ctx->base, "client_auth_filter");
   if (chand->authority_string != NULL) {
-    grpc_mdstr_unref(chand->authority_string);
+    GRPC_MDSTR_UNREF(chand->authority_string);
   }
   if (chand->error_msg_key != NULL) {
-    grpc_mdstr_unref(chand->error_msg_key);
+    GRPC_MDSTR_UNREF(chand->error_msg_key);
   }
   if (chand->status_key != NULL) {
-    grpc_mdstr_unref(chand->status_key);
+    GRPC_MDSTR_UNREF(chand->status_key);
   }
   if (chand->path_string != NULL) {
-    grpc_mdstr_unref(chand->path_string);
+    GRPC_MDSTR_UNREF(chand->path_string);
   }
 }
 
 const grpc_channel_filter grpc_client_auth_filter = {
-    auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "client-auth"};
+    auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+    init_call_elem,          destroy_call_elem,    sizeof(channel_data),
+    init_channel_elem,       destroy_channel_elem, "client-auth"};
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index f1ae6ce..fb59fa4 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -41,7 +41,6 @@
 #include "src/core/json/json.h"
 #include "src/core/httpcli/httpcli.h"
 #include "src/core/iomgr/iomgr.h"
-#include "src/core/security/json_token.h"
 #include "src/core/support/string.h"
 
 #include <grpc/support/alloc.h>
@@ -52,12 +51,12 @@
 
 /* -- Common. -- */
 
-typedef struct {
+struct grpc_credentials_metadata_request {
   grpc_credentials *creds;
   grpc_credentials_metadata_cb cb;
   grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
   void *user_data;
-} grpc_credentials_metadata_request;
+};
 
 static grpc_credentials_metadata_request *
 grpc_credentials_metadata_request_create(grpc_credentials *creds,
@@ -106,6 +105,7 @@
 }
 
 void grpc_credentials_get_request_metadata(grpc_credentials *creds,
+                                           grpc_pollset *pollset,
                                            const char *service_url,
                                            grpc_credentials_metadata_cb cb,
                                            void *user_data) {
@@ -116,7 +116,8 @@
     }
     return;
   }
-  creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
+  creds->vtable->get_request_metadata(creds, pollset, service_url, cb,
+                                      user_data);
 }
 
 grpc_security_status grpc_credentials_create_security_connector(
@@ -150,16 +151,6 @@
 
 /* -- Ssl credentials. -- */
 
-typedef struct {
-  grpc_credentials base;
-  grpc_ssl_config config;
-} grpc_ssl_credentials;
-
-typedef struct {
-  grpc_server_credentials base;
-  grpc_ssl_server_config config;
-} grpc_ssl_server_credentials;
-
 static void ssl_destroy(grpc_credentials *creds) {
   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
@@ -191,9 +182,7 @@
   gpr_free(creds);
 }
 
-static int ssl_has_request_metadata(const grpc_credentials *creds) {
-  return 0;
-}
+static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
 
 static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
   return 0;
@@ -225,7 +214,7 @@
   arg.type = GRPC_ARG_STRING;
   arg.key = GRPC_ARG_HTTP2_SCHEME;
   arg.value.string = "https";
-  *new_args = grpc_channel_args_copy_and_add(args, &arg);
+  *new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
   return status;
 }
 
@@ -326,22 +315,6 @@
 
 /* -- Jwt credentials -- */
 
-typedef struct {
-  grpc_credentials base;
-
-  /* Have a simple cache for now with just 1 entry. We could have a map based on
-     the service_url for a more sophisticated one. */
-  gpr_mu cache_mu;
-  struct {
-    grpc_credentials_md_store *jwt_md;
-    char *service_url;
-    gpr_timespec jwt_expiration;
-  } cached;
-
-  grpc_auth_json_key key;
-  gpr_timespec jwt_lifetime;
-} grpc_jwt_credentials;
-
 static void jwt_reset_cache(grpc_jwt_credentials *c) {
   if (c->cached.jwt_md != NULL) {
     grpc_credentials_md_store_unref(c->cached.jwt_md);
@@ -351,7 +324,7 @@
     gpr_free(c->cached.service_url);
     c->cached.service_url = NULL;
   }
-  c->cached.jwt_expiration = gpr_inf_past;
+  c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
 }
 
 static void jwt_destroy(grpc_credentials *creds) {
@@ -368,14 +341,14 @@
   return 1;
 }
 
-
 static void jwt_get_request_metadata(grpc_credentials *creds,
+                                     grpc_pollset *pollset,
                                      const char *service_url,
                                      grpc_credentials_metadata_cb cb,
                                      void *user_data) {
   grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
-  gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
-                                    0};
+  gpr_timespec refresh_threshold = gpr_time_from_seconds(
+      GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
 
   /* See if we can return a cached jwt. */
   grpc_credentials_md_store *jwt_md = NULL;
@@ -384,7 +357,8 @@
     if (c->cached.service_url != NULL &&
         strcmp(c->cached.service_url, service_url) == 0 &&
         c->cached.jwt_md != NULL &&
-        (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()),
+        (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
+                                   gpr_now(GPR_CLOCK_REALTIME)),
                       refresh_threshold) > 0)) {
       jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
     }
@@ -401,7 +375,8 @@
       char *md_value;
       gpr_asprintf(&md_value, "Bearer %s", jwt);
       gpr_free(jwt);
-      c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime);
+      c->cached.jwt_expiration =
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
       c->cached.service_url = gpr_strdup(service_url);
       c->cached.jwt_md = grpc_credentials_md_store_create(1);
       grpc_credentials_md_store_add_cstrings(
@@ -424,10 +399,9 @@
     jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
     jwt_get_request_metadata, NULL};
 
-grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
-                                              gpr_timespec token_lifetime) {
+grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
+    grpc_auth_json_key key, gpr_timespec token_lifetime) {
   grpc_jwt_credentials *c;
-  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
   if (!grpc_auth_json_key_is_valid(&key)) {
     gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
     return NULL;
@@ -444,28 +418,20 @@
   return &c->base;
 }
 
+grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
+                                              gpr_timespec token_lifetime) {
+  return grpc_jwt_credentials_create_from_auth_json_key(
+      grpc_auth_json_key_create_from_string(json_key), token_lifetime);
+}
+
 /* -- Oauth2TokenFetcher credentials -- */
 
-/* This object is a base for credentials that need to acquire an oauth2 token
-   from an http service. */
-
-typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
-                                       grpc_httpcli_response_cb response_cb,
-                                       gpr_timespec deadline);
-
-typedef struct {
-  grpc_credentials base;
-  gpr_mu mu;
-  grpc_credentials_md_store *access_token_md;
-  gpr_timespec token_expiration;
-  grpc_fetch_oauth2_func fetch_func;
-} grpc_oauth2_token_fetcher_credentials;
-
 static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
   grpc_credentials_md_store_unref(c->access_token_md);
   gpr_mu_destroy(&c->mu);
+  grpc_httpcli_context_destroy(&c->httpcli_context);
   gpr_free(c);
 }
 
@@ -481,8 +447,8 @@
 
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
-    const grpc_httpcli_response *response,
-    grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) {
+    const grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
+    gpr_timespec *token_lifetime) {
   char *null_terminated_body = NULL;
   char *new_access_token = NULL;
   grpc_credentials_status status = GRPC_CREDENTIALS_OK;
@@ -550,6 +516,7 @@
                  access_token->value);
     token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
     token_lifetime->tv_nsec = 0;
+    token_lifetime->clock_type = GPR_TIMESPAN;
     if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md);
     *token_md = grpc_credentials_md_store_create(1);
     grpc_credentials_md_store_add_cstrings(
@@ -581,11 +548,12 @@
   status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
       response, &c->access_token_md, &token_lifetime);
   if (status == GRPC_CREDENTIALS_OK) {
-    c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
+    c->token_expiration =
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime);
     r->cb(r->user_data, c->access_token_md->entries,
           c->access_token_md->num_entries, status);
   } else {
-    c->token_expiration = gpr_inf_past;
+    c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
     r->cb(r->user_data, NULL, 0, status);
   }
   gpr_mu_unlock(&c->mu);
@@ -593,19 +561,21 @@
 }
 
 static void oauth2_token_fetcher_get_request_metadata(
-    grpc_credentials *creds, const char *service_url,
+    grpc_credentials *creds, grpc_pollset *pollset, const char *service_url,
     grpc_credentials_metadata_cb cb, void *user_data) {
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
-  gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
-                                    0};
+  gpr_timespec refresh_threshold = gpr_time_from_seconds(
+      GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
   grpc_credentials_md_store *cached_access_token_md = NULL;
   {
     gpr_mu_lock(&c->mu);
     if (c->access_token_md != NULL &&
-        (gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
-                      refresh_threshold) > 0)) {
-      cached_access_token_md = grpc_credentials_md_store_ref(c->access_token_md);
+        (gpr_time_cmp(
+             gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)),
+             refresh_threshold) > 0)) {
+      cached_access_token_md =
+          grpc_credentials_md_store_ref(c->access_token_md);
     }
     gpr_mu_unlock(&c->mu);
   }
@@ -616,8 +586,8 @@
   } else {
     c->fetch_func(
         grpc_credentials_metadata_request_create(creds, cb, user_data),
-        on_oauth2_token_fetcher_http_response,
-        gpr_time_add(gpr_now(), refresh_threshold));
+        &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
   }
 }
 
@@ -627,8 +597,9 @@
   c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
   gpr_ref_init(&c->base.refcount, 1);
   gpr_mu_init(&c->mu);
-  c->token_expiration = gpr_inf_past;
+  c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
   c->fetch_func = fetch_func;
+  grpc_httpcli_context_init(&c->httpcli_context);
 }
 
 /* -- ComputeEngine credentials. -- */
@@ -640,6 +611,7 @@
 
 static void compute_engine_fetch_oauth2(
     grpc_credentials_metadata_request *metadata_req,
+    grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
     grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
   grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
   grpc_httpcli_request request;
@@ -648,7 +620,8 @@
   request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
   request.hdr_count = 1;
   request.hdrs = &header;
-  grpc_httpcli_get(&request, deadline, response_cb, metadata_req);
+  grpc_httpcli_get(httpcli_context, pollset, &request, deadline, response_cb,
+                   metadata_req);
 }
 
 grpc_credentials *grpc_compute_engine_credentials_create(void) {
@@ -661,13 +634,6 @@
 
 /* -- ServiceAccount credentials. -- */
 
-typedef struct {
-  grpc_oauth2_token_fetcher_credentials base;
-  grpc_auth_json_key key;
-  char *scope;
-  gpr_timespec token_lifetime;
-} grpc_service_account_credentials;
-
 static void service_account_destroy(grpc_credentials *creds) {
   grpc_service_account_credentials *c =
       (grpc_service_account_credentials *)creds;
@@ -683,6 +649,7 @@
 
 static void service_account_fetch_oauth2(
     grpc_credentials_metadata_request *metadata_req,
+    grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
     grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
   grpc_service_account_credentials *c =
       (grpc_service_account_credentials *)metadata_req->creds;
@@ -708,8 +675,8 @@
   request.hdr_count = 1;
   request.hdrs = &header;
   request.use_ssl = 1;
-  grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
-                    metadata_req);
+  grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
+                    deadline, response_cb, metadata_req);
   gpr_free(body);
   gpr_free(jwt);
 }
@@ -737,14 +704,8 @@
 
 /* -- RefreshToken credentials. -- */
 
-typedef struct {
-  grpc_oauth2_token_fetcher_credentials base;
-  grpc_auth_refresh_token refresh_token;
-} grpc_refresh_token_credentials;
-
 static void refresh_token_destroy(grpc_credentials *creds) {
-  grpc_refresh_token_credentials *c =
-      (grpc_refresh_token_credentials *)creds;
+  grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
   grpc_auth_refresh_token_destruct(&c->refresh_token);
   oauth2_token_fetcher_destroy(&c->base.base);
 }
@@ -756,6 +717,7 @@
 
 static void refresh_token_fetch_oauth2(
     grpc_credentials_metadata_request *metadata_req,
+    grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
     grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
   grpc_refresh_token_credentials *c =
       (grpc_refresh_token_credentials *)metadata_req->creds;
@@ -772,20 +734,16 @@
   request.hdr_count = 1;
   request.hdrs = &header;
   request.use_ssl = 1;
-  grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
-                    metadata_req);
+  grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
+                    deadline, response_cb, metadata_req);
   gpr_free(body);
 }
 
-grpc_credentials *grpc_refresh_token_credentials_create(
-    const char *json_refresh_token) {
+grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+    grpc_auth_refresh_token refresh_token) {
   grpc_refresh_token_credentials *c;
-  grpc_auth_refresh_token refresh_token =
-      grpc_auth_refresh_token_create_from_string(json_refresh_token);
-
   if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
-    gpr_log(GPR_ERROR,
-            "Invalid input for refresh token credentials creation");
+    gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
     return NULL;
   }
   c = gpr_malloc(sizeof(grpc_refresh_token_credentials));
@@ -796,13 +754,13 @@
   return &c->base.base;
 }
 
-/* -- Fake Oauth2 credentials. -- */
+grpc_credentials *grpc_refresh_token_credentials_create(
+    const char *json_refresh_token) {
+  return grpc_refresh_token_credentials_create_from_auth_refresh_token(
+      grpc_auth_refresh_token_create_from_string(json_refresh_token));
+}
 
-typedef struct {
-  grpc_credentials base;
-  grpc_credentials_md_store *access_token_md;
-  int is_async;
-} grpc_fake_oauth2_credentials;
+/* -- Fake Oauth2 credentials. -- */
 
 static void fake_oauth2_destroy(grpc_credentials *creds) {
   grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
@@ -830,6 +788,7 @@
 }
 
 static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
+                                             grpc_pollset *pollset,
                                              const char *service_url,
                                              grpc_credentials_metadata_cb cb,
                                              void *user_data) {
@@ -866,6 +825,54 @@
   return &c->base;
 }
 
+/* -- Oauth2 Access Token credentials. -- */
+
+static void access_token_destroy(grpc_credentials *creds) {
+  grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
+  grpc_credentials_md_store_unref(c->access_token_md);
+  gpr_free(c);
+}
+
+static int access_token_has_request_metadata(const grpc_credentials *creds) {
+  return 1;
+}
+
+static int access_token_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 1;
+}
+
+static void access_token_get_request_metadata(grpc_credentials *creds,
+                                             grpc_pollset *pollset,
+                                             const char *service_url,
+                                             grpc_credentials_metadata_cb cb,
+                                             void *user_data) {
+  grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
+  cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
+}
+
+static grpc_credentials_vtable access_token_vtable = {
+    access_token_destroy, access_token_has_request_metadata,
+    access_token_has_request_metadata_only, access_token_get_request_metadata,
+    NULL};
+
+grpc_credentials *grpc_access_token_credentials_create(
+    const char *access_token) {
+  grpc_access_token_credentials *c =
+      gpr_malloc(sizeof(grpc_access_token_credentials));
+  char *token_md_value;
+  memset(c, 0, sizeof(grpc_access_token_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.vtable = &access_token_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->access_token_md = grpc_credentials_md_store_create(1);
+  gpr_asprintf(&token_md_value, "Bearer %s", access_token);
+  grpc_credentials_md_store_add_cstrings(
+      c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
+  gpr_free(token_md_value);
+  return &c->base;
+}
+
 /* -- Fake transport security credentials. -- */
 
 static void fake_transport_security_credentials_destroy(
@@ -888,8 +895,7 @@
   return 0;
 }
 
-static grpc_security_status
-fake_transport_security_create_security_connector(
+static grpc_security_status fake_transport_security_create_security_connector(
     grpc_credentials *c, const char *target, const grpc_channel_args *args,
     grpc_credentials *request_metadata_creds,
     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
@@ -936,17 +942,12 @@
 /* -- Composite credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
-  grpc_credentials_array inner;
-  grpc_credentials *connector_creds;
-} grpc_composite_credentials;
-
-typedef struct {
   grpc_composite_credentials *composite_creds;
   size_t creds_index;
   grpc_credentials_md_store *md_elems;
   char *service_url;
   void *user_data;
+  grpc_pollset *pollset;
   grpc_credentials_metadata_cb cb;
 } grpc_composite_credentials_metadata_context;
 
@@ -1015,7 +1016,8 @@
     grpc_credentials *inner_creds =
         ctx->composite_creds->inner.creds_array[ctx->creds_index++];
     if (grpc_credentials_has_request_metadata(inner_creds)) {
-      grpc_credentials_get_request_metadata(inner_creds, ctx->service_url,
+      grpc_credentials_get_request_metadata(inner_creds, ctx->pollset,
+                                            ctx->service_url,
                                             composite_metadata_cb, ctx);
       return;
     }
@@ -1028,6 +1030,7 @@
 }
 
 static void composite_get_request_metadata(grpc_credentials *creds,
+                                           grpc_pollset *pollset,
                                            const char *service_url,
                                            grpc_credentials_metadata_cb cb,
                                            void *user_data) {
@@ -1043,11 +1046,12 @@
   ctx->user_data = user_data;
   ctx->cb = cb;
   ctx->composite_creds = c;
+  ctx->pollset = pollset;
   ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
   while (ctx->creds_index < c->inner.num_creds) {
     grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
     if (grpc_credentials_has_request_metadata(inner_creds)) {
-      grpc_credentials_get_request_metadata(inner_creds, service_url,
+      grpc_credentials_get_request_metadata(inner_creds, pollset, service_url,
                                             composite_metadata_cb, ctx);
       return;
     }
@@ -1167,26 +1171,20 @@
 
 /* -- IAM credentials. -- */
 
-typedef struct {
-  grpc_credentials base;
-  grpc_credentials_md_store *iam_md;
-} grpc_iam_credentials;
-
 static void iam_destroy(grpc_credentials *creds) {
   grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
   grpc_credentials_md_store_unref(c->iam_md);
   gpr_free(c);
 }
 
-static int iam_has_request_metadata(const grpc_credentials *creds) {
-  return 1;
-}
+static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
 
 static int iam_has_request_metadata_only(const grpc_credentials *creds) {
   return 1;
 }
 
 static void iam_get_request_metadata(grpc_credentials *creds,
+                                     grpc_pollset *pollset,
                                      const char *service_url,
                                      grpc_credentials_metadata_cb cb,
                                      void *user_data) {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 4768ce6..d988901 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -39,6 +39,8 @@
 #include <grpc/grpc_security.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/httpcli/httpcli.h"
+#include "src/core/security/json_token.h"
 #include "src/core/security/security_connector.h"
 
 struct grpc_httpcli_response;
@@ -108,7 +110,6 @@
     grpc_credentials_md_store *store);
 void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
 
-
 /* --- grpc_credentials. --- */
 
 /* It is the caller's responsibility to gpr_free the result if not NULL. */
@@ -123,7 +124,7 @@
   void (*destroy)(grpc_credentials *c);
   int (*has_request_metadata)(const grpc_credentials *c);
   int (*has_request_metadata_only)(const grpc_credentials *c);
-  void (*get_request_metadata)(grpc_credentials *c,
+  void (*get_request_metadata)(grpc_credentials *c, grpc_pollset *pollset,
                                const char *service_url,
                                grpc_credentials_metadata_cb cb,
                                void *user_data);
@@ -131,7 +132,6 @@
       grpc_credentials *c, const char *target, const grpc_channel_args *args,
       grpc_credentials *request_metadata_creds,
       grpc_channel_security_connector **sc, grpc_channel_args **new_args);
-
 } grpc_credentials_vtable;
 
 struct grpc_credentials {
@@ -145,6 +145,7 @@
 int grpc_credentials_has_request_metadata(grpc_credentials *creds);
 int grpc_credentials_has_request_metadata_only(grpc_credentials *creds);
 void grpc_credentials_get_request_metadata(grpc_credentials *creds,
+                                           grpc_pollset *pollset,
                                            const char *service_url,
                                            grpc_credentials_metadata_cb cb,
                                            void *user_data);
@@ -177,13 +178,24 @@
 /* Exposed for testing only. */
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
-    const struct grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
-    gpr_timespec *token_lifetime);
+    const struct grpc_httpcli_response *response,
+    grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
+void grpc_flush_cached_google_default_credentials(void);
 
 /* Simulates an oauth2 token fetch with the specified value for testing. */
 grpc_credentials *grpc_fake_oauth2_credentials_create(
     const char *token_md_value, int is_async);
 
+/* Private constructor for jwt credentials from an already parsed json key.
+   Takes ownership of the key. */
+grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
+    grpc_auth_json_key key, gpr_timespec token_lifetime);
+
+/* Private constructor for refresh token credentials from an already parsed
+   refresh token. Takes ownership of the refresh token. */
+grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+    grpc_auth_refresh_token token);
+
 /* --- grpc_server_credentials. --- */
 
 typedef struct {
@@ -200,4 +212,103 @@
 grpc_security_status grpc_server_credentials_create_security_connector(
     grpc_server_credentials *creds, grpc_security_connector **sc);
 
-#endif  /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
+/* -- Ssl credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_credentials;
+
+typedef struct {
+  grpc_server_credentials base;
+  grpc_ssl_server_config config;
+} grpc_ssl_server_credentials;
+
+/* -- Jwt credentials -- */
+
+typedef struct {
+  grpc_credentials base;
+
+  /* Have a simple cache for now with just 1 entry. We could have a map based on
+     the service_url for a more sophisticated one. */
+  gpr_mu cache_mu;
+  struct {
+    grpc_credentials_md_store *jwt_md;
+    char *service_url;
+    gpr_timespec jwt_expiration;
+  } cached;
+
+  grpc_auth_json_key key;
+  gpr_timespec jwt_lifetime;
+} grpc_jwt_credentials;
+
+/* -- Oauth2TokenFetcher credentials --
+
+   This object is a base for credentials that need to acquire an oauth2 token
+   from an http service. */
+
+typedef struct grpc_credentials_metadata_request
+    grpc_credentials_metadata_request;
+
+typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
+                                       grpc_httpcli_context *http_context,
+                                       grpc_pollset *pollset,
+                                       grpc_httpcli_response_cb response_cb,
+                                       gpr_timespec deadline);
+
+typedef struct {
+  grpc_credentials base;
+  gpr_mu mu;
+  grpc_credentials_md_store *access_token_md;
+  gpr_timespec token_expiration;
+  grpc_httpcli_context httpcli_context;
+  grpc_fetch_oauth2_func fetch_func;
+} grpc_oauth2_token_fetcher_credentials;
+
+/* -- ServiceAccount credentials. -- */
+
+typedef struct {
+  grpc_oauth2_token_fetcher_credentials base;
+  grpc_auth_json_key key;
+  char *scope;
+  gpr_timespec token_lifetime;
+} grpc_service_account_credentials;
+
+/* -- RefreshToken credentials. -- */
+
+typedef struct {
+  grpc_oauth2_token_fetcher_credentials base;
+  grpc_auth_refresh_token refresh_token;
+} grpc_refresh_token_credentials;
+
+/* -- Oauth2 Access Token credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_md_store *access_token_md;
+} grpc_access_token_credentials;
+
+/* -- Fake Oauth2 credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_md_store *access_token_md;
+  int is_async;
+} grpc_fake_oauth2_credentials;
+
+/* -- IAM credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_md_store *iam_md;
+} grpc_iam_credentials;
+
+/* -- Composite credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_credentials_array inner;
+  grpc_credentials *connector_creds;
+} grpc_composite_credentials;
+
+#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 0e4b9fc..8334843 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -46,7 +46,6 @@
 /* -- Constants. -- */
 
 #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
-#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
 
 /* -- Default credentials. -- */
 
@@ -55,13 +54,10 @@
 static gpr_mu g_mu;
 static gpr_once g_once = GPR_ONCE_INIT;
 
-static void init_default_credentials(void) {
-  gpr_mu_init(&g_mu);
-}
+static void init_default_credentials(void) { gpr_mu_init(&g_mu); }
 
 typedef struct {
-  gpr_cv cv;
-  gpr_mu mu;
+  grpc_pollset pollset;
   int is_done;
   int success;
 } compute_engine_detector;
@@ -82,22 +78,22 @@
       }
     }
   }
-  gpr_mu_lock(&detector->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&detector->pollset));
   detector->is_done = 1;
-  gpr_mu_unlock(&detector->mu);
-  gpr_cv_signal(&detector->cv);
+  grpc_pollset_kick(&detector->pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset));
 }
 
 static int is_stack_running_on_compute_engine(void) {
   compute_engine_detector detector;
   grpc_httpcli_request request;
+  grpc_httpcli_context context;
 
   /* The http call is local. If it takes more than one sec, it is for sure not
      on compute engine. */
-  gpr_timespec max_detection_delay = {1, 0};
+  gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN);
 
-  gpr_mu_init(&detector.mu);
-  gpr_cv_init(&detector.cv);
+  grpc_pollset_init(&detector.pollset);
   detector.is_done = 0;
   detector.success = 0;
 
@@ -105,53 +101,62 @@
   request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST;
   request.path = "/";
 
-  grpc_httpcli_get(&request, gpr_time_add(gpr_now(), max_detection_delay),
-                   on_compute_engine_detection_http_response, &detector);
+  grpc_httpcli_context_init(&context);
+
+  grpc_httpcli_get(
+      &context, &detector.pollset, &request,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
+      on_compute_engine_detection_http_response, &detector);
 
   /* Block until we get the response. This is not ideal but this should only be
      called once for the lifetime of the process by the default credentials. */
-  gpr_mu_lock(&detector.mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&detector.pollset));
   while (!detector.is_done) {
-    gpr_cv_wait(&detector.cv, &detector.mu, gpr_inf_future);
+    grpc_pollset_work(&detector.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
-  gpr_mu_unlock(&detector.mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset));
 
-  gpr_mu_destroy(&detector.mu);
-  gpr_cv_destroy(&detector.cv);
+  grpc_httpcli_context_destroy(&context);
+  grpc_pollset_destroy(&detector.pollset);
+
   return detector.success;
 }
 
 /* Takes ownership of creds_path if not NULL. */
-static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
+static grpc_credentials *create_default_creds_from_path(char *creds_path) {
+  grpc_json *json = NULL;
+  grpc_auth_json_key key;
+  grpc_auth_refresh_token token;
   grpc_credentials *result = NULL;
-  gpr_slice creds_data;
+  gpr_slice creds_data = gpr_empty_slice();
   int file_ok = 0;
-  if (creds_path == NULL) return NULL;
-  creds_data = gpr_load_file(creds_path, 1, &file_ok);
-  gpr_free(creds_path);
-  if (file_ok) {
-    result = grpc_jwt_credentials_create(
-        (const char *)GPR_SLICE_START_PTR(creds_data),
-        grpc_max_auth_token_lifetime);
-    gpr_slice_unref(creds_data);
-  }
-  return result;
-}
+  if (creds_path == NULL) goto end;
+  creds_data = gpr_load_file(creds_path, 0, &file_ok);
+  if (!file_ok) goto end;
+  json = grpc_json_parse_string_with_len(
+      (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data));
+  if (json == NULL) goto end;
 
-/* Takes ownership of creds_path if not NULL. */
-static grpc_credentials *create_refresh_token_creds_from_path(
-    char *creds_path) {
-  grpc_credentials *result = NULL;
-  gpr_slice creds_data;
-  int file_ok = 0;
-  if (creds_path == NULL) return NULL;
-  creds_data = gpr_load_file(creds_path, 1, &file_ok);
-  gpr_free(creds_path);
-  if (file_ok) {
-    result = grpc_refresh_token_credentials_create(
-        (const char *)GPR_SLICE_START_PTR(creds_data));
-    gpr_slice_unref(creds_data);
+  /* First, try an auth json key. */
+  key = grpc_auth_json_key_create_from_json(json);
+  if (grpc_auth_json_key_is_valid(&key)) {
+    result = grpc_jwt_credentials_create_from_auth_json_key(
+        key, grpc_max_auth_token_lifetime);
+    goto end;
   }
+
+  /* Then try a refresh token if the auth json key was invalid. */
+  token = grpc_auth_refresh_token_create_from_json(json);
+  if (grpc_auth_refresh_token_is_valid(&token)) {
+    result =
+        grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
+    goto end;
+  }
+
+end:
+  if (creds_path != NULL) gpr_free(creds_path);
+  gpr_slice_unref(creds_data);
+  if (json != NULL) grpc_json_destroy(json);
   return result;
 }
 
@@ -169,12 +174,12 @@
   }
 
   /* First, try the environment variable. */
-  result =
-      create_jwt_creds_from_path(gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
+  result = create_default_creds_from_path(
+      gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
   if (result != NULL) goto end;
 
   /* Then the well-known file. */
-  result = create_refresh_token_creds_from_path(
+  result = create_default_creds_from_path(
       grpc_get_well_known_google_credentials_file_path());
   if (result != NULL) goto end;
 
@@ -192,11 +197,24 @@
   if (!serving_cached_credentials && result != NULL) {
     /* Blend with default ssl credentials and add a global reference so that it
        can be cached and re-served. */
-    result = grpc_composite_credentials_create(
-        grpc_ssl_credentials_create(NULL, NULL), result);
-    GPR_ASSERT(result != NULL);
-    default_credentials = grpc_credentials_ref(result);
+    grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
+    default_credentials = grpc_credentials_ref(grpc_composite_credentials_create(
+        ssl_creds, result));
+    GPR_ASSERT(default_credentials != NULL);
+    grpc_credentials_unref(ssl_creds);
+    grpc_credentials_unref(result);
+    result = default_credentials;
   }
   gpr_mu_unlock(&g_mu);
   return result;
 }
+
+void grpc_flush_cached_google_default_credentials(void) {
+  gpr_once_init(&g_once, init_default_credentials);
+  gpr_mu_lock(&g_mu);
+  if (default_credentials != NULL) {
+    grpc_credentials_unref(default_credentials);
+    default_credentials = NULL;
+  }
+  gpr_mu_unlock(&g_mu);
+}
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 6116f1d..021912f 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -46,16 +46,10 @@
 #include <openssl/evp.h>
 #include <openssl/pem.h>
 
-#include "src/core/json/json.h"
-
 /* --- Constants. --- */
 
 /* 1 hour max. */
-const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
-
-#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
-#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
-#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
+const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0, GPR_TIMESPAN};
 
 #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
 #define GRPC_JWT_TYPE "JWT"
@@ -66,7 +60,7 @@
 
 /* --- grpc_auth_json_key. --- */
 
-static const char *json_get_string_property(grpc_json *json,
+static const char *json_get_string_property(const grpc_json *json,
                                             const char *prop_name) {
   grpc_json *child;
   for (child = json->child; child != NULL; child = child->next) {
@@ -79,7 +73,8 @@
   return child->value;
 }
 
-static int set_json_key_string_property(grpc_json *json, const char *prop_name,
+static int set_json_key_string_property(const grpc_json *json,
+                                        const char *prop_name,
                                         char **json_key_field) {
   const char *prop_value = json_get_string_property(json, prop_name);
   if (prop_value == NULL) return 0;
@@ -92,11 +87,8 @@
          strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
 }
 
-grpc_auth_json_key grpc_auth_json_key_create_from_string(
-    const char *json_string) {
+grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) {
   grpc_auth_json_key result;
-  char *scratchpad = gpr_strdup(json_string);
-  grpc_json *json = grpc_json_parse_string(scratchpad);
   BIO *bio = NULL;
   const char *prop_value;
   int success = 0;
@@ -104,7 +96,7 @@
   memset(&result, 0, sizeof(grpc_auth_json_key));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
   if (json == NULL) {
-    gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
+    gpr_log(GPR_ERROR, "Invalid json.");
     goto end;
   }
 
@@ -142,8 +134,16 @@
 
 end:
   if (bio != NULL) BIO_free(bio);
-  if (json != NULL) grpc_json_destroy(json);
   if (!success) grpc_auth_json_key_destruct(&result);
+  return result;
+}
+
+grpc_auth_json_key grpc_auth_json_key_create_from_string(
+    const char *json_string) {
+  char *scratchpad = gpr_strdup(json_string);
+  grpc_json *json = grpc_json_parse_string(scratchpad);
+  grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json);
+  if (json != NULL) grpc_json_destroy(json);
   gpr_free(scratchpad);
   return result;
 }
@@ -207,7 +207,7 @@
   grpc_json *child = NULL;
   char *json_str = NULL;
   char *result = NULL;
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec expiration = gpr_time_add(now, token_lifetime);
   char now_str[GPR_LTOA_MIN_BUFSIZE];
   char expiration_str[GPR_LTOA_MIN_BUFSIZE];
@@ -218,8 +218,8 @@
   gpr_ltoa(now.tv_sec, now_str);
   gpr_ltoa(expiration.tv_sec, expiration_str);
 
-  child = create_child(NULL, json, "iss", json_key->client_email,
-                       GRPC_JSON_STRING);
+  child =
+      create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING);
   if (scope != NULL) {
     child = create_child(child, json, "scope", scope, GRPC_JSON_STRING);
   } else {
@@ -342,18 +342,16 @@
          strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
 }
 
-grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
-    const char *json_string) {
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
+    const grpc_json *json) {
   grpc_auth_refresh_token result;
-  char *scratchpad = gpr_strdup(json_string);
-  grpc_json *json = grpc_json_parse_string(scratchpad);
   const char *prop_value;
   int success = 0;
 
   memset(&result, 0, sizeof(grpc_auth_refresh_token));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
   if (json == NULL) {
-    gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
+    gpr_log(GPR_ERROR, "Invalid json.");
     goto end;
   }
 
@@ -374,8 +372,17 @@
   success = 1;
 
 end:
-  if (json != NULL) grpc_json_destroy(json);
   if (!success) grpc_auth_refresh_token_destruct(&result);
+  return result;
+}
+
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
+    const char *json_string) {
+  char *scratchpad = gpr_strdup(json_string);
+  grpc_json *json = grpc_json_parse_string(scratchpad);
+  grpc_auth_refresh_token result =
+      grpc_auth_refresh_token_create_from_json(json);
+  if (json != NULL) grpc_json_destroy(json);
   gpr_free(scratchpad);
   return result;
 }
@@ -396,4 +403,3 @@
     refresh_token->refresh_token = NULL;
   }
 }
-
diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h
index 197796a..091dfef 100644
--- a/src/core/security/json_token.h
+++ b/src/core/security/json_token.h
@@ -37,10 +37,16 @@
 #include <grpc/support/slice.h>
 #include <openssl/rsa.h>
 
+#include "src/core/json/json.h"
+
 /* --- Constants. --- */
 
 #define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token"
 
+#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
+#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
+#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
+
 /* --- auth_json_key parsing. --- */
 
 typedef struct {
@@ -59,6 +65,10 @@
 grpc_auth_json_key grpc_auth_json_key_create_from_string(
     const char *json_string);
 
+/* Creates a json_key object from parsed json. Returns an invalid object if a
+   parsing error has been encountered. */
+grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json);
+
 /* Destructs the object. */
 void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key);
 
@@ -97,6 +107,11 @@
 grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
     const char *json_string);
 
+/* Creates a refresh token object from parsed json. Returns an invalid object if
+   a parsing error has been encountered. */
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
+    const grpc_json *json);
+
 /* Destructs the object. */
 void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
 
diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c
new file mode 100644
index 0000000..1276693
--- /dev/null
+++ b/src/core/security/jwt_verifier.c
@@ -0,0 +1,835 @@
+/*
+ *
+ * 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 disclaimser.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimser
+ * 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/security/jwt_verifier.h"
+
+#include <string.h>
+
+#include "src/core/httpcli/httpcli.h"
+#include "src/core/security/base64.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <openssl/pem.h>
+
+/* --- Utils. --- */
+
+const char *grpc_jwt_verifier_status_to_string(
+    grpc_jwt_verifier_status status) {
+  switch (status) {
+    case GRPC_JWT_VERIFIER_OK:
+      return "OK";
+    case GRPC_JWT_VERIFIER_BAD_SIGNATURE:
+      return "BAD_SIGNATURE";
+    case GRPC_JWT_VERIFIER_BAD_FORMAT:
+      return "BAD_FORMAT";
+    case GRPC_JWT_VERIFIER_BAD_AUDIENCE:
+      return "BAD_AUDIENCE";
+    case GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR:
+      return "KEY_RETRIEVAL_ERROR";
+    case GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE:
+      return "TIME_CONSTRAINT_FAILURE";
+    case GRPC_JWT_VERIFIER_GENERIC_ERROR:
+      return "GENERIC_ERROR";
+    default:
+      return "UNKNOWN";
+  }
+}
+
+static const EVP_MD *evp_md_from_alg(const char *alg) {
+  if (strcmp(alg, "RS256") == 0) {
+    return EVP_sha256();
+  } else if (strcmp(alg, "RS384") == 0) {
+    return EVP_sha384();
+  } else if (strcmp(alg, "RS512") == 0) {
+    return EVP_sha512();
+  } else {
+    return NULL;
+  }
+}
+
+static grpc_json *parse_json_part_from_jwt(const char *str, size_t len,
+                                           gpr_slice *buffer) {
+  grpc_json *json;
+
+  *buffer = grpc_base64_decode_with_len(str, len, 1);
+  if (GPR_SLICE_IS_EMPTY(*buffer)) {
+    gpr_log(GPR_ERROR, "Invalid base64.");
+    return NULL;
+  }
+  json = grpc_json_parse_string_with_len((char *)GPR_SLICE_START_PTR(*buffer),
+                                         GPR_SLICE_LENGTH(*buffer));
+  if (json == NULL) {
+    gpr_slice_unref(*buffer);
+    gpr_log(GPR_ERROR, "JSON parsing error.");
+  }
+  return json;
+}
+
+static const char *validate_string_field(const grpc_json *json,
+                                         const char *key) {
+  if (json->type != GRPC_JSON_STRING) {
+    gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value);
+    return NULL;
+  }
+  return json->value;
+}
+
+static gpr_timespec validate_time_field(const grpc_json *json,
+                                        const char *key) {
+  gpr_timespec result = gpr_time_0(GPR_CLOCK_REALTIME);
+  if (json->type != GRPC_JSON_NUMBER) {
+    gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value);
+    return result;
+  }
+  result.tv_sec = strtol(json->value, NULL, 10);
+  return result;
+}
+
+/* --- JOSE header. see http://tools.ietf.org/html/rfc7515#section-4 --- */
+
+typedef struct {
+  const char *alg;
+  const char *kid;
+  const char *typ;
+  /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */
+  gpr_slice buffer;
+} jose_header;
+
+static void jose_header_destroy(jose_header *h) {
+  gpr_slice_unref(h->buffer);
+  gpr_free(h);
+}
+
+/* Takes ownership of json and buffer. */
+static jose_header *jose_header_from_json(grpc_json *json, gpr_slice buffer) {
+  grpc_json *cur;
+  jose_header *h = gpr_malloc(sizeof(jose_header));
+  memset(h, 0, sizeof(jose_header));
+  h->buffer = buffer;
+  for (cur = json->child; cur != NULL; cur = cur->next) {
+    if (strcmp(cur->key, "alg") == 0) {
+      /* We only support RSA-1.5 signatures for now.
+         Beware of this if we add HMAC support:
+         https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
+      */
+      if (cur->type != GRPC_JSON_STRING || strncmp(cur->value, "RS", 2) ||
+          evp_md_from_alg(cur->value) == NULL) {
+        gpr_log(GPR_ERROR, "Invalid alg field [%s]", cur->value);
+        goto error;
+      }
+      h->alg = cur->value;
+    } else if (strcmp(cur->key, "typ") == 0) {
+      h->typ = validate_string_field(cur, "typ");
+      if (h->typ == NULL) goto error;
+    } else if (strcmp(cur->key, "kid") == 0) {
+      h->kid = validate_string_field(cur, "kid");
+      if (h->kid == NULL) goto error;
+    }
+  }
+  if (h->alg == NULL) {
+    gpr_log(GPR_ERROR, "Missing alg field.");
+    goto error;
+  }
+  grpc_json_destroy(json);
+  h->buffer = buffer;
+  return h;
+
+error:
+  grpc_json_destroy(json);
+  jose_header_destroy(h);
+  return NULL;
+}
+
+/* --- JWT claims. see http://tools.ietf.org/html/rfc7519#section-4.1 */
+
+struct grpc_jwt_claims {
+  /* Well known properties already parsed. */
+  const char *sub;
+  const char *iss;
+  const char *aud;
+  const char *jti;
+  gpr_timespec iat;
+  gpr_timespec exp;
+  gpr_timespec nbf;
+
+  grpc_json *json;
+  gpr_slice buffer;
+};
+
+void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) {
+  grpc_json_destroy(claims->json);
+  gpr_slice_unref(claims->buffer);
+  gpr_free(claims);
+}
+
+const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return NULL;
+  return claims->json;
+}
+
+const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return NULL;
+  return claims->sub;
+}
+
+const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return NULL;
+  return claims->iss;
+}
+
+const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return NULL;
+  return claims->jti;
+}
+
+const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return NULL;
+  return claims->aud;
+}
+
+gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME);
+  return claims->iat;
+}
+
+gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return gpr_inf_future(GPR_CLOCK_REALTIME);
+  return claims->exp;
+}
+
+gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) {
+  if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME);
+  return claims->nbf;
+}
+
+/* Takes ownership of json and buffer even in case of failure. */
+grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) {
+  grpc_json *cur;
+  grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims));
+  memset(claims, 0, sizeof(grpc_jwt_claims));
+  claims->json = json;
+  claims->buffer = buffer;
+  claims->iat = gpr_inf_past(GPR_CLOCK_REALTIME);
+  claims->nbf = gpr_inf_past(GPR_CLOCK_REALTIME);
+  claims->exp = gpr_inf_future(GPR_CLOCK_REALTIME);
+
+  /* Per the spec, all fields are optional. */
+  for (cur = json->child; cur != NULL; cur = cur->next) {
+    if (strcmp(cur->key, "sub") == 0) {
+      claims->sub = validate_string_field(cur, "sub");
+      if (claims->sub == NULL) goto error;
+    } else if (strcmp(cur->key, "iss") == 0) {
+      claims->iss = validate_string_field(cur, "iss");
+      if (claims->iss == NULL) goto error;
+    } else if (strcmp(cur->key, "aud") == 0) {
+      claims->aud = validate_string_field(cur, "aud");
+      if (claims->aud == NULL) goto error;
+    } else if (strcmp(cur->key, "jti") == 0) {
+      claims->jti = validate_string_field(cur, "jti");
+      if (claims->jti == NULL) goto error;
+    } else if (strcmp(cur->key, "iat") == 0) {
+      claims->iat = validate_time_field(cur, "iat");
+      if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0)
+        goto error;
+    } else if (strcmp(cur->key, "exp") == 0) {
+      claims->exp = validate_time_field(cur, "exp");
+      if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0)
+        goto error;
+    } else if (strcmp(cur->key, "nbf") == 0) {
+      claims->nbf = validate_time_field(cur, "nbf");
+      if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0)
+        goto error;
+    }
+  }
+  return claims;
+
+error:
+  grpc_jwt_claims_destroy(claims);
+  return NULL;
+}
+
+grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
+                                               const char *audience) {
+  gpr_timespec skewed_now;
+  int audience_ok;
+
+  GPR_ASSERT(claims != NULL);
+
+  skewed_now =
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew);
+  if (gpr_time_cmp(skewed_now, claims->nbf) < 0) {
+    gpr_log(GPR_ERROR, "JWT is not valid yet.");
+    return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
+  }
+  skewed_now =
+      gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew);
+  if (gpr_time_cmp(skewed_now, claims->exp) > 0) {
+    gpr_log(GPR_ERROR, "JWT is expired.");
+    return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
+  }
+
+  if (audience == NULL) {
+    audience_ok = claims->aud == NULL;
+  } else {
+    audience_ok = claims->aud != NULL && strcmp(audience, claims->aud) == 0;
+  }
+  if (!audience_ok) {
+    gpr_log(GPR_ERROR, "Audience mismatch: expected %s and found %s.",
+            audience == NULL ? "NULL" : audience,
+            claims->aud == NULL ? "NULL" : claims->aud);
+    return GRPC_JWT_VERIFIER_BAD_AUDIENCE;
+  }
+  return GRPC_JWT_VERIFIER_OK;
+}
+
+/* --- verifier_cb_ctx object. --- */
+
+typedef struct {
+  grpc_jwt_verifier *verifier;
+  grpc_pollset *pollset;
+  jose_header *header;
+  grpc_jwt_claims *claims;
+  char *audience;
+  gpr_slice signature;
+  gpr_slice signed_data;
+  void *user_data;
+  grpc_jwt_verification_done_cb user_cb;
+} verifier_cb_ctx;
+
+/* Takes ownership of the header, claims and signature. */
+static verifier_cb_ctx *verifier_cb_ctx_create(
+    grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header,
+    grpc_jwt_claims *claims, const char *audience, gpr_slice signature,
+    const char *signed_jwt, size_t signed_jwt_len, void *user_data,
+    grpc_jwt_verification_done_cb cb) {
+  verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx));
+  memset(ctx, 0, sizeof(verifier_cb_ctx));
+  ctx->verifier = verifier;
+  ctx->pollset = pollset;
+  ctx->header = header;
+  ctx->audience = gpr_strdup(audience);
+  ctx->claims = claims;
+  ctx->signature = signature;
+  ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len);
+  ctx->user_data = user_data;
+  ctx->user_cb = cb;
+  return ctx;
+}
+
+void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) {
+  if (ctx->audience != NULL) gpr_free(ctx->audience);
+  if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims);
+  gpr_slice_unref(ctx->signature);
+  gpr_slice_unref(ctx->signed_data);
+  jose_header_destroy(ctx->header);
+  /* TODO: see what to do with claims... */
+  gpr_free(ctx);
+}
+
+/* --- grpc_jwt_verifier object. --- */
+
+/* Clock skew defaults to one minute. */
+gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN};
+
+/* Max delay defaults to one minute. */
+gpr_timespec grpc_jwt_verifier_max_delay = {60, 0, GPR_TIMESPAN};
+
+typedef struct {
+  char *email_domain;
+  char *key_url_prefix;
+} email_key_mapping;
+
+struct grpc_jwt_verifier {
+  email_key_mapping *mappings;
+  size_t num_mappings; /* Should be very few, linear search ok. */
+  size_t allocated_mappings;
+  grpc_httpcli_context http_ctx;
+};
+
+static grpc_json *json_from_http(const grpc_httpcli_response *response) {
+  grpc_json *json = NULL;
+
+  if (response == NULL) {
+    gpr_log(GPR_ERROR, "HTTP response is NULL.");
+    return NULL;
+  }
+  if (response->status != 200) {
+    gpr_log(GPR_ERROR, "Call to http server failed with error %d.",
+            response->status);
+    return NULL;
+  }
+
+  json = grpc_json_parse_string_with_len(response->body, response->body_length);
+  if (json == NULL) {
+    gpr_log(GPR_ERROR, "Invalid JSON found in response.");
+  }
+  return json;
+}
+
+static const grpc_json *find_property_by_name(const grpc_json *json,
+                                              const char *name) {
+  const grpc_json *cur;
+  for (cur = json->child; cur != NULL; cur = cur->next) {
+    if (strcmp(cur->key, name) == 0) return cur;
+  }
+  return NULL;
+}
+
+static EVP_PKEY *extract_pkey_from_x509(const char *x509_str) {
+  X509 *x509 = NULL;
+  EVP_PKEY *result = NULL;
+  BIO *bio = BIO_new(BIO_s_mem());
+  BIO_write(bio, x509_str, strlen(x509_str));
+  x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+  if (x509 == NULL) {
+    gpr_log(GPR_ERROR, "Unable to parse x509 cert.");
+    goto end;
+  }
+  result = X509_get_pubkey(x509);
+  if (result == NULL) {
+    gpr_log(GPR_ERROR, "Cannot find public key in X509 cert.");
+  }
+
+end:
+  BIO_free(bio);
+  if (x509 != NULL) X509_free(x509);
+  return result;
+}
+
+static BIGNUM *bignum_from_base64(const char *b64) {
+  BIGNUM *result = NULL;
+  gpr_slice bin;
+
+  if (b64 == NULL) return NULL;
+  bin = grpc_base64_decode(b64, 1);
+  if (GPR_SLICE_IS_EMPTY(bin)) {
+    gpr_log(GPR_ERROR, "Invalid base64 for big num.");
+    return NULL;
+  }
+  result = BN_bin2bn(GPR_SLICE_START_PTR(bin), GPR_SLICE_LENGTH(bin), NULL);
+  gpr_slice_unref(bin);
+  return result;
+}
+
+static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) {
+  const grpc_json *key_prop;
+  RSA *rsa = NULL;
+  EVP_PKEY *result = NULL;
+
+  GPR_ASSERT(kty != NULL && json != NULL);
+  if (strcmp(kty, "RSA") != 0) {
+    gpr_log(GPR_ERROR, "Unsupported key type %s.", kty);
+    goto end;
+  }
+  rsa = RSA_new();
+  if (rsa == NULL) {
+    gpr_log(GPR_ERROR, "Could not create rsa key.");
+    goto end;
+  }
+  for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) {
+    if (strcmp(key_prop->key, "n") == 0) {
+      rsa->n = bignum_from_base64(validate_string_field(key_prop, "n"));
+      if (rsa->n == NULL) goto end;
+    } else if (strcmp(key_prop->key, "e") == 0) {
+      rsa->e = bignum_from_base64(validate_string_field(key_prop, "e"));
+      if (rsa->e == NULL) goto end;
+    }
+  }
+  if (rsa->e == NULL || rsa->n == NULL) {
+    gpr_log(GPR_ERROR, "Missing RSA public key field.");
+    goto end;
+  }
+  result = EVP_PKEY_new();
+  EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */
+
+end:
+  if (rsa != NULL) RSA_free(rsa);
+  return result;
+}
+
+static EVP_PKEY *find_verification_key(const grpc_json *json,
+                                       const char *header_alg,
+                                       const char *header_kid) {
+  const grpc_json *jkey;
+  const grpc_json *jwk_keys;
+  /* Try to parse the json as a JWK set:
+     https://tools.ietf.org/html/rfc7517#section-5. */
+  jwk_keys = find_property_by_name(json, "keys");
+  if (jwk_keys == NULL) {
+    /* Use the google proprietary format which is:
+      { <kid1>: <x5091>, <kid2>: <x5092>, ... } */
+    const grpc_json *cur = find_property_by_name(json, header_kid);
+    if (cur == NULL) return NULL;
+    return extract_pkey_from_x509(cur->value);
+  }
+
+  if (jwk_keys->type != GRPC_JSON_ARRAY) {
+    gpr_log(GPR_ERROR,
+            "Unexpected value type of keys property in jwks key set.");
+    return NULL;
+  }
+  /* Key format is specified in:
+     https://tools.ietf.org/html/rfc7518#section-6. */
+  for (jkey = jwk_keys->child; jkey != NULL; jkey = jkey->next) {
+    grpc_json *key_prop;
+    const char *alg = NULL;
+    const char *kid = NULL;
+    const char *kty = NULL;
+
+    if (jkey->type != GRPC_JSON_OBJECT) continue;
+    for (key_prop = jkey->child; key_prop != NULL; key_prop = key_prop->next) {
+      if (strcmp(key_prop->key, "alg") == 0 &&
+          key_prop->type == GRPC_JSON_STRING) {
+        alg = key_prop->value;
+      } else if (strcmp(key_prop->key, "kid") == 0 &&
+                 key_prop->type == GRPC_JSON_STRING) {
+        kid = key_prop->value;
+      } else if (strcmp(key_prop->key, "kty") == 0 &&
+                 key_prop->type == GRPC_JSON_STRING) {
+        kty = key_prop->value;
+      }
+    }
+    if (alg != NULL && kid != NULL && kty != NULL &&
+        strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) {
+      return pkey_from_jwk(jkey, kty);
+    }
+  }
+  gpr_log(GPR_ERROR,
+          "Could not find matching key in key set for kid=%s and alg=%s",
+          header_kid, header_alg);
+  return NULL;
+}
+
+static int verify_jwt_signature(EVP_PKEY *key, const char *alg,
+                                gpr_slice signature, gpr_slice signed_data) {
+  EVP_MD_CTX *md_ctx = EVP_MD_CTX_create();
+  const EVP_MD *md = evp_md_from_alg(alg);
+  int result = 0;
+
+  GPR_ASSERT(md != NULL); /* Checked before. */
+  if (md_ctx == NULL) {
+    gpr_log(GPR_ERROR, "Could not create EVP_MD_CTX.");
+    goto end;
+  }
+  if (EVP_DigestVerifyInit(md_ctx, NULL, md, NULL, key) != 1) {
+    gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed.");
+    goto end;
+  }
+  if (EVP_DigestVerifyUpdate(md_ctx, GPR_SLICE_START_PTR(signed_data),
+                             GPR_SLICE_LENGTH(signed_data)) != 1) {
+    gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed.");
+    goto end;
+  }
+  if (EVP_DigestVerifyFinal(md_ctx, GPR_SLICE_START_PTR(signature),
+                            GPR_SLICE_LENGTH(signature)) != 1) {
+    gpr_log(GPR_ERROR, "JWT signature verification failed.");
+    goto end;
+  }
+  result = 1;
+
+end:
+  if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
+  return result;
+}
+
+static void on_keys_retrieved(void *user_data,
+                              const grpc_httpcli_response *response) {
+  grpc_json *json = json_from_http(response);
+  verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data;
+  EVP_PKEY *verification_key = NULL;
+  grpc_jwt_verifier_status status = GRPC_JWT_VERIFIER_GENERIC_ERROR;
+  grpc_jwt_claims *claims = NULL;
+
+  if (json == NULL) {
+    status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR;
+    goto end;
+  }
+  verification_key =
+      find_verification_key(json, ctx->header->alg, ctx->header->kid);
+  if (verification_key == NULL) {
+    gpr_log(GPR_ERROR, "Could not find verification key with kid %s.",
+            ctx->header->kid);
+    status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR;
+    goto end;
+  }
+
+  if (!verify_jwt_signature(verification_key, ctx->header->alg, ctx->signature,
+                            ctx->signed_data)) {
+    status = GRPC_JWT_VERIFIER_BAD_SIGNATURE;
+    goto end;
+  }
+
+  status = grpc_jwt_claims_check(ctx->claims, ctx->audience);
+  if (status == GRPC_JWT_VERIFIER_OK) {
+    /* Pass ownership. */
+    claims = ctx->claims;
+    ctx->claims = NULL;
+  }
+
+end:
+  if (json != NULL) grpc_json_destroy(json);
+  if (verification_key != NULL) EVP_PKEY_free(verification_key);
+  ctx->user_cb(ctx->user_data, status, claims);
+  verifier_cb_ctx_destroy(ctx);
+}
+
+static void on_openid_config_retrieved(void *user_data,
+                                       const grpc_httpcli_response *response) {
+  const grpc_json *cur;
+  grpc_json *json = json_from_http(response);
+  verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data;
+  grpc_httpcli_request req;
+  const char *jwks_uri;
+
+  /* TODO(jboeuf): Cache the jwks_uri in order to avoid this hop next time.*/
+  if (json == NULL) goto error;
+  cur = find_property_by_name(json, "jwks_uri");
+  if (cur == NULL) {
+    gpr_log(GPR_ERROR, "Could not find jwks_uri in openid config.");
+    goto error;
+  }
+  jwks_uri = validate_string_field(cur, "jwks_uri");
+  if (jwks_uri == NULL) goto error;
+  if (strstr(jwks_uri, "https://") != jwks_uri) {
+    gpr_log(GPR_ERROR, "Invalid non https jwks_uri: %s.", jwks_uri);
+    goto error;
+  }
+  jwks_uri += 8;
+  req.use_ssl = 1;
+  req.host = gpr_strdup(jwks_uri);
+  req.path = strchr(jwks_uri, '/');
+  if (req.path == NULL) {
+    req.path = "";
+  } else {
+    *(req.host + (req.path - jwks_uri)) = '\0';
+  }
+  grpc_httpcli_get(
+      &ctx->verifier->http_ctx, ctx->pollset, &req,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
+      on_keys_retrieved, ctx);
+  grpc_json_destroy(json);
+  gpr_free(req.host);
+  return;
+
+error:
+  if (json != NULL) grpc_json_destroy(json);
+  ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL);
+  verifier_cb_ctx_destroy(ctx);
+}
+
+static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v,
+                                               const char *email_domain) {
+  size_t i;
+  if (v->mappings == NULL) return NULL;
+  for (i = 0; i < v->num_mappings; i++) {
+    if (strcmp(email_domain, v->mappings[i].email_domain) == 0) {
+      return &v->mappings[i];
+    }
+  }
+  return NULL;
+}
+
+static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain,
+                                 const char *key_url_prefix) {
+  email_key_mapping *mapping = verifier_get_mapping(v, email_domain);
+  GPR_ASSERT(v->num_mappings < v->allocated_mappings);
+  if (mapping != NULL) {
+    gpr_free(mapping->key_url_prefix);
+    mapping->key_url_prefix = gpr_strdup(key_url_prefix);
+    return;
+  }
+  v->mappings[v->num_mappings].email_domain = gpr_strdup(email_domain);
+  v->mappings[v->num_mappings].key_url_prefix = gpr_strdup(key_url_prefix);
+  v->num_mappings++;
+  GPR_ASSERT(v->num_mappings <= v->allocated_mappings);
+}
+
+/* Takes ownership of ctx. */
+static void retrieve_key_and_verify(verifier_cb_ctx *ctx) {
+  const char *at_sign;
+  grpc_httpcli_response_cb http_cb;
+  char *path_prefix = NULL;
+  const char *iss;
+  grpc_httpcli_request req;
+  memset(&req, 0, sizeof(grpc_httpcli_request));
+  req.use_ssl = 1;
+
+  GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL);
+  iss = ctx->claims->iss;
+  if (ctx->header->kid == NULL) {
+    gpr_log(GPR_ERROR, "Missing kid in jose header.");
+    goto error;
+  }
+  if (iss == NULL) {
+    gpr_log(GPR_ERROR, "Missing iss in claims.");
+    goto error;
+  }
+
+  /* This code relies on:
+     https://openid.net/specs/openid-connect-discovery-1_0.html
+     Nobody seems to implement the account/email/webfinger part 2. of the spec
+     so we will rely instead on email/url mappings if we detect such an issuer.
+     Part 4, on the other hand is implemented by both google and salesforce. */
+
+  /* Very non-sophisticated way to detect an email address. Should be good
+     enough for now... */
+  at_sign = strchr(iss, '@');
+  if (at_sign != NULL) {
+    email_key_mapping *mapping;
+    const char *email_domain = at_sign + 1;
+    GPR_ASSERT(ctx->verifier != NULL);
+    mapping = verifier_get_mapping(ctx->verifier, email_domain);
+    if (mapping == NULL) {
+      gpr_log(GPR_ERROR, "Missing mapping for issuer email.");
+      goto error;
+    }
+    req.host = gpr_strdup(mapping->key_url_prefix);
+    path_prefix = strchr(req.host, '/');
+    if (path_prefix == NULL) {
+      gpr_asprintf(&req.path, "/%s", iss);
+    } else {
+      *(path_prefix++) = '\0';
+      gpr_asprintf(&req.path, "/%s/%s", path_prefix, iss);
+    }
+    http_cb = on_keys_retrieved;
+  } else {
+    req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss);
+    path_prefix = strchr(req.host, '/');
+    if (path_prefix == NULL) {
+      req.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX);
+    } else {
+      *(path_prefix++) = 0;
+      gpr_asprintf(&req.path, "/%s%s", path_prefix,
+                   GRPC_OPENID_CONFIG_URL_SUFFIX);
+    }
+    http_cb = on_openid_config_retrieved;
+  }
+
+  grpc_httpcli_get(
+      &ctx->verifier->http_ctx, ctx->pollset, &req,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
+      http_cb, ctx);
+  gpr_free(req.host);
+  gpr_free(req.path);
+  return;
+
+error:
+  ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL);
+  verifier_cb_ctx_destroy(ctx);
+}
+
+void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier,
+                              grpc_pollset *pollset, const char *jwt,
+                              const char *audience,
+                              grpc_jwt_verification_done_cb cb,
+                              void *user_data) {
+  const char *dot = NULL;
+  grpc_json *json;
+  jose_header *header = NULL;
+  grpc_jwt_claims *claims = NULL;
+  gpr_slice header_buffer;
+  gpr_slice claims_buffer;
+  gpr_slice signature;
+  size_t signed_jwt_len;
+  const char *cur = jwt;
+
+  GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL);
+  dot = strchr(cur, '.');
+  if (dot == NULL) goto error;
+  json = parse_json_part_from_jwt(cur, dot - cur, &header_buffer);
+  if (json == NULL) goto error;
+  header = jose_header_from_json(json, header_buffer);
+  if (header == NULL) goto error;
+
+  cur = dot + 1;
+  dot = strchr(cur, '.');
+  if (dot == NULL) goto error;
+  json = parse_json_part_from_jwt(cur, dot - cur, &claims_buffer);
+  if (json == NULL) goto error;
+  claims = grpc_jwt_claims_from_json(json, claims_buffer);
+  if (claims == NULL) goto error;
+
+  signed_jwt_len = (size_t)(dot - jwt);
+  cur = dot + 1;
+  signature = grpc_base64_decode(cur, 1);
+  if (GPR_SLICE_IS_EMPTY(signature)) goto error;
+  retrieve_key_and_verify(
+      verifier_cb_ctx_create(verifier, pollset, header, claims, audience,
+                             signature, jwt, signed_jwt_len, user_data, cb));
+  return;
+
+error:
+  if (header != NULL) jose_header_destroy(header);
+  if (claims != NULL) grpc_jwt_claims_destroy(claims);
+  cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL);
+}
+
+grpc_jwt_verifier *grpc_jwt_verifier_create(
+    const grpc_jwt_verifier_email_domain_key_url_mapping *mappings,
+    size_t num_mappings) {
+  grpc_jwt_verifier *v = gpr_malloc(sizeof(grpc_jwt_verifier));
+  memset(v, 0, sizeof(grpc_jwt_verifier));
+  grpc_httpcli_context_init(&v->http_ctx);
+
+  /* We know at least of one mapping. */
+  v->allocated_mappings = 1 + num_mappings;
+  v->mappings = gpr_malloc(v->allocated_mappings * sizeof(email_key_mapping));
+  verifier_put_mapping(v, GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN,
+                       GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX);
+  /* User-Provided mappings. */
+  if (mappings != NULL) {
+    size_t i;
+    for (i = 0; i < num_mappings; i++) {
+      verifier_put_mapping(v, mappings[i].email_domain,
+                           mappings[i].key_url_prefix);
+    }
+  }
+  return v;
+}
+
+void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v) {
+  size_t i;
+  if (v == NULL) return;
+  grpc_httpcli_context_destroy(&v->http_ctx);
+  if (v->mappings != NULL) {
+    for (i = 0; i < v->num_mappings; i++) {
+      gpr_free(v->mappings[i].email_domain);
+      gpr_free(v->mappings[i].key_url_prefix);
+    }
+    gpr_free(v->mappings);
+  }
+  gpr_free(v);
+}
diff --git a/src/core/security/jwt_verifier.h b/src/core/security/jwt_verifier.h
new file mode 100644
index 0000000..8077e24
--- /dev/null
+++ b/src/core/security/jwt_verifier.h
@@ -0,0 +1,136 @@
+/*
+ *
+ * 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 disclaimser.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimser
+ * 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_SECURITY_JWT_VERIFIER_H
+#define GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H
+
+#include "src/core/iomgr/pollset.h"
+#include "src/core/json/json.h"
+
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+
+/* --- Constants. --- */
+
+#define GRPC_OPENID_CONFIG_URL_SUFFIX "/.well-known/openid-configuration"
+#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN \
+  "developer.gserviceaccount.com"
+#define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \
+  "www.googleapis.com/robot/v1/metadata/x509"
+
+/* --- grpc_jwt_verifier_status. --- */
+
+typedef enum {
+  GRPC_JWT_VERIFIER_OK = 0,
+  GRPC_JWT_VERIFIER_BAD_SIGNATURE,
+  GRPC_JWT_VERIFIER_BAD_FORMAT,
+  GRPC_JWT_VERIFIER_BAD_AUDIENCE,
+  GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR,
+  GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE,
+  GRPC_JWT_VERIFIER_GENERIC_ERROR
+} grpc_jwt_verifier_status;
+
+const char *grpc_jwt_verifier_status_to_string(grpc_jwt_verifier_status status);
+
+/* --- grpc_jwt_claims. --- */
+
+typedef struct grpc_jwt_claims grpc_jwt_claims;
+
+void grpc_jwt_claims_destroy(grpc_jwt_claims *claims);
+
+/* Returns the whole JSON tree of the claims. */
+const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims);
+
+/* Access to registered claims in https://tools.ietf.org/html/rfc7519#page-9 */
+const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims);
+const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims);
+const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims);
+const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims);
+gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims);
+gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims);
+gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims);
+
+/* --- grpc_jwt_verifier. --- */
+
+typedef struct grpc_jwt_verifier grpc_jwt_verifier;
+
+typedef struct {
+  /* The email domain is the part after the @ sign. */
+  const char *email_domain;
+
+  /* The key url prefix will be used to get the public key from the issuer:
+     https://<key_url_prefix>/<issuer_email>
+     Therefore the key_url_prefix must NOT contain https://. */
+  const char *key_url_prefix;
+} grpc_jwt_verifier_email_domain_key_url_mapping;
+
+/* Globals to control the verifier. Not thread-safe. */
+extern gpr_timespec grpc_jwt_verifier_clock_skew;
+extern gpr_timespec grpc_jwt_verifier_max_delay;
+
+/* The verifier can be created with some custom mappings to help with key
+   discovery in the case where the issuer is an email address.
+   mappings can be NULL in which case num_mappings MUST be 0.
+   A verifier object has one built-in mapping (unless overridden):
+   GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN ->
+   GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX.*/
+grpc_jwt_verifier *grpc_jwt_verifier_create(
+    const grpc_jwt_verifier_email_domain_key_url_mapping *mappings,
+    size_t num_mappings);
+
+/*The verifier must not be destroyed if there are still outstanding callbacks.*/
+void grpc_jwt_verifier_destroy(grpc_jwt_verifier *verifier);
+
+/* User provided callback that will be called when the verification of the JWT
+   is done (maybe in another thread).
+   It is the responsibility of the callee to call grpc_jwt_claims_destroy on
+   the claims. */
+typedef void (*grpc_jwt_verification_done_cb)(void *user_data,
+                                              grpc_jwt_verifier_status status,
+                                              grpc_jwt_claims *claims);
+
+/* Verifies for the JWT for the given expected audience. */
+void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier,
+                              grpc_pollset *pollset, const char *jwt,
+                              const char *audience,
+                              grpc_jwt_verification_done_cb cb,
+                              void *user_data);
+
+/* --- TESTING ONLY exposed functions. --- */
+
+grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer);
+grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
+                                               const char *audience);
+
+#endif /* GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H */
+
diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c
index 7bb1de4..3548198 100644
--- a/src/core/security/secure_endpoint.c
+++ b/src/core/security/secure_endpoint.c
@@ -101,9 +101,7 @@
   if (grpc_trace_secure_endpoint) {
     size_t i;
     for (i = 0; i < nslices; i++) {
-      char *data =
-          gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
-                      GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+      char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
       gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
       gpr_free(data);
     }
@@ -116,7 +114,7 @@
                     grpc_endpoint_cb_status error) {
   unsigned i;
   gpr_uint8 keep_looping = 0;
-  int input_buffer_count = 0;
+  size_t input_buffer_count = 0;
   tsi_result result = TSI_OK;
   secure_endpoint *ep = (secure_endpoint *)user_data;
   gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
@@ -129,7 +127,7 @@
     size_t message_size = GPR_SLICE_LENGTH(encrypted);
 
     while (message_size > 0 || keep_looping) {
-      size_t unprotected_buffer_size_written = end - cur;
+      size_t unprotected_buffer_size_written = (size_t)(end - cur);
       size_t processed_message_size = message_size;
       gpr_mu_lock(&ep->protector_mu);
       result = tsi_frame_protector_unprotect(ep->protector, message_bytes,
@@ -166,7 +164,7 @@
         &ep->input_buffer,
         gpr_slice_split_head(
             &ep->read_staging_buffer,
-            cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)));
+            (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer))));
   }
 
   /* TODO(yangg) experiment with moving this block after read_cb to see if it
@@ -225,7 +223,7 @@
                                                  grpc_endpoint_write_cb cb,
                                                  void *user_data) {
   unsigned i;
-  int output_buffer_count = 0;
+  size_t output_buffer_count = 0;
   tsi_result result = TSI_OK;
   secure_endpoint *ep = (secure_endpoint *)secure_ep;
   gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
@@ -235,9 +233,7 @@
 
   if (grpc_trace_secure_endpoint) {
     for (i = 0; i < nslices; i++) {
-      char *data =
-          gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
-                      GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
+      char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
       gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
       gpr_free(data);
     }
@@ -248,7 +244,7 @@
     gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain);
     size_t message_size = GPR_SLICE_LENGTH(plain);
     while (message_size > 0) {
-      size_t protected_buffer_size_to_send = end - cur;
+      size_t protected_buffer_size_to_send = (size_t)(end - cur);
       size_t processed_message_size = message_size;
       gpr_mu_lock(&ep->protector_mu);
       result = tsi_frame_protector_protect(ep->protector, message_bytes,
@@ -273,7 +269,7 @@
   if (result == TSI_OK) {
     size_t still_pending_size;
     do {
-      size_t protected_buffer_size_to_send = end - cur;
+      size_t protected_buffer_size_to_send = (size_t)(end - cur);
       gpr_mu_lock(&ep->protector_mu);
       result = tsi_frame_protector_protect_flush(ep->protector, cur,
                                                  &protected_buffer_size_to_send,
@@ -290,7 +286,7 @@
           &ep->output_buffer,
           gpr_slice_split_head(
               &ep->write_staging_buffer,
-              cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)));
+              (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
     }
   }
 
diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c
index 3e1db9a..0c3572b 100644
--- a/src/core/security/secure_transport_setup.c
+++ b/src/core/security/secure_transport_setup.c
@@ -47,7 +47,8 @@
   tsi_handshaker *handshaker;
   unsigned char *handshake_buffer;
   size_t handshake_buffer_size;
-  grpc_endpoint *endpoint;
+  grpc_endpoint *wrapped_endpoint;
+  grpc_endpoint *secure_endpoint;
   gpr_slice_buffer left_overs;
   grpc_secure_transport_setup_done_cb cb;
   void *user_data;
@@ -63,18 +64,21 @@
 static void secure_transport_setup_done(grpc_secure_transport_setup *s,
                                         int is_success) {
   if (is_success) {
-    s->cb(s->user_data, GRPC_SECURITY_OK, s->endpoint);
+    s->cb(s->user_data, GRPC_SECURITY_OK, s->wrapped_endpoint,
+          s->secure_endpoint);
   } else {
-    if (s->endpoint != NULL) {
-      grpc_endpoint_shutdown(s->endpoint);
-      grpc_endpoint_destroy(s->endpoint);
+    if (s->secure_endpoint != NULL) {
+      grpc_endpoint_shutdown(s->secure_endpoint);
+      grpc_endpoint_destroy(s->secure_endpoint);
+    } else {
+      grpc_endpoint_destroy(s->wrapped_endpoint);
     }
-    s->cb(s->user_data, GRPC_SECURITY_ERROR, NULL);
+    s->cb(s->user_data, GRPC_SECURITY_ERROR, s->wrapped_endpoint, NULL);
   }
   if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker);
   if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer);
   gpr_slice_buffer_destroy(&s->left_overs);
-  grpc_security_connector_unref(s->connector);
+  GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup");
   gpr_free(s);
 }
 
@@ -95,8 +99,9 @@
     secure_transport_setup_done(s, 0);
     return;
   }
-  s->endpoint = grpc_secure_endpoint_create(
-      protector, s->endpoint, s->left_overs.slices, s->left_overs.count);
+  s->secure_endpoint =
+      grpc_secure_endpoint_create(protector, s->wrapped_endpoint,
+                                  s->left_overs.slices, s->left_overs.count);
   secure_transport_setup_done(s, 1);
   return;
 }
@@ -152,7 +157,7 @@
       gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset);
   /* TODO(klempner,jboeuf): This should probably use the client setup
          deadline */
-  write_status = grpc_endpoint_write(s->endpoint, &to_send, 1,
+  write_status = grpc_endpoint_write(s->wrapped_endpoint, &to_send, 1,
                                      on_handshake_data_sent_to_peer, s);
   if (write_status == GRPC_ENDPOINT_WRITE_ERROR) {
     gpr_log(GPR_ERROR, "Could not send handshake data to peer.");
@@ -198,7 +203,7 @@
     if (result == TSI_INCOMPLETE_DATA) {
       /* TODO(klempner,jboeuf): This should probably use the client setup
          deadline */
-      grpc_endpoint_notify_on_read(s->endpoint,
+      grpc_endpoint_notify_on_read(s->wrapped_endpoint,
                                    on_handshake_data_received_from_peer, setup);
       cleanup_slices(slices, nslices);
       return;
@@ -234,8 +239,9 @@
                          gpr_slice_split_tail(&slices[i], consumed_slice_size));
     gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */
   }
-  gpr_slice_buffer_addn(&s->left_overs, &slices[i + 1],
-                        num_left_overs - has_left_overs_in_current_slice);
+  gpr_slice_buffer_addn(
+      &s->left_overs, &slices[i + 1],
+      num_left_overs - (size_t)has_left_overs_in_current_slice);
   check_peer(s);
 }
 
@@ -255,7 +261,7 @@
   if (tsi_handshaker_is_in_progress(s->handshaker)) {
     /* TODO(klempner,jboeuf): This should probably use the client setup
        deadline */
-    grpc_endpoint_notify_on_read(s->endpoint,
+    grpc_endpoint_notify_on_read(s->wrapped_endpoint,
                                  on_handshake_data_received_from_peer, setup);
   } else {
     check_peer(s);
@@ -275,10 +281,11 @@
     secure_transport_setup_done(s, 0);
     return;
   }
-  s->connector = grpc_security_connector_ref(connector);
+  s->connector =
+      GRPC_SECURITY_CONNECTOR_REF(connector, "secure_transport_setup");
   s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
   s->handshake_buffer = gpr_malloc(s->handshake_buffer_size);
-  s->endpoint = nonsecure_endpoint;
+  s->wrapped_endpoint = nonsecure_endpoint;
   s->user_data = user_data;
   s->cb = cb;
   gpr_slice_buffer_init(&s->left_overs);
diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h
index 58701c4..29025f5 100644
--- a/src/core/security/secure_transport_setup.h
+++ b/src/core/security/secure_transport_setup.h
@@ -42,7 +42,7 @@
 /* Ownership of the secure_endpoint is transfered. */
 typedef void (*grpc_secure_transport_setup_done_cb)(
     void *user_data, grpc_security_status status,
-    grpc_endpoint *secure_endpoint);
+    grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint);
 
 /* Calls the callback upon completion. */
 void grpc_setup_secure_transport(grpc_security_connector *connector,
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 4098636..f6e423e 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -84,12 +84,12 @@
 /* -- Common methods. -- */
 
 /* Returns the first property with that name. */
-const tsi_peer_property *tsi_peer_get_property_by_name(
-    const tsi_peer *peer, const char *name) {
+const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
+                                                       const char *name) {
   size_t i;
   if (peer == NULL) return NULL;
   for (i = 0; i < peer->property_count; i++) {
-    const tsi_peer_property* property = &peer->properties[i];
+    const tsi_peer_property *property = &peer->properties[i];
     if (name == NULL && property->name == NULL) {
       return property;
     }
@@ -124,24 +124,44 @@
   return sc->check_call_host(sc, host, cb, user_data);
 }
 
-void grpc_security_connector_unref(grpc_security_connector *sc) {
-  if (sc == NULL) return;
-  if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
-}
-
+#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
+grpc_security_connector *grpc_security_connector_ref(
+    grpc_security_connector *sc, const char *file, int line,
+    const char *reason) {
+  if (sc == NULL) return NULL;
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "SECURITY_CONNECTOR:%p   ref %d -> %d %s", sc,
+          (int)sc->refcount.count, (int)sc->refcount.count + 1, reason);
+#else
 grpc_security_connector *grpc_security_connector_ref(
     grpc_security_connector *sc) {
   if (sc == NULL) return NULL;
+#endif
   gpr_ref(&sc->refcount);
   return sc;
 }
 
+#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
+void grpc_security_connector_unref(grpc_security_connector *sc,
+                                   const char *file, int line,
+                                   const char *reason) {
+  if (sc == NULL) return;
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc,
+          (int)sc->refcount.count, (int)sc->refcount.count - 1, reason);
+#else
+void grpc_security_connector_unref(grpc_security_connector *sc) {
+  if (sc == NULL) return;
+#endif
+  if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
+}
+
 static void connector_pointer_arg_destroy(void *p) {
-  grpc_security_connector_unref(p);
+  GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg");
 }
 
 static void *connector_pointer_arg_copy(void *p) {
-  return grpc_security_connector_ref(p);
+  return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg");
 }
 
 grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
@@ -196,12 +216,12 @@
 static void fake_channel_destroy(grpc_security_connector *sc) {
   grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
   grpc_credentials_unref(c->request_metadata_creds);
-  grpc_auth_context_unref(sc->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
   gpr_free(sc);
 }
 
 static void fake_server_destroy(grpc_security_connector *sc) {
-  grpc_auth_context_unref(sc->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
   gpr_free(sc);
 }
 
@@ -242,7 +262,7 @@
     status = GRPC_SECURITY_ERROR;
     goto end;
   }
-  grpc_auth_context_unref(sc->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
   sc->auth_context = grpc_auth_context_create(NULL, 1);
   sc->auth_context->properties[0] = grpc_auth_property_init_from_cstring(
       GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
@@ -323,7 +343,7 @@
   if (c->target_name != NULL) gpr_free(c->target_name);
   if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
   tsi_peer_destruct(&c->peer);
-  grpc_auth_context_unref(sc->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
   gpr_free(sc);
 }
 
@@ -333,7 +353,7 @@
   if (c->handshaker_factory != NULL) {
     tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
   }
-  grpc_auth_context_unref(sc->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
   gpr_free(sc);
 }
 
@@ -386,29 +406,13 @@
   return r;
 }
 
-static grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
-  /* We bet that iterating over a handful of properties twice will be faster
-     than having to realloc on average . */
-  size_t auth_prop_count = 1; /* for transport_security_type. */
+grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
   size_t i;
-  const char *peer_identity_property_name = NULL;
   grpc_auth_context *ctx = NULL;
-  for (i = 0; i < peer->property_count; i++) {
-    const tsi_peer_property *prop = &peer->properties[i];
-    if (prop->name == NULL) continue;
-    if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
-      auth_prop_count++;
-      /* If there is no subject alt name, have the CN as the identity. */
-      if (peer_identity_property_name == NULL) {
-        peer_identity_property_name = prop->name;
-      }
-    } else if (strcmp(prop->name,
-                      TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
-      auth_prop_count++;
-      peer_identity_property_name = prop->name;
-    }
-  }
-  ctx = grpc_auth_context_create(NULL, auth_prop_count);
+
+  /* The caller has checked the certificate type property. */
+  GPR_ASSERT(peer->property_count >= 1);
+  ctx = grpc_auth_context_create(NULL, peer->property_count);
   ctx->properties[0] = grpc_auth_property_init_from_cstring(
       GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
       GRPC_SSL_TRANSPORT_SECURITY_TYPE);
@@ -417,15 +421,19 @@
     const tsi_peer_property *prop = &peer->properties[i];
     if (prop->name == NULL) continue;
     if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
+      /* If there is no subject alt name, have the CN as the identity. */
+      if (ctx->peer_identity_property_name == NULL) {
+        ctx->peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
+      }
       ctx->properties[ctx->property_count++] = grpc_auth_property_init(
           GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length);
     } else if (strcmp(prop->name,
                       TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
+      ctx->peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
       ctx->properties[ctx->property_count++] = grpc_auth_property_init(
           GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length);
     }
   }
-  GPR_ASSERT(auth_prop_count == ctx->property_count);
   return ctx;
 }
 
@@ -449,6 +457,9 @@
     gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
     return GRPC_SECURITY_ERROR;
   }
+  if (sc->auth_context != NULL) {
+    GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
+  }
   sc->auth_context = tsi_ssl_peer_to_auth_context(peer);
   return GRPC_SECURITY_OK;
 }
@@ -550,7 +561,7 @@
     alpn_protocol_strings[i] =
         (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
     alpn_protocol_string_lengths[i] =
-        strlen(grpc_chttp2_get_alpn_version_index(i));
+        (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
   }
 
   if (config == NULL || target_name == NULL) {
@@ -589,7 +600,8 @@
       config->pem_private_key, config->pem_private_key_size,
       config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
       pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings,
-      alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
+      alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols,
+      &c->handshaker_factory);
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
@@ -623,7 +635,7 @@
     alpn_protocol_strings[i] =
         (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
     alpn_protocol_string_lengths[i] =
-        strlen(grpc_chttp2_get_alpn_version_index(i));
+        (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
   }
 
   if (config == NULL || config->num_key_cert_pairs == 0) {
@@ -642,8 +654,8 @@
       (const unsigned char **)config->pem_cert_chains,
       config->pem_cert_chains_sizes, config->num_key_cert_pairs,
       config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(),
-      alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols,
-      &c->handshaker_factory);
+      alpn_protocol_strings, alpn_protocol_string_lengths,
+      (uint16_t)num_alpn_protocols, &c->handshaker_factory);
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
@@ -661,4 +673,3 @@
   gpr_free(alpn_protocol_string_lengths);
   return GRPC_SECURITY_ERROR;
 }
-
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index 0617041..a4c723f 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -80,12 +80,25 @@
   grpc_auth_context *auth_context; /* Populated after the peer is checked. */
 };
 
-/* Increments the refcount. */
+/* Refcounting. */
+#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
+#define GRPC_SECURITY_CONNECTOR_REF(p, r) \
+  grpc_security_connector_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \
+  grpc_security_connector_unref((p), __FILE__, __LINE__, (r))
 grpc_security_connector *grpc_security_connector_ref(
-    grpc_security_connector *sc);
-
-/* Decrements the refcount and destroys the object if it reaches 0. */
-void grpc_security_connector_unref(grpc_security_connector *sc);
+    grpc_security_connector *policy, const char *file, int line,
+    const char *reason);
+void grpc_security_connector_unref(grpc_security_connector *policy,
+                                   const char *file, int line,
+                                   const char *reason);
+#else
+#define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p))
+#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p))
+grpc_security_connector *grpc_security_connector_ref(
+    grpc_security_connector *policy);
+void grpc_security_connector_unref(grpc_security_connector *policy);
+#endif
 
 /* Handshake creation. */
 grpc_security_status grpc_security_connector_create_handshaker(
@@ -172,9 +185,9 @@
   specific error code otherwise.
 */
 grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_credentials *request_metadata_creds,
-    const grpc_ssl_config *config, const char *target_name,
-    const char *overridden_target_name, grpc_channel_security_connector **sc);
+    grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
+    const char *target_name, const char *overridden_target_name,
+    grpc_channel_security_connector **sc);
 
 /* Gets the default ssl roots. */
 size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
@@ -200,7 +213,10 @@
     const grpc_ssl_server_config *config, grpc_security_connector **sc);
 
 /* Util. */
-const tsi_peer_property *tsi_peer_get_property_by_name(
-    const tsi_peer *peer, const char *name);
+const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
+                                                       const char *name);
+
+/* Exposed for testing only. */
+grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer);
 
 #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index 9aba1e7..8ce7876 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -69,12 +69,20 @@
   return GRPC_CALL_OK;
 }
 
-const grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
+grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
   void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
   if (sec_ctx == NULL) return NULL;
   return grpc_call_is_client(call)
-             ? ((grpc_client_security_context *)sec_ctx)->auth_context
-             : ((grpc_server_security_context *)sec_ctx)->auth_context;
+             ? GRPC_AUTH_CONTEXT_REF(
+                   ((grpc_client_security_context *)sec_ctx)->auth_context,
+                   "grpc_call_auth_context client")
+             : GRPC_AUTH_CONTEXT_REF(
+                   ((grpc_server_security_context *)sec_ctx)->auth_context,
+                   "grpc_call_auth_context server");
+}
+
+void grpc_auth_context_release(grpc_auth_context *context) {
+  GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref");
 }
 
 /* --- grpc_client_security_context --- */
@@ -89,7 +97,7 @@
 void grpc_client_security_context_destroy(void *ctx) {
   grpc_client_security_context *c = (grpc_client_security_context *)ctx;
   grpc_credentials_unref(c->creds);
-  grpc_auth_context_unref(c->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
   gpr_free(ctx);
 }
 
@@ -104,7 +112,7 @@
 
 void grpc_server_security_context_destroy(void *ctx) {
   grpc_server_security_context *c = (grpc_server_security_context *)ctx;
-  grpc_auth_context_unref(c->auth_context);
+  GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context");
   gpr_free(ctx);
 }
 
@@ -120,21 +128,40 @@
   memset(ctx->properties, 0, property_count * sizeof(grpc_auth_property));
   ctx->property_count = property_count;
   gpr_ref_init(&ctx->refcount, 1);
-  if (chained != NULL) ctx->chained = grpc_auth_context_ref(chained);
+  if (chained != NULL) ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
   return ctx;
 }
 
+#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG
+grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx,
+                                         const char *file, int line,
+                                         const char *reason) {
+  if (ctx == NULL) return NULL;
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "AUTH_CONTEXT:%p   ref %d -> %d %s", ctx, (int)ctx->refcount.count,
+          (int)ctx->refcount.count + 1, reason);
+#else
 grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) {
   if (ctx == NULL) return NULL;
+#endif
   gpr_ref(&ctx->refcount);
   return ctx;
 }
 
+#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG
+void grpc_auth_context_unref(grpc_auth_context *ctx, const char *file, int line,
+                             const char *reason) {
+  if (ctx == NULL) return;
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "AUTH_CONTEXT:%p unref %d -> %d %s", ctx, (int)ctx->refcount.count,
+          (int)ctx->refcount.count - 1, reason);
+#else
 void grpc_auth_context_unref(grpc_auth_context *ctx) {
   if (ctx == NULL) return;
+#endif
   if (gpr_unref(&ctx->refcount)) {
     size_t i;
-    grpc_auth_context_unref(ctx->chained);
+    GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained");
     if (ctx->properties != NULL) {
       for (i = 0; i < ctx->property_count; i++) {
         grpc_auth_property_reset(&ctx->properties[i]);
@@ -223,8 +250,8 @@
 }
 
 void grpc_auth_property_reset(grpc_auth_property *property) {
-  if (property->name != NULL) gpr_free(property->name);
-  if (property->value != NULL) gpr_free(property->value);
+  gpr_free(property->name);
+  gpr_free(property->value);
   memset(property, 0, sizeof(grpc_auth_property));
 }
 
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index d8909cd..76a4591 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -36,6 +36,10 @@
 
 #include "src/core/security/credentials.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* --- grpc_auth_context ---
 
    High level authentication context object. Can optionally be chained. */
@@ -55,9 +59,22 @@
                                             size_t property_count);
 
 /* Refcounting. */
-grpc_auth_context *grpc_auth_context_ref(
-    grpc_auth_context *ctx);
-void grpc_auth_context_unref(grpc_auth_context *ctx);
+#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG
+#define GRPC_AUTH_CONTEXT_REF(p, r) \
+  grpc_auth_context_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_AUTH_CONTEXT_UNREF(p, r) \
+  grpc_auth_context_unref((p), __FILE__, __LINE__, (r))
+grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy,
+                                         const char *file, int line,
+                                         const char *reason);
+void grpc_auth_context_unref(grpc_auth_context *policy, const char *file,
+                             int line, const char *reason);
+#else
+#define GRPC_AUTH_CONTEXT_REF(p, r) grpc_auth_context_ref((p))
+#define GRPC_AUTH_CONTEXT_UNREF(p, r) grpc_auth_context_unref((p))
+grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy);
+void grpc_auth_context_unref(grpc_auth_context *policy);
+#endif
 
 grpc_auth_property grpc_auth_property_init_from_cstring(const char *name,
                                                         const char *value);
@@ -90,5 +107,9 @@
 grpc_server_security_context *grpc_server_security_context_create(void);
 void grpc_server_security_context_destroy(void *ctx);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif  /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
 
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index b19160b..10eef6d 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -51,24 +51,17 @@
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
 static void auth_start_transport_op(grpc_call_element *elem,
-                                    grpc_transport_op *op) {
+                                    grpc_transport_stream_op *op) {
   /* TODO(jboeuf): Get the metadata and get a new context from it. */
 
   /* pass control down the stack */
   grpc_call_next_op(elem, op);
 }
 
-/* Called on special channel events, such as disconnection or new incoming
-   calls on the server */
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  grpc_channel_next_op(elem, op);
-}
-
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
@@ -82,20 +75,23 @@
 
   /* Create a security context for the call and reference the auth context from
      the channel. */
+  if (initial_op->context[GRPC_CONTEXT_SECURITY].value != NULL) {
+    initial_op->context[GRPC_CONTEXT_SECURITY].destroy(
+        initial_op->context[GRPC_CONTEXT_SECURITY].value);
+  }
   server_ctx = grpc_server_security_context_create();
-  server_ctx->auth_context =
-      grpc_auth_context_ref(chand->security_connector->auth_context);
+  server_ctx->auth_context = GRPC_AUTH_CONTEXT_REF(
+      chand->security_connector->auth_context, "server_security_context");
   initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
   initial_op->context[GRPC_CONTEXT_SECURITY].destroy =
       grpc_server_security_context_destroy;
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_call_element *elem) {
-}
+static void destroy_call_elem(grpc_call_element *elem) {}
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
                               int is_first, int is_last) {
   grpc_security_connector *sc = grpc_find_security_connector_in_args(args);
@@ -111,17 +107,19 @@
 
   /* initialize members */
   GPR_ASSERT(!sc->is_client_side);
-  chand->security_connector = grpc_security_connector_ref(sc);
+  chand->security_connector =
+      GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter");
 }
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_channel_element *elem) {
   /* grab pointers to our data from the channel element */
   channel_data *chand = elem->channel_data;
-  grpc_security_connector_unref(chand->security_connector);
+  GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector,
+                                "server_auth_filter");
 }
 
 const grpc_channel_filter grpc_server_auth_filter = {
-    auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "server-auth"};
+    auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+    init_call_elem,          destroy_call_elem,    sizeof(channel_data),
+    init_channel_elem,       destroy_channel_elem, "server-auth"};
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 3519930..3717b89 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -51,10 +51,16 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
+typedef struct tcp_endpoint_list {
+  grpc_endpoint *tcp_endpoint;
+  struct tcp_endpoint_list *next;
+} tcp_endpoint_list;
+
 typedef struct grpc_server_secure_state {
   grpc_server *server;
   grpc_tcp_server *tcp;
   grpc_security_connector *sc;
+  tcp_endpoint_list *handshaking_tcp_endpoints;
   int is_shutdown;
   gpr_mu mu;
   gpr_refcount refcount;
@@ -66,38 +72,66 @@
 
 static void state_unref(grpc_server_secure_state *state) {
   if (gpr_unref(&state->refcount)) {
-    grpc_security_connector_unref(state->sc);
+    /* ensure all threads have unlocked */
+    gpr_mu_lock(&state->mu);
+    gpr_mu_unlock(&state->mu);
+    /* clean up */
+    GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server");
     gpr_free(state);
   }
 }
 
-static grpc_transport_setup_result setup_transport(void *statep,
-                                                   grpc_transport *transport,
-                                                   grpc_mdctx *mdctx) {
+static void setup_transport(void *statep, grpc_transport *transport,
+                            grpc_mdctx *mdctx) {
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_server_auth_filter, &grpc_http_server_filter};
   grpc_server_secure_state *state = statep;
-  grpc_transport_setup_result result;
   grpc_arg connector_arg = grpc_security_connector_to_arg(state->sc);
   grpc_channel_args *args_copy = grpc_channel_args_copy_and_add(
-      grpc_server_get_channel_args(state->server), &connector_arg);
-  result = grpc_server_setup_transport(state->server, transport, extra_filters,
-                                       GPR_ARRAY_SIZE(extra_filters), mdctx,
-                                       args_copy);
+      grpc_server_get_channel_args(state->server), &connector_arg, 1);
+  grpc_server_setup_transport(state->server, transport, extra_filters,
+                              GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy);
   grpc_channel_args_destroy(args_copy);
-  return result;
+}
+
+static int remove_tcp_from_list_locked(grpc_server_secure_state *state,
+                                       grpc_endpoint *tcp) {
+  tcp_endpoint_list *node = state->handshaking_tcp_endpoints;
+  tcp_endpoint_list *tmp = NULL;
+  if (node && node->tcp_endpoint == tcp) {
+    state->handshaking_tcp_endpoints = state->handshaking_tcp_endpoints->next;
+    gpr_free(node);
+    return 0;
+  }
+  while (node) {
+    if (node->next->tcp_endpoint == tcp) {
+      tmp = node->next;
+      node->next = node->next->next;
+      gpr_free(tmp);
+      return 0;
+    }
+    node = node->next;
+  }
+  return -1;
 }
 
 static void on_secure_transport_setup_done(void *statep,
                                            grpc_security_status status,
+                                           grpc_endpoint *wrapped_endpoint,
                                            grpc_endpoint *secure_endpoint) {
   grpc_server_secure_state *state = statep;
+  grpc_transport *transport;
+  grpc_mdctx *mdctx;
   if (status == GRPC_SECURITY_OK) {
     gpr_mu_lock(&state->mu);
+    remove_tcp_from_list_locked(state, wrapped_endpoint);
     if (!state->is_shutdown) {
-      grpc_create_chttp2_transport(
-          setup_transport, state, grpc_server_get_channel_args(state->server),
-          secure_endpoint, NULL, 0, grpc_mdctx_create(), 0);
+      mdctx = grpc_mdctx_create();
+      transport = grpc_create_chttp2_transport(
+          grpc_server_get_channel_args(state->server), secure_endpoint, mdctx,
+          0);
+      setup_transport(state, transport, mdctx);
+      grpc_chttp2_transport_start_reading(transport, NULL, 0);
     } else {
       /* We need to consume this here, because the server may already have gone
        * away. */
@@ -105,6 +139,9 @@
     }
     gpr_mu_unlock(&state->mu);
   } else {
+    gpr_mu_lock(&state->mu);
+    remove_tcp_from_list_locked(state, wrapped_endpoint);
+    gpr_mu_unlock(&state->mu);
     gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
   }
   state_unref(state);
@@ -112,7 +149,14 @@
 
 static void on_accept(void *statep, grpc_endpoint *tcp) {
   grpc_server_secure_state *state = statep;
+  tcp_endpoint_list *node;
   state_ref(state);
+  node = gpr_malloc(sizeof(tcp_endpoint_list));
+  node->tcp_endpoint = tcp;
+  gpr_mu_lock(&state->mu);
+  node->next = state->handshaking_tcp_endpoints;
+  state->handshaking_tcp_endpoints = node;
+  gpr_mu_unlock(&state->mu);
   grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done,
                               state);
 }
@@ -124,16 +168,29 @@
   grpc_tcp_server_start(state->tcp, pollsets, pollset_count, on_accept, state);
 }
 
+static void destroy_done(void *statep) {
+  grpc_server_secure_state *state = statep;
+  grpc_server_listener_destroy_done(state->server);
+  gpr_mu_lock(&state->mu);
+  while (state->handshaking_tcp_endpoints != NULL) {
+    grpc_endpoint_shutdown(state->handshaking_tcp_endpoints->tcp_endpoint);
+    remove_tcp_from_list_locked(state,
+                                state->handshaking_tcp_endpoints->tcp_endpoint);
+  }
+  gpr_mu_unlock(&state->mu);
+  state_unref(state);
+}
+
 /* Server callback: destroy the tcp listener (so we don't generate further
    callbacks) */
 static void destroy(grpc_server *server, void *statep) {
   grpc_server_secure_state *state = statep;
+  grpc_tcp_server *tcp;
   gpr_mu_lock(&state->mu);
   state->is_shutdown = 1;
-  grpc_tcp_server_destroy(state->tcp, grpc_server_listener_destroy_done,
-                          server);
+  tcp = state->tcp;
   gpr_mu_unlock(&state->mu);
-  state_unref(state);
+  grpc_tcp_server_destroy(tcp, destroy_done, state);
 }
 
 int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
@@ -198,6 +255,7 @@
   state->server = server;
   state->tcp = tcp;
   state->sc = sc;
+  state->handshaking_tcp_endpoints = NULL;
   state->is_shutdown = 0;
   gpr_mu_init(&state->mu);
   gpr_ref_init(&state->refcount, 1);
@@ -210,7 +268,7 @@
 /* Error path: cleanup and return */
 error:
   if (sc) {
-    grpc_security_connector_unref(sc);
+    GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
   }
   if (resolved) {
     grpc_resolved_addresses_destroy(resolved);
diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c
index 0491c91..3e571b1 100644
--- a/src/core/statistics/census_rpc_stats.c
+++ b/src/core/statistics/census_rpc_stats.c
@@ -157,7 +157,7 @@
         key.ptr = gpr_strdup(key.ptr);
         census_ht_insert(store, key, (void*)window_stats);
       }
-      census_window_stats_add(window_stats, gpr_now(), stats);
+      census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats);
     } else {
       census_internal_unlock_trace_store();
     }
@@ -185,7 +185,7 @@
   if (store != NULL) {
     size_t n;
     unsigned i, j;
-    gpr_timespec now = gpr_now();
+    gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
     census_ht_kv* kv = census_ht_get_all_elements(store, &n);
     if (kv != NULL) {
       data->num_entries = n;
diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
index 05e72b9..3036ba5 100644
--- a/src/core/statistics/census_tracing.c
+++ b/src/core/statistics/census_tracing.c
@@ -94,7 +94,7 @@
     g_id++;
     memcpy(&ret->id, &g_id, sizeof(census_op_id));
     ret->rpc_stats.cnt = 1;
-    ret->ts = gpr_now();
+    ret->ts = gpr_now(GPR_CLOCK_REALTIME);
     census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void*)ret);
     gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id);
     gpr_mu_unlock(&g_mu);
@@ -122,7 +122,7 @@
   trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
   if (trace != NULL) {
     census_trace_annotation* anno = gpr_malloc(sizeof(census_trace_annotation));
-    anno->ts = gpr_now();
+    anno->ts = gpr_now(GPR_CLOCK_REALTIME);
     {
       char* d = anno->txt;
       const char* s = anno_txt;
@@ -143,8 +143,8 @@
   gpr_mu_lock(&g_mu);
   trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
   if (trace != NULL) {
-    trace->rpc_stats.elapsed_time_ms =
-        gpr_timespec_to_micros(gpr_time_sub(gpr_now(), trace->ts));
+    trace->rpc_stats.elapsed_time_ms = gpr_timespec_to_micros(
+        gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), trace->ts));
     gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us",
             op_id_2_uint64(&op_id), trace->method,
             trace->rpc_stats.elapsed_time_ms);
@@ -194,8 +194,8 @@
 
 static census_trace_annotation* dup_annotation_chain(
     census_trace_annotation* from) {
-  census_trace_annotation *ret = NULL;
-  census_trace_annotation **to = &ret;
+  census_trace_annotation* ret = NULL;
+  census_trace_annotation** to = &ret;
   for (; from != NULL; from = from->next) {
     *to = gpr_malloc(sizeof(census_trace_annotation));
     memcpy(*to, from, sizeof(census_trace_annotation));
@@ -223,9 +223,9 @@
     size_t n = 0;
     census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n);
     *num_active_ops = (int)n;
-    if (n != 0 ) {
+    if (n != 0) {
       size_t i = 0;
-      ret = gpr_malloc(sizeof(census_trace_obj *) * n);
+      ret = gpr_malloc(sizeof(census_trace_obj*) * n);
       for (i = 0; i < n; i++) {
         ret[i] = trace_obj_dup((census_trace_obj*)all_kvs[i].v);
       }
diff --git a/src/core/statistics/window_stats.h b/src/core/statistics/window_stats.h
index d733d8d..0020f6b 100644
--- a/src/core/statistics/window_stats.h
+++ b/src/core/statistics/window_stats.h
@@ -90,11 +90,11 @@
     // Record a new event, taking 15.3ms, transferring 1784 bytes.
     stat.latency = 0.153;
     stat.bytes = 1784;
-    census_window_stats_add(stats, gpr_now(), &stat);
+    census_window_stats_add(stats, gpr_now(GPR_CLOCK_REALTIME), &stat);
     // Get sums and print them out
     result[kMinInterval].statistic = &sums[kMinInterval];
     result[kHourInterval].statistic = &sums[kHourInterval];
-    census_window_stats_get_sums(stats, gpr_now(), result);
+    census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), result);
     printf("%d events/min, average time %gs, average bytes %g\n",
            result[kMinInterval].count,
            (my_stat*)result[kMinInterval].statistic->latency /
@@ -170,4 +170,4 @@
    assertion failure). This function is thread-compatible. */
 void census_window_stats_destroy(struct census_window_stats* wstats);
 
-#endif  /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */
diff --git a/src/core/support/cancellable.c b/src/core/support/cancellable.c
index 5a4d488..4756f1e 100644
--- a/src/core/support/cancellable.c
+++ b/src/core/support/cancellable.c
@@ -121,8 +121,9 @@
         } else {
           gpr_event ev;
           gpr_event_init(&ev);
-          gpr_event_wait(&ev,
-                         gpr_time_add(gpr_now(), gpr_time_from_micros(1000)));
+          gpr_event_wait(
+              &ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                gpr_time_from_micros(1000, GPR_TIMESPAN)));
         }
       }
     } while (failures != 0);
diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c
index 4baad85..45a3182 100644
--- a/src/core/support/cmdline.c
+++ b/src/core/support/cmdline.c
@@ -228,7 +228,7 @@
                 cl->cur_arg->name);
         print_usage_and_die(cl);
       }
-      *(int *)cl->cur_arg->value = intval;
+      *(int *)cl->cur_arg->value = (int)intval;
       break;
     case ARGTYPE_BOOL:
       if (0 == strcmp(arg, "1") || 0 == strcmp(arg, "true")) {
@@ -287,8 +287,8 @@
     eq = strchr(arg, '=');
     if (eq != NULL) {
       /* copy the string into a temp buffer and extract the name */
-      tmp = arg_name = gpr_malloc(eq - arg + 1);
-      memcpy(arg_name, arg, eq - arg);
+      tmp = arg_name = gpr_malloc((size_t)(eq - arg + 1));
+      memcpy(arg_name, arg, (size_t)(eq - arg));
       arg_name[eq - arg] = 0;
     } else {
       arg_name = arg;
diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c
index 37e840d..282d4da 100644
--- a/src/core/support/cpu_linux.c
+++ b/src/core/support/cpu_linux.c
@@ -51,7 +51,9 @@
 static int ncpus = 0;
 
 static void init_num_cpus() {
-  ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+  /* This must be signed. sysconf returns -1 when the number cannot be
+     determined */
+  ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN);
   if (ncpus < 1) {
     gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
     ncpus = 1;
@@ -61,7 +63,7 @@
 unsigned gpr_cpu_num_cores(void) {
   static gpr_once once = GPR_ONCE_INIT;
   gpr_once_init(&once, init_num_cpus);
-  return ncpus;
+  return (unsigned)ncpus;
 }
 
 unsigned gpr_cpu_current_cpu(void) {
@@ -70,7 +72,7 @@
     gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
     return 0;
   }
-  return cpu;
+  return (unsigned)cpu;
 }
 
 #endif /* GPR_CPU_LINUX */
diff --git a/src/core/support/cpu_windows.c b/src/core/support/cpu_windows.c
index 107a7b8..ce32eb0 100644
--- a/src/core/support/cpu_windows.c
+++ b/src/core/support/cpu_windows.c
@@ -34,7 +34,6 @@
 #include <grpc/support/port_platform.h>
 
 #ifdef GPR_WIN32
-#include <windows.h>
 #include <grpc/support/log.h>
 
 unsigned gpr_cpu_num_cores(void) {
diff --git a/src/core/support/file.c b/src/core/support/file.c
index 8ce7a67..c1361d8 100644
--- a/src/core/support/file.c
+++ b/src/core/support/file.c
@@ -58,7 +58,8 @@
     goto end;
   }
   fseek(file, 0, SEEK_END);
-  contents_size = ftell(file);
+  /* Converting to size_t on the assumption that it will not fail */
+  contents_size = (size_t)ftell(file);
   fseek(file, 0, SEEK_SET);
   contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0));
   bytes_read = fread(contents, 1, contents_size, file);
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
index 673affd..9029703 100644
--- a/src/core/support/histogram.c
+++ b/src/core/support/histogram.c
@@ -164,7 +164,9 @@
   size_t lower_idx;
   size_t upper_idx;
 
-  GPR_ASSERT(h->count >= 1);
+  if (h->count == 0) {
+    return 0.0;
+  }
 
   if (count_below <= 0) {
     return h->min_seen;
@@ -189,12 +191,12 @@
         break;
       }
     }
-    return (bucket_start(h, lower_idx) + bucket_start(h, upper_idx)) / 2.0;
+    return (bucket_start(h, (double)lower_idx) + bucket_start(h, (double)upper_idx)) / 2.0;
   } else {
     /* treat values as uniform throughout the bucket, and find where this value
        should lie */
-    lower_bound = bucket_start(h, lower_idx);
-    upper_bound = bucket_start(h, lower_idx + 1);
+    lower_bound = bucket_start(h, (double)lower_idx);
+    upper_bound = bucket_start(h, (double)(lower_idx + 1));
     return GPR_CLAMP(upper_bound - (upper_bound - lower_bound) *
                                        (count_so_far - count_below) /
                                        h->buckets[lower_idx],
diff --git a/src/core/support/host_port.c b/src/core/support/host_port.c
index 53669f0..0906ebc 100644
--- a/src/core/support/host_port.c
+++ b/src/core/support/host_port.c
@@ -76,7 +76,7 @@
       return;
     }
     host_start = name + 1;
-    host_len = rbracket - host_start;
+    host_len = (size_t)(rbracket - host_start);
     if (memchr(host_start, ':', host_len) == NULL) {
       /* Require all bracketed hosts to contain a colon, because a hostname or
       IPv4 address should never use brackets. */
@@ -87,7 +87,7 @@
     if (colon != NULL && strchr(colon + 1, ':') == NULL) {
       /* Exactly 1 colon.  Split into host:port. */
       host_start = name;
-      host_len = colon - name;
+      host_len = (size_t)(colon - name);
       port_start = colon + 1;
     } else {
       /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
index 48349d2..5ac36e7 100644
--- a/src/core/support/log_linux.c
+++ b/src/core/support/log_linux.c
@@ -43,7 +43,9 @@
 
 #ifdef GPR_LINUX
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -71,9 +73,10 @@
 
 void gpr_default_log(gpr_log_func_args *args) {
   char *final_slash;
+  char *prefix;
   const char *display_file;
   char time_buffer[64];
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
   final_slash = strrchr(args->file, '/');
@@ -89,10 +92,12 @@
     strcpy(time_buffer, "error:strftime");
   }
 
-  fprintf(stderr, "%s%s.%09d %7ld %s:%d] %s\n",
+  gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
           gpr_log_severity_string(args->severity), time_buffer,
-          (int)(now.tv_nsec), gettid(), display_file, args->line,
-          args->message);
+          (int)(now.tv_nsec), gettid(), display_file, args->line);
+
+  fprintf(stderr, "%-60s %s\n", prefix, args->message);
+  gpr_free(prefix);
 }
 
 #endif
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
index afca792..940ee20 100644
--- a/src/core/support/log_posix.c
+++ b/src/core/support/log_posix.c
@@ -75,7 +75,7 @@
   char *final_slash;
   const char *display_file;
   char time_buffer[64];
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
   final_slash = strrchr(args->file, '/');
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index f878e6a..629781d 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -82,7 +82,7 @@
 /* Simple starter implementation */
 void gpr_default_log(gpr_log_func_args *args) {
   char time_buffer[64];
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
   if (localtime_s(&tm, &now.tv_sec)) {
@@ -94,23 +94,22 @@
 
   fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n",
           gpr_log_severity_string(args->severity), time_buffer,
-          (int)(now.tv_nsec), GetCurrentThreadId(),
-          args->file, args->line, args->message);
+          (int)(now.tv_nsec), GetCurrentThreadId(), args->file, args->line,
+          args->message);
 }
 
 char *gpr_format_message(DWORD messageid) {
   LPTSTR tmessage;
   char *message;
-  DWORD status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                               FORMAT_MESSAGE_FROM_SYSTEM |
-                               FORMAT_MESSAGE_IGNORE_INSERTS,
-                               NULL, messageid,
-                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                               (LPTSTR)(&tmessage), 0, NULL);
+  DWORD status = FormatMessage(
+      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+          FORMAT_MESSAGE_IGNORE_INSERTS,
+      NULL, messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+      (LPTSTR)(&tmessage), 0, NULL);
   if (status == 0) return gpr_strdup("Unable to retrieve error string");
   message = gpr_tchar_to_char(tmessage);
   LocalFree(tmessage);
   return message;
 }
 
-#endif  /* GPR_WIN32 */
+#endif /* GPR_WIN32 */
diff --git a/src/core/support/murmur_hash.c b/src/core/support/murmur_hash.c
index cc84691..37fdca8 100644
--- a/src/core/support/murmur_hash.c
+++ b/src/core/support/murmur_hash.c
@@ -48,7 +48,7 @@
 
 gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed) {
   const gpr_uint8 *data = (const gpr_uint8 *)key;
-  const int nblocks = len / 4;
+  const size_t nblocks = len / 4;
   int i;
 
   gpr_uint32 h1 = seed;
@@ -57,11 +57,11 @@
   const gpr_uint32 c1 = 0xcc9e2d51;
   const gpr_uint32 c2 = 0x1b873593;
 
-  const gpr_uint32 *blocks = (const uint32_t *)(data + nblocks * 4);
-  const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
+  const gpr_uint32 *blocks = ((const gpr_uint32 *)key) + nblocks;
+  const gpr_uint8 *tail = (const gpr_uint8 *)(data + nblocks * 4);
 
   /* body */
-  for (i = -nblocks; i; i++) {
+  for (i = -(int)nblocks; i; i++) {
     k1 = GETBLOCK32(blocks, i);
 
     k1 *= c1;
@@ -78,9 +78,9 @@
   /* tail */
   switch (len & 3) {
     case 3:
-      k1 ^= tail[2] << 16;
+      k1 ^= ((gpr_uint32)tail[2]) << 16;
     case 2:
-      k1 ^= tail[1] << 8;
+      k1 ^= ((gpr_uint32)tail[1]) << 8;
     case 1:
       k1 ^= tail[0];
       k1 *= c1;
@@ -90,7 +90,7 @@
   };
 
   /* finalization */
-  h1 ^= len;
+  h1 ^= (gpr_uint32)len;
   FMIX32(h1);
   return h1;
 }
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
index 4cff029..e4196a4 100644
--- a/src/core/support/slice.c
+++ b/src/core/support/slice.c
@@ -194,7 +194,7 @@
   } else {
     /* small slice: just inline the data */
     slice.refcount = NULL;
-    slice.data.inlined.length = length;
+    slice.data.inlined.length = (gpr_uint8)length;
   }
   return slice;
 }
@@ -202,11 +202,11 @@
 gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) {
   gpr_slice subset;
 
+  GPR_ASSERT(end >= begin);
+
   if (source.refcount) {
     /* Enforce preconditions */
-    GPR_ASSERT(source.data.refcounted.length >= begin);
     GPR_ASSERT(source.data.refcounted.length >= end);
-    GPR_ASSERT(end >= begin);
 
     /* Build the result */
     subset.refcount = source.refcount;
@@ -214,8 +214,10 @@
     subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
     subset.data.refcounted.length = end - begin;
   } else {
+    /* Enforce preconditions */
+    GPR_ASSERT(source.data.inlined.length >= end);
     subset.refcount = NULL;
-    subset.data.inlined.length = end - begin;
+    subset.data.inlined.length = (gpr_uint8)(end - begin);
     memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
            end - begin);
   }
@@ -227,7 +229,7 @@
 
   if (end - begin <= sizeof(subset.data.inlined.bytes)) {
     subset.refcount = NULL;
-    subset.data.inlined.length = end - begin;
+    subset.data.inlined.length = (gpr_uint8)(end - begin);
     memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin,
            end - begin);
   } else {
@@ -245,17 +247,17 @@
     /* inlined data, copy it out */
     GPR_ASSERT(source->data.inlined.length >= split);
     tail.refcount = NULL;
-    tail.data.inlined.length = source->data.inlined.length - split;
+    tail.data.inlined.length = (gpr_uint8)(source->data.inlined.length - split);
     memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
            tail.data.inlined.length);
-    source->data.inlined.length = split;
+    source->data.inlined.length = (gpr_uint8)split;
   } else {
     size_t tail_length = source->data.refcounted.length - split;
     GPR_ASSERT(source->data.refcounted.length >= split);
     if (tail_length < sizeof(tail.data.inlined.bytes)) {
       /* Copy out the bytes - it'll be cheaper than refcounting */
       tail.refcount = NULL;
-      tail.data.inlined.length = tail_length;
+      tail.data.inlined.length = (gpr_uint8)tail_length;
       memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
              tail_length);
     } else {
@@ -280,16 +282,16 @@
     GPR_ASSERT(source->data.inlined.length >= split);
 
     head.refcount = NULL;
-    head.data.inlined.length = split;
+    head.data.inlined.length = (gpr_uint8)split;
     memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
-    source->data.inlined.length -= split;
+    source->data.inlined.length = (gpr_uint8)(source->data.inlined.length - split);
     memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
             source->data.inlined.length);
   } else if (split < sizeof(head.data.inlined.bytes)) {
     GPR_ASSERT(source->data.refcounted.length >= split);
 
     head.refcount = NULL;
-    head.data.inlined.length = split;
+    head.data.inlined.length = (gpr_uint8)split;
     memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
     source->data.refcounted.bytes += split;
     source->data.refcounted.length -= split;
@@ -311,7 +313,7 @@
 }
 
 int gpr_slice_cmp(gpr_slice a, gpr_slice b) {
-  int d = GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b);
+  int d = (int)(GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b));
   if (d != 0) return d;
   return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b),
                 GPR_SLICE_LENGTH(a));
@@ -319,7 +321,14 @@
 
 int gpr_slice_str_cmp(gpr_slice a, const char *b) {
   size_t b_length = strlen(b);
-  int d = GPR_SLICE_LENGTH(a) - b_length;
+  int d = (int)(GPR_SLICE_LENGTH(a) - b_length);
   if (d != 0) return d;
   return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
 }
+
+char *gpr_slice_to_cstring(gpr_slice slice) {
+  char *result = gpr_malloc(GPR_SLICE_LENGTH(slice) + 1);
+  memcpy(result, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
+  result[GPR_SLICE_LENGTH(slice)] = '\0';
+  return result;
+}
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index 91b5d8c..6e6c72a 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -81,7 +81,7 @@
   if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes))
     goto add_new;
   out = back->data.inlined.bytes + back->data.inlined.length;
-  back->data.inlined.length += n;
+  back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + n);
   return out;
 
 add_new:
@@ -89,7 +89,7 @@
   back = &sb->slices[sb->count];
   sb->count++;
   back->refcount = NULL;
-  back->data.inlined.length = n;
+  back->data.inlined.length = (gpr_uint8)n;
   return back->data.inlined.bytes;
 }
 
@@ -116,7 +116,7 @@
           GPR_SLICE_INLINED_SIZE) {
         memcpy(back->data.inlined.bytes + back->data.inlined.length,
                s.data.inlined.bytes, s.data.inlined.length);
-        back->data.inlined.length += s.data.inlined.length;
+        back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + s.data.inlined.length);
       } else {
         size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length;
         memcpy(back->data.inlined.bytes + back->data.inlined.length,
@@ -126,7 +126,7 @@
         back = &sb->slices[n];
         sb->count = n + 1;
         back->refcount = NULL;
-        back->data.inlined.length = s.data.inlined.length - cp1;
+        back->data.inlined.length = (gpr_uint8)(s.data.inlined.length - cp1);
         memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
                s.data.inlined.length - cp1);
       }
@@ -190,3 +190,19 @@
     GPR_SWAP(gpr_slice *, a->slices, b->slices);
   }
 }
+
+void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) {
+  /* anything to move? */
+  if (src->count == 0) {
+    return;
+  }
+  /* anything in dst? */
+  if (dst->count == 0) {
+    gpr_slice_buffer_swap(src, dst);
+    return;
+  }
+  /* both buffers have data - copy, and reset src */
+  gpr_slice_buffer_addn(dst, src->slices, src->count);
+  src->count = 0;
+  src->length = 0;
+}
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
new file mode 100644
index 0000000..2844330
--- /dev/null
+++ b/src/core/support/stack_lockfree.c
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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/support/stack_lockfree.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+
+/* The lockfree node structure is a single architecture-level
+   word that allows for an atomic CAS to set it up. */
+struct lockfree_node_contents {
+  /* next thing to look at. Actual index for head, next index otherwise */
+  gpr_uint16 index;
+#ifdef GPR_ARCH_64
+  gpr_uint16 pad;
+  gpr_uint32 aba_ctr;
+#else
+#ifdef GPR_ARCH_32
+  gpr_uint16 aba_ctr;
+#else
+#error Unsupported bit width architecture
+#endif
+#endif
+};
+
+/* Use a union to make sure that these are in the same bits as an atm word */
+typedef union lockfree_node {
+  gpr_atm atm;
+  struct lockfree_node_contents contents;
+} lockfree_node;
+
+#define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */
+#define INVALID_ENTRY_INDEX                        \
+  ((1 << 16) - 1) /* reserve this entry as invalid \
+                       */
+
+struct gpr_stack_lockfree {
+  lockfree_node *entries;
+  lockfree_node head; /* An atomic entry describing curr head */
+};
+
+gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
+  gpr_stack_lockfree *stack;
+  stack = gpr_malloc(sizeof(*stack));
+  /* Since we only allocate 16 bits to represent an entry number,
+   * make sure that we are within the desired range */
+  /* Reserve the highest entry number as a dummy */
+  GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
+  stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]),
+                                      ENTRY_ALIGNMENT_BITS);
+  /* Clear out all entries */
+  memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
+  memset(&stack->head, 0, sizeof(stack->head));
+
+  /* Point the head at reserved dummy entry */
+  stack->head.contents.index = INVALID_ENTRY_INDEX;
+  return stack;
+}
+
+void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) {
+  gpr_free_aligned(stack->entries);
+  gpr_free(stack);
+}
+
+int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
+  lockfree_node head;
+  lockfree_node newhead;
+
+  /* First fill in the entry's index and aba ctr for new head */
+  newhead.contents.index = (gpr_uint16)entry;
+  /* Also post-increment the aba_ctr */
+  newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++;
+
+  do {
+    /* Atomically get the existing head value for use */
+    head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
+    /* Point to it */
+    stack->entries[entry].contents.index = head.contents.index;
+  } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
+  /* Use rel_cas above to make sure that entry index is set properly */
+  return head.contents.index == INVALID_ENTRY_INDEX;
+}
+
+int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
+  lockfree_node head;
+  lockfree_node newhead;
+  do {
+    head.atm = gpr_atm_acq_load(&(stack->head.atm));
+    if (head.contents.index == INVALID_ENTRY_INDEX) {
+      return -1;
+    }
+    newhead.atm =
+        gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
+
+  } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
+  return head.contents.index;
+}
diff --git a/src/core/surface/client.h b/src/core/support/stack_lockfree.h
similarity index 66%
copy from src/core/surface/client.h
copy to src/core/support/stack_lockfree.h
index 9db2ccf..eec960f 100644
--- a/src/core/surface/client.h
+++ b/src/core/support/stack_lockfree.h
@@ -31,11 +31,21 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H
+#define GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H
 
-#include "src/core/channel/channel_stack.h"
+typedef struct gpr_stack_lockfree gpr_stack_lockfree;
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+/* This stack must specify the maximum number of entries to track.
+   The current implementation only allows up to 65534 entries */
+gpr_stack_lockfree* gpr_stack_lockfree_create(int entries);
+void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+/* Pass in a valid entry number for the next stack entry */
+/* Returns 1 if this is the first element on the stack, 0 otherwise */
+int gpr_stack_lockfree_push(gpr_stack_lockfree*, int entry);
+
+/* Returns -1 on empty or the actual entry number */
+int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);
+
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H */
diff --git a/src/core/support/string.c b/src/core/support/string.c
index bfd7ce1..9babbd9 100644
--- a/src/core/support/string.c
+++ b/src/core/support/string.c
@@ -38,6 +38,7 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/useful.h>
 
@@ -61,14 +62,14 @@
   size_t capacity;
   size_t length;
   char *data;
-} hexout;
+} dump_out;
 
-static hexout hexout_create(void) {
-  hexout r = {0, 0, NULL};
+static dump_out dump_out_create(void) {
+  dump_out r = {0, 0, NULL};
   return r;
 }
 
-static void hexout_append(hexout *out, char c) {
+static void dump_out_append(dump_out *out, char c) {
   if (out->length == out->capacity) {
     out->capacity = GPR_MAX(8, 2 * out->capacity);
     out->data = gpr_realloc(out->data, out->capacity);
@@ -76,34 +77,55 @@
   out->data[out->length++] = c;
 }
 
-char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags) {
+static void hexdump(dump_out *out, const char *buf, size_t len) {
   static const char hex[16] = "0123456789abcdef";
-  hexout out = hexout_create();
 
   const gpr_uint8 *const beg = (const gpr_uint8 *)buf;
   const gpr_uint8 *const end = beg + len;
   const gpr_uint8 *cur;
 
   for (cur = beg; cur != end; ++cur) {
-    if (cur != beg) hexout_append(&out, ' ');
-    hexout_append(&out, hex[*cur >> 4]);
-    hexout_append(&out, hex[*cur & 0xf]);
+    if (cur != beg) dump_out_append(out, ' ');
+    dump_out_append(out, hex[*cur >> 4]);
+    dump_out_append(out, hex[*cur & 0xf]);
   }
+}
 
-  if (flags & GPR_HEXDUMP_PLAINTEXT) {
-    if (len) hexout_append(&out, ' ');
-    hexout_append(&out, '\'');
-    for (cur = beg; cur != end; ++cur) {
-      hexout_append(&out, isprint(*cur) ? *cur : '.');
-    }
-    hexout_append(&out, '\'');
+static void asciidump(dump_out *out, const char *buf, size_t len) {
+  const gpr_uint8 *const beg = (const gpr_uint8 *)buf;
+  const gpr_uint8 *const end = beg + len;
+  const gpr_uint8 *cur;
+  int out_was_empty = (out->length == 0);
+  if (!out_was_empty) {
+    dump_out_append(out, ' ');
+    dump_out_append(out, '\'');
   }
+  for (cur = beg; cur != end; ++cur) {
+    dump_out_append(out, isprint(*cur) ? *(char *)cur : '.');
+  }
+  if (!out_was_empty) {
+    dump_out_append(out, '\'');
+  }
+}
 
-  hexout_append(&out, 0);
-
+char *gpr_dump(const char *buf, size_t len, gpr_uint32 flags) {
+  dump_out out = dump_out_create();
+  if (flags & GPR_DUMP_HEX) {
+    hexdump(&out, buf, len);
+  }
+  if (flags & GPR_DUMP_ASCII) {
+    asciidump(&out, buf, len);
+  }
+  dump_out_append(&out, 0);
   return out.data;
 }
 
+char *gpr_dump_slice(gpr_slice s, gpr_uint32 flags) {
+  return gpr_dump((const char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s),
+                  flags);
+}
+
+
 int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) {
   gpr_uint32 out = 0;
   gpr_uint32 new;
@@ -113,7 +135,7 @@
 
   for (i = 0; i < len; i++) {
     if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */
-    new = 10 * out + (buf[i] - '0');
+    new = 10 * out + (gpr_uint32)(buf[i] - '0');
     if (new < out) return 0; /* overflow */
     out = new;
   }
@@ -143,7 +165,7 @@
 
   if (neg) value = -value;
   while (value) {
-    string[i++] = '0' + value % 10;
+    string[i++] = (char)('0' + value % 10);
     value /= 10;
   }
   if (neg) string[i++] = '-';
@@ -153,6 +175,12 @@
 }
 
 char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
+  return gpr_strjoin_sep(strs, nstrs, "", final_length);
+}
+
+char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
+                      size_t *final_length) {
+  const size_t sep_len = strlen(sep);
   size_t out_length = 0;
   size_t i;
   char *out;
@@ -160,10 +188,17 @@
     out_length += strlen(strs[i]);
   }
   out_length += 1;  /* null terminator */
+  if (nstrs > 0) {
+    out_length += sep_len * (nstrs - 1);  /* separators */
+  }
   out = gpr_malloc(out_length);
   out_length = 0;
   for (i = 0; i < nstrs; i++) {
-    size_t slen = strlen(strs[i]);
+    const size_t slen = strlen(strs[i]);
+    if (i != 0) {
+      memcpy(out + out_length, sep, sep_len);
+      out_length += sep_len;
+    }
     memcpy(out + out_length, strs[i], slen);
     out_length += slen;
   }
@@ -174,6 +209,52 @@
   return out;
 }
 
+/** Finds the initial (\a begin) and final (\a end) offsets of the next
+ * substring from \a str + \a read_offset until the next \a sep or the end of \a
+ * str.
+ *
+ * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */
+static int slice_find_separator_offset(const gpr_slice str,
+                                       const char *sep,
+                                       const size_t read_offset,
+                                       size_t *begin,
+                                       size_t *end) {
+  size_t i;
+  const gpr_uint8 *str_ptr = GPR_SLICE_START_PTR(str) + read_offset;
+  const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset;
+  const size_t sep_len = strlen(sep);
+  if (str_len < sep_len) {
+    return 0;
+  }
+
+  for (i = 0; i <= str_len - sep_len; i++) {
+    if (memcmp(str_ptr + i, sep, sep_len) == 0) {
+      *begin = read_offset;
+      *end = read_offset + i;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) {
+  const size_t sep_len = strlen(sep);
+  size_t begin, end;
+
+  GPR_ASSERT(sep_len > 0);
+
+  if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) {
+    do {
+      gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end));
+    } while (slice_find_separator_offset(str, sep, end + sep_len, &begin,
+                                         &end) != 0);
+    gpr_slice_buffer_add_indexed(
+        dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str)));
+  } else { /* no sep found, add whole input */
+    gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str));
+  }
+}
+
 void gpr_strvec_init(gpr_strvec *sv) {
   memset(sv, 0, sizeof(*sv));
 }
diff --git a/src/core/support/string.h b/src/core/support/string.h
index 31e9fcb..3ac4abe 100644
--- a/src/core/support/string.h
+++ b/src/core/support/string.h
@@ -37,6 +37,8 @@
 #include <stddef.h>
 
 #include <grpc/support/port_platform.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/slice.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -44,12 +46,16 @@
 
 /* String utility functions */
 
-/* flag to include plaintext after a hexdump */
-#define GPR_HEXDUMP_PLAINTEXT 0x00000001
+/* Flags for gpr_dump function. */
+#define GPR_DUMP_HEX   0x00000001
+#define GPR_DUMP_ASCII 0x00000002
 
-/* Converts array buf, of length len, into a hexadecimal dump. Result should
-   be freed with gpr_free() */
-char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags);
+/* Converts array buf, of length len, into a C string  according to the flags.
+   Result should be freed with gpr_free() */
+char *gpr_dump(const char *buf, size_t len, gpr_uint32 flags);
+
+/* Calls gpr_dump on a slice. */
+char *gpr_dump_slice(gpr_slice slice, gpr_uint32 flags);
 
 /* Parses an array of bytes into an integer (base 10). Returns 1 on success,
    0 on failure. */
@@ -72,6 +78,16 @@
    if it is non-null. */
 char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length);
 
+/* Join a set of strings using a separator, returning the resulting string.
+   Total combined length (excluding null terminator) is returned in total_length
+   if it is non-null. */
+char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
+                      size_t *total_length);
+
+/** Split \a str by the separator \a sep. Results are stored in \a dst, which
+ * should be a properly initialized instance. */
+void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst);
+
 /* A vector of strings... for building up a final string one piece at a time */
 typedef struct {
   char **strs;
diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c
index 6d1d633..27b9f36 100644
--- a/src/core/support/string_win32.c
+++ b/src/core/support/string_win32.c
@@ -37,7 +37,6 @@
 
 #ifdef GPR_WIN32
 
-#include <windows.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
diff --git a/src/core/support/string_win32.h b/src/core/support/string_win32.h
index 0bc3247..1260aa5 100644
--- a/src/core/support/string_win32.h
+++ b/src/core/support/string_win32.h
@@ -38,8 +38,6 @@
 
 #ifdef GPR_WIN32
 
-#include <windows.h>
-
 /* These allocate new strings using gpr_malloc to convert from and to utf-8. */
 LPTSTR gpr_char_to_tchar(LPCSTR input);
 LPSTR gpr_tchar_to_char(LPCTSTR input);
diff --git a/src/core/support/subprocess_posix.c b/src/core/support/subprocess_posix.c
index b4631fa..171054e 100644
--- a/src/core/support/subprocess_posix.c
+++ b/src/core/support/subprocess_posix.c
@@ -66,8 +66,8 @@
   if (pid == -1) {
     return NULL;
   } else if (pid == 0) {
-    exec_args = gpr_malloc((argc + 1) * sizeof(char *));
-    memcpy(exec_args, argv, argc * sizeof(char *));
+    exec_args = gpr_malloc(((size_t)argc + 1) * sizeof(char *));
+    memcpy(exec_args, argv, (size_t)argc * sizeof(char *));
     exec_args[argc] = NULL;
     execv(exec_args[0], exec_args);
     /* if we reach here, an error has occurred */
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
index 0ccbd49..41af8ce 100644
--- a/src/core/support/sync_posix.c
+++ b/src/core/support/sync_posix.c
@@ -63,7 +63,7 @@
 
 int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
   int err = 0;
-  if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
+  if (gpr_time_cmp(abs_deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) {
     err = pthread_cond_wait(cv, mu);
   } else {
     struct timespec abs_deadline_ts;
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index cc31d9b..63196d1 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -37,9 +37,6 @@
 
 #ifdef GPR_WIN32
 
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0600
-#include <windows.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
@@ -86,10 +83,10 @@
   int timeout = 0;
   DWORD timeout_max_ms;
   mu->locked = 0;
-  if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
+  if (gpr_time_cmp(abs_deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) {
     SleepConditionVariableCS(cv, &mu->cs, INFINITE);
   } else {
-    gpr_timespec now = gpr_now();
+    gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
     gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000;
     gpr_int64 deadline_ms =
         abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
index 3cc7982..4fa3907 100644
--- a/src/core/support/thd_win32.c
+++ b/src/core/support/thd_win32.c
@@ -37,7 +37,6 @@
 
 #ifdef GPR_WIN32
 
-#include <windows.h>
 #include <string.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
diff --git a/src/core/support/time.c b/src/core/support/time.c
index 7dbf950..570f195 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -41,6 +41,7 @@
 
 int gpr_time_cmp(gpr_timespec a, gpr_timespec b) {
   int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
+  GPR_ASSERT(a.clock_type == b.clock_type);
   if (cmp == 0) {
     cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);
   }
@@ -71,70 +72,94 @@
   ((t)(TYPE_IS_SIGNED(t) ? (TOP_BIT_OF_TYPE(t) - 1) \
                          : ((TOP_BIT_OF_TYPE(t) - 1) << 1) + 1))
 
-const gpr_timespec gpr_time_0 = {0, 0};
-const gpr_timespec gpr_inf_future = {TYPE_MAX(time_t), 0};
-const gpr_timespec gpr_inf_past = {TYPE_MIN(time_t), 0};
+gpr_timespec gpr_time_0(gpr_clock_type type) {
+  gpr_timespec out;
+  out.tv_sec = 0;
+  out.tv_nsec = 0;
+  out.clock_type = type;
+  return out;
+}
+
+gpr_timespec gpr_inf_future(gpr_clock_type type) {
+  gpr_timespec out;
+  out.tv_sec = TYPE_MAX(time_t);
+  out.tv_nsec = 0;
+  out.clock_type = type;
+  return out;
+}
+
+gpr_timespec gpr_inf_past(gpr_clock_type type) {
+  gpr_timespec out;
+  out.tv_sec = TYPE_MIN(time_t);
+  out.tv_nsec = 0;
+  out.clock_type = type;
+  return out;
+}
 
 /* TODO(ctiller): consider merging _nanos, _micros, _millis into a single
    function for maintainability. Similarly for _seconds, _minutes, and _hours */
 
-gpr_timespec gpr_time_from_nanos(long ns) {
+gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
   gpr_timespec result;
+  result.clock_type = type;
   if (ns == LONG_MAX) {
-    result = gpr_inf_future;
+    result = gpr_inf_future(type);
   } else if (ns == LONG_MIN) {
-    result = gpr_inf_past;
+    result = gpr_inf_past(type);
   } else if (ns >= 0) {
     result.tv_sec = ns / GPR_NS_PER_SEC;
-    result.tv_nsec = ns - result.tv_sec * GPR_NS_PER_SEC;
+    result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC);
   } else {
     /* Calculation carefully formulated to avoid any possible under/overflow. */
     result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1;
-    result.tv_nsec = ns - result.tv_sec * GPR_NS_PER_SEC;
+    result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC);
   }
   return result;
 }
 
-gpr_timespec gpr_time_from_micros(long us) {
+gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
   gpr_timespec result;
+  result.clock_type = type;
   if (us == LONG_MAX) {
-    result = gpr_inf_future;
+    result = gpr_inf_future(type);
   } else if (us == LONG_MIN) {
-    result = gpr_inf_past;
+    result = gpr_inf_past(type);
   } else if (us >= 0) {
     result.tv_sec = us / 1000000;
-    result.tv_nsec = (us - result.tv_sec * 1000000) * 1000;
+    result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000);
   } else {
     /* Calculation carefully formulated to avoid any possible under/overflow. */
     result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1;
-    result.tv_nsec = (us - result.tv_sec * 1000000) * 1000;
+    result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000);
   }
   return result;
 }
 
-gpr_timespec gpr_time_from_millis(long ms) {
+gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
   gpr_timespec result;
+  result.clock_type = type;
   if (ms == LONG_MAX) {
-    result = gpr_inf_future;
+    result = gpr_inf_future(type);
   } else if (ms == LONG_MIN) {
-    result = gpr_inf_past;
+    result = gpr_inf_past(type);
   } else if (ms >= 0) {
     result.tv_sec = ms / 1000;
-    result.tv_nsec = (ms - result.tv_sec * 1000) * 1000000;
+    result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000);
   } else {
     /* Calculation carefully formulated to avoid any possible under/overflow. */
     result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1;
-    result.tv_nsec = (ms - result.tv_sec * 1000) * 1000000;
+    result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000);
   }
   return result;
 }
 
-gpr_timespec gpr_time_from_seconds(long s) {
+gpr_timespec gpr_time_from_seconds(long s, gpr_clock_type type) {
   gpr_timespec result;
+  result.clock_type = type;
   if (s == LONG_MAX) {
-    result = gpr_inf_future;
+    result = gpr_inf_future(type);
   } else if (s == LONG_MIN) {
-    result = gpr_inf_past;
+    result = gpr_inf_past(type);
   } else {
     result.tv_sec = s;
     result.tv_nsec = 0;
@@ -142,12 +167,13 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_minutes(long m) {
+gpr_timespec gpr_time_from_minutes(long m, gpr_clock_type type) {
   gpr_timespec result;
+  result.clock_type = type;
   if (m >= LONG_MAX / 60) {
-    result = gpr_inf_future;
+    result = gpr_inf_future(type);
   } else if (m <= LONG_MIN / 60) {
-    result = gpr_inf_past;
+    result = gpr_inf_past(type);
   } else {
     result.tv_sec = m * 60;
     result.tv_nsec = 0;
@@ -155,12 +181,13 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_hours(long h) {
+gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) {
   gpr_timespec result;
+  result.clock_type = type;
   if (h >= LONG_MAX / 3600) {
-    result = gpr_inf_future;
+    result = gpr_inf_future(type);
   } else if (h <= LONG_MIN / 3600) {
-    result = gpr_inf_past;
+    result = gpr_inf_past(type);
   } else {
     result.tv_sec = h * 3600;
     result.tv_nsec = 0;
@@ -171,6 +198,8 @@
 gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
   gpr_timespec sum;
   int inc = 0;
+  GPR_ASSERT(b.clock_type == GPR_TIMESPAN);
+  sum.clock_type = a.clock_type;
   sum.tv_nsec = a.tv_nsec + b.tv_nsec;
   if (sum.tv_nsec >= GPR_NS_PER_SEC) {
     sum.tv_nsec -= GPR_NS_PER_SEC;
@@ -180,14 +209,14 @@
     sum = a;
   } else if (b.tv_sec == TYPE_MAX(time_t) ||
              (b.tv_sec >= 0 && a.tv_sec >= TYPE_MAX(time_t) - b.tv_sec)) {
-    sum = gpr_inf_future;
+    sum = gpr_inf_future(sum.clock_type);
   } else if (b.tv_sec == TYPE_MIN(time_t) ||
              (b.tv_sec <= 0 && a.tv_sec <= TYPE_MIN(time_t) - b.tv_sec)) {
-    sum = gpr_inf_past;
+    sum = gpr_inf_past(sum.clock_type);
   } else {
     sum.tv_sec = a.tv_sec + b.tv_sec;
     if (inc != 0 && sum.tv_sec == TYPE_MAX(time_t) - 1) {
-      sum = gpr_inf_future;
+      sum = gpr_inf_future(sum.clock_type);
     } else {
       sum.tv_sec += inc;
     }
@@ -198,6 +227,12 @@
 gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
   gpr_timespec diff;
   int dec = 0;
+  if (b.clock_type == GPR_TIMESPAN) {
+    diff.clock_type = a.clock_type;
+  } else {
+    GPR_ASSERT(a.clock_type == b.clock_type);
+    diff.clock_type = GPR_TIMESPAN;
+  }
   diff.tv_nsec = a.tv_nsec - b.tv_nsec;
   if (diff.tv_nsec < 0) {
     diff.tv_nsec += GPR_NS_PER_SEC;
@@ -207,14 +242,14 @@
     diff = a;
   } else if (b.tv_sec == TYPE_MIN(time_t) ||
              (b.tv_sec <= 0 && a.tv_sec >= TYPE_MAX(time_t) + b.tv_sec)) {
-    diff = gpr_inf_future;
+    diff = gpr_inf_future(GPR_CLOCK_REALTIME);
   } else if (b.tv_sec == TYPE_MAX(time_t) ||
              (b.tv_sec >= 0 && a.tv_sec <= TYPE_MIN(time_t) + b.tv_sec)) {
-    diff = gpr_inf_past;
+    diff = gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
     diff.tv_sec = a.tv_sec - b.tv_sec;
     if (dec != 0 && diff.tv_sec == TYPE_MIN(time_t) + 1) {
-      diff = gpr_inf_past;
+      diff = gpr_inf_past(GPR_CLOCK_REALTIME);
     } else {
       diff.tv_sec -= dec;
     }
@@ -225,6 +260,9 @@
 int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) {
   int cmp_ab;
 
+  GPR_ASSERT(a.clock_type == b.clock_type);
+  GPR_ASSERT(threshold.clock_type == GPR_TIMESPAN);
+
   cmp_ab = gpr_time_cmp(a, b);
   if (cmp_ab == 0) return 1;
   if (cmp_ab < 0) {
@@ -245,10 +283,10 @@
        care?) */
     return -2147483647;
   } else {
-    return t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS;
+    return (gpr_int32)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS);
   }
 }
 
 double gpr_timespec_to_micros(gpr_timespec t) {
-  return t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
+  return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
 }
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index 3675f1e..258b2e6 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -38,6 +38,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
+#include <grpc/support/log.h>
 #include <grpc/support/time.h>
 
 static struct timespec timespec_from_gpr(gpr_timespec gts) {
@@ -48,29 +49,65 @@
 }
 
 #if _POSIX_TIMERS > 0
-static gpr_timespec gpr_from_timespec(struct timespec ts) {
+static gpr_timespec gpr_from_timespec(struct timespec ts,
+                                      gpr_clock_type clock) {
   gpr_timespec rv;
   rv.tv_sec = ts.tv_sec;
-  rv.tv_nsec = ts.tv_nsec;
+  rv.tv_nsec = (int)ts.tv_nsec;
+  rv.clock_type = clock;
   return rv;
 }
 
-gpr_timespec gpr_now(void) {
+/** maps gpr_clock_type --> clockid_t for clock_gettime */
+static clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, CLOCK_REALTIME};
+
+void gpr_time_init(void) {}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
   struct timespec now;
-  clock_gettime(CLOCK_REALTIME, &now);
-  return gpr_from_timespec(now);
+  GPR_ASSERT(clock != GPR_TIMESPAN);
+  clock_gettime(clockid_for_gpr_clock[clock], &now);
+  return gpr_from_timespec(now, clock);
 }
 #else
 /* For some reason Apple's OSes haven't implemented clock_gettime. */
 
 #include <sys/time.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
 
-gpr_timespec gpr_now(void) {
+static double g_time_scale;
+static uint64_t g_time_start;
+
+void gpr_time_init(void) {
+  mach_timebase_info_data_t tb = {0, 1};
+  mach_timebase_info(&tb);
+  g_time_scale = tb.numer;
+  g_time_scale /= tb.denom;
+  g_time_start = mach_absolute_time();
+}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
   gpr_timespec now;
   struct timeval now_tv;
-  gettimeofday(&now_tv, NULL);
-  now.tv_sec = now_tv.tv_sec;
-  now.tv_nsec = now_tv.tv_usec * 1000;
+  double now_dbl;
+
+  now.clock_type = clock;
+  switch (clock) {
+    case GPR_CLOCK_REALTIME:
+      gettimeofday(&now_tv, NULL);
+      now.tv_sec = now_tv.tv_sec;
+      now.tv_nsec = now_tv.tv_usec * 1000;
+      break;
+    case GPR_CLOCK_MONOTONIC:
+      now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale;
+      now.tv_sec = now_dbl * 1e-9;
+      now.tv_nsec = now_dbl - now.tv_sec * 1e9;
+      break;
+    case GPR_TIMESPAN:
+      abort();
+  }
+
   return now;
 }
 #endif
@@ -83,7 +120,7 @@
   for (;;) {
     /* We could simplify by using clock_nanosleep instead, but it might be
      * slightly less portable. */
-    now = gpr_now();
+    now = gpr_now(GPR_CLOCK_REALTIME);
     if (gpr_time_cmp(until, now) <= 0) {
       return;
     }
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index f4443b5..238cd07 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -39,14 +39,36 @@
 
 #include <grpc/support/time.h>
 #include <sys/timeb.h>
-#include <windows.h>
 
-gpr_timespec gpr_now(void) {
+static LARGE_INTEGER g_start_time;
+static double g_time_scale;
+
+void gpr_time_init(void) {
+  LARGE_INTEGER frequency;
+  QueryPerformanceFrequency(&frequency);
+  QueryPerformanceCounter(&g_start_time);
+  g_time_scale = 1.0 / frequency.QuadPart;
+}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
   gpr_timespec now_tv;
   struct _timeb now_tb;
-  _ftime_s(&now_tb);
-  now_tv.tv_sec = now_tb.time;
-  now_tv.tv_nsec = now_tb.millitm * 1000000;
+  LARGE_INTEGER timestamp;
+  double now_dbl;
+  now_tv.clock_type = clock;
+  switch (clock) {
+    case GPR_CLOCK_REALTIME:
+      _ftime_s(&now_tb);
+      now_tv.tv_sec = now_tb.time;
+      now_tv.tv_nsec = now_tb.millitm * 1000000;
+      break;
+    case GPR_CLOCK_MONOTONIC:
+      QueryPerformanceCounter(&timestamp);
+      now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
+      now_tv.tv_sec = (time_t)now_dbl;
+      now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9);
+      break;
+  }
   return now_tv;
 }
 
@@ -58,13 +80,14 @@
   for (;;) {
     /* We could simplify by using clock_nanosleep instead, but it might be
      * slightly less portable. */
-    now = gpr_now();
+    now = gpr_now(GPR_CLOCK_REALTIME);
     if (gpr_time_cmp(until, now) <= 0) {
       return;
     }
 
     delta = gpr_time_sub(until, now);
-    sleep_millis = (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+    sleep_millis =
+        (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
     Sleep(sleep_millis);
   }
 }
diff --git a/src/core/surface/byte_buffer.c b/src/core/surface/byte_buffer.c
index 4817e00..a930949 100644
--- a/src/core/surface/byte_buffer.c
+++ b/src/core/surface/byte_buffer.c
@@ -55,6 +55,20 @@
   return bb;
 }
 
+grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
+    grpc_byte_buffer_reader *reader) {
+  grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
+  gpr_slice slice;
+  bb->type = GRPC_BB_RAW;
+  bb->data.raw.compression = GRPC_COMPRESS_NONE;
+  gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
+
+  while (grpc_byte_buffer_reader_next(reader, &slice)) {
+    gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slice);
+  }
+  return bb;
+}
+
 grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) {
   switch (bb->type) {
     case GRPC_BB_RAW:
diff --git a/src/core/surface/byte_buffer_queue.c b/src/core/surface/byte_buffer_queue.c
index 7c31bfe..e47dc4f 100644
--- a/src/core/surface/byte_buffer_queue.c
+++ b/src/core/surface/byte_buffer_queue.c
@@ -62,6 +62,7 @@
 }
 
 void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *buffer) {
+  q->bytes += grpc_byte_buffer_length(buffer);
   bba_push(&q->filling, buffer);
 }
 
@@ -72,8 +73,11 @@
   }
 }
 
+size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q) { return q->bytes; }
+
 grpc_byte_buffer *grpc_bbq_pop(grpc_byte_buffer_queue *q) {
   grpc_bbq_array temp_array;
+  grpc_byte_buffer *out;
 
   if (q->drain_pos == q->draining.count) {
     if (q->filling.count == 0) {
@@ -87,5 +91,7 @@
     q->draining = temp_array;
   }
 
-  return q->draining.data[q->drain_pos++];
+  out = q->draining.data[q->drain_pos++];
+  q->bytes -= grpc_byte_buffer_length(out);
+  return out;
 }
diff --git a/src/core/surface/byte_buffer_queue.h b/src/core/surface/byte_buffer_queue.h
index 32c57f8..f019589 100644
--- a/src/core/surface/byte_buffer_queue.h
+++ b/src/core/surface/byte_buffer_queue.h
@@ -49,6 +49,7 @@
   size_t drain_pos;
   grpc_bbq_array filling;
   grpc_bbq_array draining;
+  size_t bytes;
 } grpc_byte_buffer_queue;
 
 void grpc_bbq_destroy(grpc_byte_buffer_queue *q);
@@ -56,5 +57,6 @@
 void grpc_bbq_flush(grpc_byte_buffer_queue *q);
 int grpc_bbq_empty(grpc_byte_buffer_queue *q);
 void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *bb);
+size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q);
 
 #endif  /* GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H */
diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c
index 86829a6..283db83 100644
--- a/src/core/surface/byte_buffer_reader.c
+++ b/src/core/surface/byte_buffer_reader.c
@@ -64,11 +64,11 @@
         grpc_msg_decompress(reader->buffer_in->data.raw.compression,
                             &reader->buffer_in->data.raw.slice_buffer,
                             &decompressed_slices_buffer);
-        reader->buffer_out = grpc_raw_byte_buffer_create(
-            decompressed_slices_buffer.slices,
-            decompressed_slices_buffer.count);
+        reader->buffer_out =
+            grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices,
+                                        decompressed_slices_buffer.count);
         gpr_slice_buffer_destroy(&decompressed_slices_buffer);
-      } else {  /* not compressed, use the input buffer as output */
+      } else { /* not compressed, use the input buffer as output */
         reader->buffer_out = reader->buffer_in;
       }
       reader->current.index = 0;
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 5cdd7cd..6e643b5 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -30,24 +30,36 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/compression.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
 #include "src/core/census/grpc_context.h"
-#include "src/core/surface/call.h"
 #include "src/core/channel/channel_stack.h"
 #include "src/core/iomgr/alarm.h"
 #include "src/core/profiling/timers.h"
 #include "src/core/support/string.h"
 #include "src/core/surface/byte_buffer_queue.h"
+#include "src/core/surface/call.h"
 #include "src/core/surface/channel.h"
 #include "src/core/surface/completion_queue.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <assert.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+/** The maximum number of completions possible.
+    Based upon the maximum number of individually queueable ops in the batch
+   api:
+      - initial metadata send
+      - message send
+      - status/close send (depending on client/server)
+      - initial metadata recv
+      - message recv
+      - status/close recv (depending on client/server) */
+#define MAX_CONCURRENT_COMPLETIONS 6
 
 typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state;
 
@@ -76,14 +88,14 @@
 typedef struct {
   /* Overall status of the operation: starts OK, may degrade to
      non-OK */
-  int success;
-  /* Completion function to call at the end of the operation */
-  grpc_ioreq_completion_func on_complete;
-  void *user_data;
+  gpr_uint8 success;
   /* a bit mask of which request ops are needed (1u << opid) */
   gpr_uint16 need_mask;
   /* a bit mask of which request ops are now completed */
   gpr_uint16 complete_mask;
+  /* Completion function to call at the end of the operation */
+  grpc_ioreq_completion_func on_complete;
+  void *user_data;
 } reqinfo_master;
 
 /* Status data for a request can come from several sources; this
@@ -99,6 +111,8 @@
   /* Status came from 'the wire' - or somewhere below the surface
      layer */
   STATUS_FROM_WIRE,
+  /* Status came from the server sending status */
+  STATUS_FROM_SERVER_STATUS,
   STATUS_SOURCE_COUNT
 } status_source;
 
@@ -133,6 +147,7 @@
   grpc_mdctx *metadata_context;
   /* TODO(ctiller): share with cq if possible? */
   gpr_mu mu;
+  gpr_mu completion_mu;
 
   /* how far through the stream have we read? */
   read_state read_state;
@@ -148,13 +163,26 @@
   gpr_uint8 receiving;
   /* are we currently completing requests */
   gpr_uint8 completing;
+  /** has grpc_call_destroy been called */
+  gpr_uint8 destroy_called;
   /* pairs with completed_requests */
   gpr_uint8 num_completed_requests;
   /* are we currently reading a message? */
   gpr_uint8 reading_message;
+  /* have we bound a pollset yet? */
+  gpr_uint8 bound_pollset;
+  /* is an error status set */
+  gpr_uint8 error_status_set;
+  /** should the alarm be cancelled */
+  gpr_uint8 cancel_alarm;
+  /** bitmask of allocated completion events in completions */
+  gpr_uint8 allocated_completions;
+
   /* flags with bits corresponding to write states allowing us to determine
      what was sent */
   gpr_uint16 last_send_contains;
+  /* cancel with this status on the next outgoing transport op */
+  grpc_status_code cancel_with_status;
 
   /* Active ioreqs.
      request_set and request_data contain one element per active ioreq
@@ -208,6 +236,9 @@
   /* Received call statuses from various sources */
   received_status status[STATUS_SOURCE_COUNT];
 
+  /* Compression algorithm for the call */
+  grpc_compression_algorithm compression_algorithm;
+
   /* Contexts for various subsystems (security, tracing, ...). */
   grpc_call_context_element context[GRPC_CONTEXT_COUNT];
 
@@ -231,6 +262,12 @@
   gpr_uint32 incoming_message_length;
   gpr_uint32 incoming_message_flags;
   grpc_iomgr_closure destroy_closure;
+  grpc_iomgr_closure on_done_recv;
+  grpc_iomgr_closure on_done_send;
+  grpc_iomgr_closure on_done_bind;
+
+  /** completion events - for completion queue use */
+  grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS];
 };
 
 #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
@@ -243,13 +280,16 @@
 static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline);
 static void call_on_done_recv(void *call, int success);
 static void call_on_done_send(void *call, int success);
-static int fill_send_ops(grpc_call *call, grpc_transport_op *op);
-static void execute_op(grpc_call *call, grpc_transport_op *op);
+static int fill_send_ops(grpc_call *call, grpc_transport_stream_op *op);
+static void execute_op(grpc_call *call, grpc_transport_stream_op *op);
 static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata);
 static void finish_read_ops(grpc_call *call);
 static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
-                                          const char *description,
-                                          gpr_uint8 locked);
+                                          const char *description);
+static void finished_loose_op(void *call, int success);
+
+static void lock(grpc_call *call);
+static void unlock(grpc_call *call);
 
 grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
                             const void *server_transport_data,
@@ -257,15 +297,19 @@
                             size_t add_initial_metadata_count,
                             gpr_timespec send_deadline) {
   size_t i;
-  grpc_transport_op initial_op;
-  grpc_transport_op *initial_op_ptr = NULL;
+  grpc_transport_stream_op initial_op;
+  grpc_transport_stream_op *initial_op_ptr = NULL;
   grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
   grpc_call *call =
       gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
   memset(call, 0, sizeof(grpc_call));
   gpr_mu_init(&call->mu);
+  gpr_mu_init(&call->completion_mu);
   call->channel = channel;
   call->cq = cq;
+  if (cq) {
+    GRPC_CQ_INTERNAL_REF(cq, "bind");
+  }
   call->is_client = server_transport_data == NULL;
   for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
     call->request_set[i] = REQSET_EMPTY;
@@ -273,8 +317,6 @@
   if (call->is_client) {
     call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE;
     call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE;
-    call->context[GRPC_CONTEXT_TRACING].value = grpc_census_context_create();
-    call->context[GRPC_CONTEXT_TRACING].destroy = grpc_census_context_destroy;
   }
   GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT);
   for (i = 0; i < add_initial_metadata_count; i++) {
@@ -282,21 +324,23 @@
   }
   call->send_initial_metadata_count = add_initial_metadata_count;
   call->send_deadline = send_deadline;
-  grpc_channel_internal_ref(channel);
+  GRPC_CHANNEL_INTERNAL_REF(channel, "call");
   call->metadata_context = grpc_channel_get_metadata_context(channel);
   grpc_sopb_init(&call->send_ops);
   grpc_sopb_init(&call->recv_ops);
   gpr_slice_buffer_init(&call->incoming_message);
-  /* dropped in destroy */
-  gpr_ref_init(&call->internal_refcount, 1);
+  grpc_iomgr_closure_init(&call->on_done_recv, call_on_done_recv, call);
+  grpc_iomgr_closure_init(&call->on_done_send, call_on_done_send, call);
+  grpc_iomgr_closure_init(&call->on_done_bind, finished_loose_op, call);
+  /* dropped in destroy and when READ_STATE_STREAM_CLOSED received */
+  gpr_ref_init(&call->internal_refcount, 2);
   /* server hack: start reads immediately so we can get initial metadata.
      TODO(ctiller): figure out a cleaner solution */
   if (!call->is_client) {
     memset(&initial_op, 0, sizeof(initial_op));
     initial_op.recv_ops = &call->recv_ops;
     initial_op.recv_state = &call->recv_state;
-    initial_op.on_done_recv = call_on_done_recv;
-    initial_op.recv_user_data = call;
+    initial_op.on_done_recv = &call->on_done_recv;
     initial_op.context = call->context;
     call->receiving = 1;
     GRPC_CALL_INTERNAL_REF(call, "receiving");
@@ -304,7 +348,7 @@
   }
   grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr,
                        CALL_STACK_FROM_CALL(call));
-  if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) {
+  if (gpr_time_cmp(send_deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) != 0) {
     set_deadline_alarm(call, send_deadline);
   }
   return call;
@@ -312,13 +356,41 @@
 
 void grpc_call_set_completion_queue(grpc_call *call,
                                     grpc_completion_queue *cq) {
+  lock(call);
   call->cq = cq;
+  if (cq) {
+    GRPC_CQ_INTERNAL_REF(cq, "bind");
+  }
+  unlock(call);
 }
 
 grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
   return call->cq;
 }
 
+static grpc_cq_completion *allocate_completion(grpc_call *call) {
+  gpr_uint8 i;
+  gpr_mu_lock(&call->completion_mu);
+  for (i = 0; i < GPR_ARRAY_SIZE(call->completions); i++) {
+    if (call->allocated_completions & (1u << i)) {
+      continue;
+    }
+    call->allocated_completions |= 1u << i;
+    gpr_mu_unlock(&call->completion_mu);
+    return &call->completions[i];
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
+
+static void done_completion(void *call, grpc_cq_completion *completion) {
+  grpc_call *c = call;
+  gpr_mu_lock(&c->completion_mu);
+  c->allocated_completions &= ~(1u << (completion - c->completions));
+  gpr_mu_unlock(&c->completion_mu);
+  GRPC_CALL_INTERNAL_UNREF(c, "completion", 1);
+}
+
 #ifdef GRPC_CALL_REF_COUNT_DEBUG
 void grpc_call_internal_ref(grpc_call *c, const char *reason) {
   gpr_log(GPR_DEBUG, "CALL:   ref %p %d -> %d [%s]", c,
@@ -333,22 +405,23 @@
   size_t i;
   grpc_call *c = call;
   grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
-  grpc_channel_internal_unref(c->channel);
+  GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call");
   gpr_mu_destroy(&c->mu);
+  gpr_mu_destroy(&c->completion_mu);
   for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
     if (c->status[i].details) {
-      grpc_mdstr_unref(c->status[i].details);
+      GRPC_MDSTR_UNREF(c->status[i].details);
     }
   }
   for (i = 0; i < c->owned_metadata_count; i++) {
-    grpc_mdelem_unref(c->owned_metadata[i]);
+    GRPC_MDELEM_UNREF(c->owned_metadata[i]);
   }
   gpr_free(c->owned_metadata);
   for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) {
     gpr_free(c->buffered_metadata[i].metadata);
   }
   for (i = 0; i < c->send_initial_metadata_count; i++) {
-    grpc_mdelem_unref(c->send_initial_metadata[i].md);
+    GRPC_MDELEM_UNREF(c->send_initial_metadata[i].md);
   }
   for (i = 0; i < GRPC_CONTEXT_COUNT; i++) {
     if (c->context[i].destroy) {
@@ -359,6 +432,9 @@
   grpc_sopb_destroy(&c->recv_ops);
   grpc_bbq_destroy(&c->incoming_queue);
   gpr_slice_buffer_destroy(&c->incoming_message);
+  if (c->cq) {
+    GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
+  }
   gpr_free(c);
 }
 
@@ -383,18 +459,31 @@
 
 static void set_status_code(grpc_call *call, status_source source,
                             gpr_uint32 status) {
+  if (call->status[source].is_set) return;
+
   call->status[source].is_set = 1;
   call->status[source].code = status;
+  call->error_status_set = status != GRPC_STATUS_OK;
 
   if (status != GRPC_STATUS_OK && !grpc_bbq_empty(&call->incoming_queue)) {
     grpc_bbq_flush(&call->incoming_queue);
   }
 }
 
+static void set_compression_algorithm(grpc_call *call,
+                                      grpc_compression_algorithm algo) {
+  call->compression_algorithm = algo;
+}
+
+grpc_compression_algorithm grpc_call_get_compression_algorithm(
+    const grpc_call *call) {
+  return call->compression_algorithm;
+}
+
 static void set_status_details(grpc_call *call, status_source source,
                                grpc_mdstr *status) {
   if (call->status[source].details != NULL) {
-    grpc_mdstr_unref(call->status[source].details);
+    GRPC_MDSTR_UNREF(call->status[source].details);
   }
   call->status[source].details = status;
 }
@@ -411,6 +500,7 @@
 
 static int need_more_data(grpc_call *call) {
   if (call->read_state == READ_STATE_STREAM_CLOSED) return 0;
+  /* TODO(ctiller): this needs some serious cleanup */
   return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) ||
          (is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) &&
           grpc_bbq_empty(&call->incoming_queue)) ||
@@ -419,23 +509,44 @@
          is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) ||
          (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) &&
           grpc_bbq_empty(&call->incoming_queue)) ||
-         (call->write_state == WRITE_STATE_INITIAL && !call->is_client);
+         (call->write_state == WRITE_STATE_INITIAL && !call->is_client) ||
+         (call->cancel_with_status != GRPC_STATUS_OK) || call->destroy_called;
 }
 
 static void unlock(grpc_call *call) {
-  grpc_transport_op op;
+  grpc_transport_stream_op op;
   completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
   int completing_requests = 0;
   int start_op = 0;
   int i;
+  const gpr_uint32 MAX_RECV_PEEK_AHEAD = 65536;
+  size_t buffered_bytes;
+  int cancel_alarm = 0;
 
   memset(&op, 0, sizeof(op));
 
+  op.cancel_with_status = call->cancel_with_status;
+  start_op = op.cancel_with_status != GRPC_STATUS_OK;
+  call->cancel_with_status = GRPC_STATUS_OK; /* reset */
+
+  cancel_alarm = call->cancel_alarm;
+  call->cancel_alarm = 0;
+
   if (!call->receiving && need_more_data(call)) {
     op.recv_ops = &call->recv_ops;
     op.recv_state = &call->recv_state;
-    op.on_done_recv = call_on_done_recv;
-    op.recv_user_data = call;
+    op.on_done_recv = &call->on_done_recv;
+    if (grpc_bbq_empty(&call->incoming_queue) && call->reading_message) {
+      op.max_recv_bytes = call->incoming_message_length -
+                          call->incoming_message.length + MAX_RECV_PEEK_AHEAD;
+    } else {
+      buffered_bytes = grpc_bbq_bytes(&call->incoming_queue);
+      if (buffered_bytes > MAX_RECV_PEEK_AHEAD) {
+        op.max_recv_bytes = 0;
+      } else {
+        op.max_recv_bytes = MAX_RECV_PEEK_AHEAD - buffered_bytes;
+      }
+    }
     call->receiving = 1;
     GRPC_CALL_INTERNAL_REF(call, "receiving");
     start_op = 1;
@@ -449,6 +560,12 @@
     }
   }
 
+  if (!call->bound_pollset && call->cq && (!call->is_client || start_op)) {
+    call->bound_pollset = 1;
+    op.bind_pollset = grpc_cq_pollset(call->cq);
+    start_op = 1;
+  }
+
   if (!call->completing && call->num_completed_requests != 0) {
     completing_requests = call->num_completed_requests;
     memcpy(completed_requests, call->completed_requests,
@@ -460,6 +577,10 @@
 
   gpr_mu_unlock(&call->mu);
 
+  if (cancel_alarm) {
+    grpc_alarm_cancel(&call->alarm);
+  }
+
   if (start_op) {
     execute_op(call, &op);
   }
@@ -551,10 +672,18 @@
             call->write_state = WRITE_STATE_WRITE_CLOSED;
           }
           break;
+        case GRPC_IOREQ_SEND_STATUS:
+          if (call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details !=
+              NULL) {
+            GRPC_MDSTR_UNREF(
+                call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details);
+            call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details =
+                NULL;
+          }
+          break;
         case GRPC_IOREQ_RECV_CLOSE:
         case GRPC_IOREQ_SEND_INITIAL_METADATA:
         case GRPC_IOREQ_SEND_TRAILING_METADATA:
-        case GRPC_IOREQ_SEND_STATUS:
         case GRPC_IOREQ_SEND_CLOSE:
           break;
         case GRPC_IOREQ_RECV_STATUS:
@@ -637,13 +766,23 @@
 }
 
 static void finish_message(grpc_call *call) {
-  /* TODO(ctiller): this could be a lot faster if coded directly */
-  grpc_byte_buffer *byte_buffer = grpc_raw_byte_buffer_create(
-      call->incoming_message.slices, call->incoming_message.count);
+  if (call->error_status_set == 0) {
+    /* TODO(ctiller): this could be a lot faster if coded directly */
+    grpc_byte_buffer *byte_buffer;
+    /* some aliases for readability */
+    gpr_slice *slices = call->incoming_message.slices;
+    const size_t nslices = call->incoming_message.count;
+
+    if ((call->incoming_message_flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
+        (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
+      byte_buffer = grpc_raw_compressed_byte_buffer_create(
+          slices, nslices, call->compression_algorithm);
+    } else {
+      byte_buffer = grpc_raw_byte_buffer_create(slices, nslices);
+    }
+    grpc_bbq_push(&call->incoming_queue, byte_buffer);
+  }
   gpr_slice_buffer_reset_and_unref(&call->incoming_message);
-
-  grpc_bbq_push(&call->incoming_queue, byte_buffer);
-
   GPR_ASSERT(call->incoming_message.count == 0);
   call->reading_message = 0;
 }
@@ -655,7 +794,26 @@
     gpr_asprintf(
         &message, "Message terminated early; read %d bytes, expected %d",
         (int)call->incoming_message.length, (int)call->incoming_message_length);
-    cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message, 1);
+    cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
+    gpr_free(message);
+    return 0;
+  }
+  /* sanity check: if message flags indicate a compressed message, the
+   * compression level should already be present in the call, as parsed off its
+   * corresponding metadata. */
+  if ((msg.flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
+      (call->compression_algorithm == GRPC_COMPRESS_NONE)) {
+    char *message = NULL;
+    char *alg_name;
+    if (!grpc_compression_algorithm_name(call->compression_algorithm,
+                                         &alg_name)) {
+      /* This shouldn't happen, other than due to data corruption */
+      alg_name = "<unknown>";
+    }
+    gpr_asprintf(&message,
+                 "Invalid compression algorithm (%s) for compressed message.",
+                 alg_name);
+    cancel_with_status(call, GRPC_STATUS_INTERNAL, message);
     gpr_free(message);
     return 0;
   }
@@ -666,7 +824,7 @@
         &message,
         "Maximum message length of %d exceeded by a message of length %d",
         grpc_channel_get_max_message_length(call->channel), msg.length);
-    cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message, 1);
+    cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
     gpr_free(message);
     return 0;
   } else if (msg.length > 0) {
@@ -688,7 +846,7 @@
   /* we have to be reading a message to know what to do here */
   if (!call->reading_message) {
     cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT,
-                       "Received payload data while not reading a message", 1);
+                       "Received payload data while not reading a message");
     return 0;
   }
   /* append the slice to the incoming buffer */
@@ -699,7 +857,7 @@
     gpr_asprintf(
         &message, "Receiving message overflow; read %d bytes, expected %d",
         (int)call->incoming_message.length, (int)call->incoming_message_length);
-    cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message, 1);
+    cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
     gpr_free(message);
     return 0;
   } else if (call->incoming_message.length == call->incoming_message_length) {
@@ -744,10 +902,8 @@
     if (call->recv_state == GRPC_STREAM_CLOSED) {
       GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED);
       call->read_state = READ_STATE_STREAM_CLOSED;
-      if (call->have_alarm) {
-        grpc_alarm_cancel(&call->alarm);
-        call->have_alarm = 0;
-      }
+      call->cancel_alarm |= call->have_alarm;
+      GRPC_CALL_INTERNAL_UNREF(call, "closed", 0);
     }
     finish_read_ops(call);
   } else {
@@ -819,7 +975,7 @@
   }
 }
 
-static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
+static int fill_send_ops(grpc_call *call, grpc_transport_stream_op *op) {
   grpc_ioreq_data data;
   gpr_uint32 flags;
   grpc_metadata_batch mdb;
@@ -841,7 +997,6 @@
       }
       grpc_sopb_add_metadata(&call->send_ops, mdb);
       op->send_ops = &call->send_ops;
-      op->bind_pollset = grpc_cq_pollset(call->cq);
       call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA;
       call->send_initial_metadata_count = 0;
     /* fall through intended */
@@ -865,7 +1020,7 @@
           mdb.list = chain_metadata_from_app(call, data.send_metadata.count,
                                              data.send_metadata.metadata);
           mdb.garbage.head = mdb.garbage.tail = NULL;
-          mdb.deadline = gpr_inf_future;
+          mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
           /* send status */
           /* TODO(ctiller): cache common status values */
           data = call->request_data[GRPC_IOREQ_SEND_STATUS];
@@ -878,10 +1033,11 @@
                 &mdb, &call->details_link,
                 grpc_mdelem_from_metadata_strings(
                     call->metadata_context,
-                    grpc_mdstr_ref(
+                    GRPC_MDSTR_REF(
                         grpc_channel_get_message_string(call->channel)),
-                    grpc_mdstr_from_string(call->metadata_context,
-                                           data.send_status.details)));
+                    data.send_status.details));
+            call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details =
+                NULL;
           }
           grpc_sopb_add_metadata(&call->send_ops, mdb);
         }
@@ -891,8 +1047,7 @@
       break;
   }
   if (op->send_ops) {
-    op->on_done_send = call_on_done_send;
-    op->send_user_data = call;
+    op->on_done_send = &call->on_done_send;
   }
   return op->send_ops != NULL;
 }
@@ -926,7 +1081,7 @@
 
   switch (call->read_state) {
     case READ_STATE_STREAM_CLOSED:
-      if (empty) {
+      if (empty && !call->have_alarm) {
         finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, 1);
       }
     /* fallthrough */
@@ -981,6 +1136,14 @@
                                  GRPC_CALL_ERROR_INVALID_METADATA);
       }
     }
+    if (op == GRPC_IOREQ_SEND_STATUS) {
+      set_status_code(call, STATUS_FROM_SERVER_STATUS,
+                      reqs[i].data.send_status.code);
+      if (reqs[i].data.send_status.details) {
+        set_status_details(call, STATUS_FROM_SERVER_STATUS,
+                           GRPC_MDSTR_REF(reqs[i].data.send_status.details));
+      }
+    }
     have_ops |= 1u << op;
 
     call->request_data[op] = data;
@@ -1014,10 +1177,9 @@
 void grpc_call_destroy(grpc_call *c) {
   int cancel;
   lock(c);
-  if (c->have_alarm) {
-    grpc_alarm_cancel(&c->alarm);
-    c->have_alarm = 0;
-  }
+  GPR_ASSERT(!c->destroy_called);
+  c->destroy_called = 1;
+  c->cancel_alarm |= c->have_alarm;
   cancel = c->read_state != READ_STATE_STREAM_CLOSED;
   unlock(c);
   if (cancel) grpc_call_cancel(c);
@@ -1031,38 +1193,64 @@
 grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
                                              grpc_status_code status,
                                              const char *description) {
-  return cancel_with_status(c, status, description, 0);
+  grpc_call_error r;
+  lock(c);
+  r = cancel_with_status(c, status, description);
+  unlock(c);
+  return r;
 }
 
 static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
-                                          const char *description,
-                                          gpr_uint8 locked) {
-  grpc_transport_op op;
+                                          const char *description) {
   grpc_mdstr *details =
       description ? grpc_mdstr_from_string(c->metadata_context, description)
                   : NULL;
-  memset(&op, 0, sizeof(op));
-  op.cancel_with_status = status;
 
-  if (locked == 0) {
-    lock(c);
-  }
+  GPR_ASSERT(status != GRPC_STATUS_OK);
+
   set_status_code(c, STATUS_FROM_API_OVERRIDE, status);
   set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
-  if (locked == 0) {
-    unlock(c);
-  }
 
-  execute_op(c, &op);
+  c->cancel_with_status = status;
 
   return GRPC_CALL_OK;
 }
 
-static void execute_op(grpc_call *call, grpc_transport_op *op) {
+static void finished_loose_op(void *call, int success_ignored) {
+  GRPC_CALL_INTERNAL_UNREF(call, "loose-op", 0);
+}
+
+typedef struct {
+  grpc_call *call;
+  grpc_iomgr_closure closure;
+} finished_loose_op_allocated_args;
+
+static void finished_loose_op_allocated(void *alloc, int success) {
+  finished_loose_op_allocated_args *args = alloc;
+  finished_loose_op(args->call, success);
+  gpr_free(args);
+}
+
+static void execute_op(grpc_call *call, grpc_transport_stream_op *op) {
   grpc_call_element *elem;
+
+  GPR_ASSERT(op->on_consumed == NULL);
+  if (op->cancel_with_status != GRPC_STATUS_OK || op->bind_pollset) {
+    GRPC_CALL_INTERNAL_REF(call, "loose-op");
+    if (op->bind_pollset) {
+      op->on_consumed = &call->on_done_bind;
+    } else {
+      finished_loose_op_allocated_args *args = gpr_malloc(sizeof(*args));
+      args->call = call;
+      grpc_iomgr_closure_init(&args->closure, finished_loose_op_allocated,
+                              args);
+      op->on_consumed = &args->closure;
+    }
+  }
+
   elem = CALL_ELEM_FROM_CALL(call, 0);
   op->context = call->context;
-  elem->filter->start_transport_op(elem, op);
+  elem->filter->start_transport_stream_op(elem, op);
 }
 
 grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
@@ -1071,14 +1259,14 @@
 
 static void call_alarm(void *arg, int success) {
   grpc_call *call = arg;
+  lock(call);
+  call->have_alarm = 0;
   if (success) {
-    if (call->is_client) {
-      cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
-                         "Deadline Exceeded", 0);
-    } else {
-      grpc_call_cancel(call);
-    }
+    cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
+                       "Deadline Exceeded");
   }
+  finish_read_ops(call);
+  unlock(call);
   GRPC_CALL_INTERNAL_UNREF(call, "alarm", 1);
 }
 
@@ -1090,7 +1278,8 @@
   }
   GRPC_CALL_INTERNAL_REF(call, "alarm");
   call->have_alarm = 1;
-  grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now());
+  grpc_alarm_init(&call->alarm, deadline, call_alarm, call,
+                  gpr_now(GPR_CLOCK_REALTIME));
 }
 
 /* we offset status by a small amount when storing it into transport metadata
@@ -1116,6 +1305,28 @@
   return status;
 }
 
+/* just as for status above, we need to offset: metadata userdata can't hold a
+ * zero (null), which in this case is used to signal no compression */
+#define COMPRESS_OFFSET 1
+static void destroy_compression(void *ignored) {}
+
+static gpr_uint32 decode_compression(grpc_mdelem *md) {
+  grpc_compression_algorithm algorithm;
+  void *user_data = grpc_mdelem_get_user_data(md, destroy_compression);
+  if (user_data) {
+    algorithm = ((grpc_compression_level)(gpr_intptr)user_data) - COMPRESS_OFFSET;
+  } else {
+    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
+    if (!grpc_compression_algorithm_parse(md_c_str, &algorithm)) {
+      gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
+      assert(0);
+    }
+    grpc_mdelem_set_user_data(md, destroy_compression,
+                              (void *)(gpr_intptr)(algorithm + COMPRESS_OFFSET));
+  }
+  return algorithm;
+}
+
 static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
   grpc_linked_mdelem *l;
   grpc_metadata_array *dest;
@@ -1130,7 +1341,10 @@
     if (key == grpc_channel_get_status_string(call->channel)) {
       set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
     } else if (key == grpc_channel_get_message_string(call->channel)) {
-      set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
+      set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(md->value));
+    } else if (key ==
+               grpc_channel_get_compression_algorithm_string(call->channel)) {
+      set_compression_algorithm(call, decode_compression(md));
     } else {
       dest = &call->buffered_metadata[is_trailing];
       if (dest->count == dest->capacity) {
@@ -1154,7 +1368,7 @@
       l->md = 0;
     }
   }
-  if (gpr_time_cmp(md->deadline, gpr_inf_future) != 0) {
+  if (gpr_time_cmp(md->deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) != 0) {
     set_deadline_alarm(call, md->deadline);
   }
   if (!is_trailing) {
@@ -1163,10 +1377,10 @@
 
   grpc_mdctx_lock(mdctx);
   for (l = md->list.head; l; l = l->next) {
-    if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+    if (l->md) GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md);
   }
   for (l = md->garbage.head; l; l = l->next) {
-    grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+    GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md);
   }
   grpc_mdctx_unlock(mdctx);
 }
@@ -1188,11 +1402,13 @@
 }
 
 static void finish_batch(grpc_call *call, int success, void *tag) {
-  grpc_cq_end_op(call->cq, tag, call, success);
+  grpc_cq_end_op(call->cq, tag, success, done_completion, call,
+                 allocate_completion(call));
 }
 
 static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
-  grpc_cq_end_op(call->cq, tag, call, 1);
+  grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
+                 allocate_completion(call));
 }
 
 static int are_write_flags_valid(gpr_uint32 flags) {
@@ -1215,8 +1431,10 @@
   GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
 
   if (nops == 0) {
-    grpc_cq_begin_op(call->cq, call);
-    grpc_cq_end_op(call->cq, tag, call, 1);
+    grpc_cq_begin_op(call->cq);
+    GRPC_CALL_INTERNAL_REF(call, "completion");
+    grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
+                   allocate_completion(call));
     return GRPC_CALL_OK;
   }
 
@@ -1235,13 +1453,13 @@
         req->flags = op->flags;
         break;
       case GRPC_OP_SEND_MESSAGE:
-        if (!are_write_flags_valid(op->flags)){
+        if (!are_write_flags_valid(op->flags)) {
           return GRPC_CALL_ERROR_INVALID_FLAGS;
         }
         req = &reqs[out++];
         req->op = GRPC_IOREQ_SEND_MESSAGE;
         req->data.send_message = op->data.send_message;
-        req->flags = ops->flags;
+        req->flags = op->flags;
         break;
       case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
         /* Flag validation: currently allow no flags */
@@ -1270,7 +1488,11 @@
         req->op = GRPC_IOREQ_SEND_STATUS;
         req->data.send_status.code = op->data.send_status_from_server.status;
         req->data.send_status.details =
-            op->data.send_status_from_server.status_details;
+            op->data.send_status_from_server.status_details != NULL
+                ? grpc_mdstr_from_string(
+                      call->metadata_context,
+                      op->data.send_status_from_server.status_details)
+                : NULL;
         req = &reqs[out++];
         req->op = GRPC_IOREQ_SEND_CLOSE;
         break;
@@ -1334,7 +1556,8 @@
     }
   }
 
-  grpc_cq_begin_op(call->cq, call);
+  GRPC_CALL_INTERNAL_REF(call, "completion");
+  grpc_cq_begin_op(call->cq);
 
   return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func, tag);
 }
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 7a14161..3b6f9c9 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -72,14 +72,14 @@
   grpc_byte_buffer *send_message;
   struct {
     grpc_status_code code;
-    const char *details;
+    grpc_mdstr *details;
   } send_status;
 } grpc_ioreq_data;
 
 typedef struct {
   grpc_ioreq_op op;
+  gpr_uint32 flags; /**< A copy of the write flags from grpc_op */
   grpc_ioreq_data data;
-  gpr_uint32 flags;  /**< A copy of the write flags from grpc_op */
 } grpc_ioreq;
 
 typedef void (*grpc_ioreq_completion_func)(grpc_call *call, int success,
@@ -96,8 +96,10 @@
 
 #ifdef GRPC_CALL_REF_COUNT_DEBUG
 void grpc_call_internal_ref(grpc_call *call, const char *reason);
-void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion);
-#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call, reason)
+void grpc_call_internal_unref(grpc_call *call, const char *reason,
+                              int allow_immediate_deletion);
+#define GRPC_CALL_INTERNAL_REF(call, reason) \
+  grpc_call_internal_ref(call, reason)
 #define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) \
   grpc_call_internal_unref(call, reason, allow_immediate_deletion)
 #else
@@ -125,8 +127,7 @@
 
 void grpc_server_log_request_call(char *file, int line,
                                   gpr_log_severity severity,
-                                  grpc_server *server,
-                                  grpc_call **call,
+                                  grpc_server *server, grpc_call **call,
                                   grpc_call_details *details,
                                   grpc_metadata_array *initial_metadata,
                                   grpc_completion_queue *cq_bound_to_call,
@@ -135,16 +136,20 @@
 
 /* Set a context pointer.
    No thread safety guarantees are made wrt this value. */
-void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value,
-                           void (*destroy)(void *value));
+void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
+                           void *value, void (*destroy)(void *value));
 /* Get a context pointer. */
 void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
 
 #define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \
   if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag)
 
-#define GRPC_SERVER_LOG_REQUEST_CALL(sev, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notifications, tag) \
-  if (grpc_trace_batch) grpc_server_log_request_call(sev, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notifications, tag)
+#define GRPC_SERVER_LOG_REQUEST_CALL(sev, server, call, details,             \
+                                     initial_metadata, cq_bound_to_call,     \
+                                     cq_for_notifications, tag)              \
+  if (grpc_trace_batch)                                                      \
+  grpc_server_log_request_call(sev, server, call, details, initial_metadata, \
+                               cq_bound_to_call, cq_for_notifications, tag)
 
 gpr_uint8 grpc_call_is_client(grpc_call *call);
 
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
index 5566329..997046d 100644
--- a/src/core/surface/call_log_batch.c
+++ b/src/core/surface/call_log_batch.c
@@ -46,8 +46,8 @@
     gpr_strvec_add(b, gpr_strdup(md[i].key));
 
     gpr_strvec_add(b, gpr_strdup(" value="));
-    gpr_strvec_add(b, gpr_hexdump(md[i].value, md[i].value_length,
-                                  GPR_HEXDUMP_PLAINTEXT));
+    gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length,
+                               GPR_DUMP_HEX | GPR_DUMP_ASCII));
   }
 }
 
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 9175ad0..a6438ff 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -39,7 +39,6 @@
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/support/string.h"
 #include "src/core/surface/call.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/init.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -64,6 +63,7 @@
   grpc_mdctx *metadata_context;
   /** mdstr for the grpc-status key */
   grpc_mdstr *grpc_status_string;
+  grpc_mdstr *grpc_compression_algorithm_string;
   grpc_mdstr *grpc_message_string;
   grpc_mdstr *path_string;
   grpc_mdstr *authority_string;
@@ -91,25 +91,25 @@
   size_t size =
       sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
   grpc_channel *channel = gpr_malloc(size);
+  memset(channel, 0, sizeof(*channel));
   GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
   channel->is_client = is_client;
-  /* decremented by grpc_channel_destroy, and grpc_client_channel_closed if
-   * is_client */
-  gpr_ref_init(&channel->refs, 1 + is_client);
+  /* decremented by grpc_channel_destroy */
+  gpr_ref_init(&channel->refs, 1);
   channel->metadata_context = mdctx;
   channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
+  channel->grpc_compression_algorithm_string =
+      grpc_mdstr_from_string(mdctx, "grpc-encoding");
   channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
   for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
     char buf[GPR_LTOA_MIN_BUFSIZE];
     gpr_ltoa(i, buf);
     channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings(
-        mdctx, grpc_mdstr_ref(channel->grpc_status_string),
+        mdctx, GRPC_MDSTR_REF(channel->grpc_status_string),
         grpc_mdstr_from_string(mdctx, buf));
   }
   channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
   channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
-  grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context,
-                          CHANNEL_STACK_FROM_CHANNEL(channel));
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = NULL;
 
@@ -130,6 +130,10 @@
     }
   }
 
+  grpc_channel_stack_init(filters, num_filters, channel, args,
+                          channel->metadata_context,
+                          CHANNEL_STACK_FROM_CHANNEL(channel));
+
   return channel;
 }
 
@@ -154,10 +158,10 @@
   return grpc_channel_create_call_internal(
       channel, cq,
       grpc_mdelem_from_metadata_strings(
-          channel->metadata_context, grpc_mdstr_ref(channel->path_string),
+          channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
           grpc_mdstr_from_string(channel->metadata_context, method)),
       grpc_mdelem_from_metadata_strings(
-          channel->metadata_context, grpc_mdstr_ref(channel->authority_string),
+          channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
           grpc_mdstr_from_string(channel->metadata_context, host)),
       deadline);
 }
@@ -166,10 +170,10 @@
                                  const char *host) {
   registered_call *rc = gpr_malloc(sizeof(registered_call));
   rc->path = grpc_mdelem_from_metadata_strings(
-      channel->metadata_context, grpc_mdstr_ref(channel->path_string),
+      channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
       grpc_mdstr_from_string(channel->metadata_context, method));
   rc->authority = grpc_mdelem_from_metadata_strings(
-      channel->metadata_context, grpc_mdstr_ref(channel->authority_string),
+      channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
       grpc_mdstr_from_string(channel->metadata_context, host));
   gpr_mu_lock(&channel->registered_call_mu);
   rc->next = channel->registered_calls;
@@ -183,12 +187,18 @@
     void *registered_call_handle, gpr_timespec deadline) {
   registered_call *rc = registered_call_handle;
   return grpc_channel_create_call_internal(
-      channel, completion_queue, grpc_mdelem_ref(rc->path),
-      grpc_mdelem_ref(rc->authority), deadline);
+      channel, completion_queue, GRPC_MDELEM_REF(rc->path),
+      GRPC_MDELEM_REF(rc->authority), deadline);
 }
 
-void grpc_channel_internal_ref(grpc_channel *channel) {
-  gpr_ref(&channel->refs);
+#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
+void grpc_channel_internal_ref(grpc_channel *c, const char *reason) {
+  gpr_log(GPR_DEBUG, "CHANNEL:   ref %p %d -> %d [%s]", c, c->refs.count,
+          c->refs.count + 1, reason);
+#else
+void grpc_channel_internal_ref(grpc_channel *c) {
+#endif
+  gpr_ref(&c->refs);
 }
 
 static void destroy_channel(void *p, int ok) {
@@ -196,17 +206,18 @@
   size_t i;
   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
   for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
-    grpc_mdelem_unref(channel->grpc_status_elem[i]);
+    GRPC_MDELEM_UNREF(channel->grpc_status_elem[i]);
   }
-  grpc_mdstr_unref(channel->grpc_status_string);
-  grpc_mdstr_unref(channel->grpc_message_string);
-  grpc_mdstr_unref(channel->path_string);
-  grpc_mdstr_unref(channel->authority_string);
+  GRPC_MDSTR_UNREF(channel->grpc_status_string);
+  GRPC_MDSTR_UNREF(channel->grpc_compression_algorithm_string);
+  GRPC_MDSTR_UNREF(channel->grpc_message_string);
+  GRPC_MDSTR_UNREF(channel->path_string);
+  GRPC_MDSTR_UNREF(channel->authority_string);
   while (channel->registered_calls) {
     registered_call *rc = channel->registered_calls;
     channel->registered_calls = rc->next;
-    grpc_mdelem_unref(rc->path);
-    grpc_mdelem_unref(rc->authority);
+    GRPC_MDELEM_UNREF(rc->path);
+    GRPC_MDELEM_UNREF(rc->authority);
     gpr_free(rc);
   }
   grpc_mdctx_unref(channel->metadata_context);
@@ -214,7 +225,13 @@
   gpr_free(channel);
 }
 
+#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
+void grpc_channel_internal_unref(grpc_channel *channel, const char *reason) {
+  gpr_log(GPR_DEBUG, "CHANNEL: unref %p %d -> %d [%s]", channel,
+          channel->refs.count, channel->refs.count - 1, reason);
+#else
 void grpc_channel_internal_unref(grpc_channel *channel) {
+#endif
   if (gpr_unref(&channel->refs)) {
     channel->destroy_closure.cb = destroy_channel;
     channel->destroy_closure.cb_arg = channel;
@@ -223,26 +240,14 @@
 }
 
 void grpc_channel_destroy(grpc_channel *channel) {
-  grpc_channel_op op;
+  grpc_transport_op op;
   grpc_channel_element *elem;
-
+  memset(&op, 0, sizeof(op));
+  op.disconnect = 1;
   elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
+  elem->filter->start_transport_op(elem, &op);
 
-  op.type = GRPC_CHANNEL_GOAWAY;
-  op.dir = GRPC_CALL_DOWN;
-  op.data.goaway.status = GRPC_STATUS_OK;
-  op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect");
-  elem->filter->channel_op(elem, NULL, &op);
-
-  op.type = GRPC_CHANNEL_DISCONNECT;
-  op.dir = GRPC_CALL_DOWN;
-  elem->filter->channel_op(elem, NULL, &op);
-
-  grpc_channel_internal_unref(channel);
-}
-
-void grpc_client_channel_closed(grpc_channel_element *elem) {
-  grpc_channel_internal_unref(CHANNEL_FROM_TOP_ELEM(elem));
+  GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
 }
 
 grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
@@ -257,14 +262,19 @@
   return channel->grpc_status_string;
 }
 
+grpc_mdstr *grpc_channel_get_compression_algorithm_string(
+    grpc_channel *channel) {
+  return channel->grpc_compression_algorithm_string;
+}
+
 grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
   if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
-    return grpc_mdelem_ref(channel->grpc_status_elem[i]);
+    return GRPC_MDELEM_REF(channel->grpc_status_elem[i]);
   } else {
     char tmp[GPR_LTOA_MIN_BUFSIZE];
     gpr_ltoa(i, tmp);
     return grpc_mdelem_from_metadata_strings(
-        channel->metadata_context, grpc_mdstr_ref(channel->grpc_status_string),
+        channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string),
         grpc_mdstr_from_string(channel->metadata_context, tmp));
   }
 }
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index 6d1ed87..4e03eb4 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H
 
 #include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/subchannel_factory.h"
 
 grpc_channel *grpc_channel_create_from_filters(
     const grpc_channel_filter **filters, size_t count,
@@ -53,12 +54,25 @@
 grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
                                                  int status_code);
 grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
+grpc_mdstr *grpc_channel_get_compression_algorithm_string(
+    grpc_channel *channel);
 grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
 gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
 
-void grpc_client_channel_closed(grpc_channel_element *elem);
-
+#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
+void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
+void grpc_channel_internal_unref(grpc_channel *channel, const char *reason);
+#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
+  grpc_channel_internal_ref(channel, reason)
+#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
+  grpc_channel_internal_unref(channel, reason)
+#else
 void grpc_channel_internal_ref(grpc_channel *channel);
 void grpc_channel_internal_unref(grpc_channel *channel);
+#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
+  grpc_channel_internal_ref(channel)
+#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
+  grpc_channel_internal_unref(channel)
+#endif
 
 #endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 946ee09..91c7b35 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -31,157 +31,121 @@
  *
  */
 
-#include "src/core/iomgr/sockaddr.h"
-
 #include <grpc/grpc.h>
 
 #include <stdlib.h>
 #include <string.h>
 
-#include "src/core/channel/census_filter.h"
+#include <grpc/support/alloc.h>
+
 #include "src/core/channel/channel_args.h"
 #include "src/core/channel/client_channel.h"
-#include "src/core/channel/client_setup.h"
-#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/compress_filter.h"
 #include "src/core/channel/http_client_filter.h"
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/resolve_address.h"
+#include "src/core/client_config/resolver_registry.h"
 #include "src/core/iomgr/tcp_client.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
-#include "src/core/support/string.h"
 #include "src/core/transport/chttp2_transport.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 
-typedef struct setup setup;
-
-/* A single setup request (started via initiate) */
 typedef struct {
-  grpc_client_setup_request *cs_request;
-  setup *setup;
-  /* Resolved addresses, or null if resolution not yet completed */
-  grpc_resolved_addresses *resolved;
-  /* which address in resolved should we pick for the next connection attempt */
-  size_t resolved_index;
-} request;
+  grpc_connector base;
+  gpr_refcount refs;
 
-/* Global setup logic (may be running many simultaneous setup requests, but
-   with only one 'active' */
-struct setup {
-  const char *target;
-  grpc_transport_setup_callback setup_callback;
-  void *setup_user_data;
-};
+  grpc_iomgr_closure *notify;
+  grpc_connect_in_args args;
+  grpc_connect_out_args *result;
+} connector;
 
-static int maybe_try_next_resolved(request *r);
-
-static void done(request *r, int was_successful) {
-  grpc_client_setup_request_finish(r->cs_request, was_successful);
-  if (r->resolved) {
-    grpc_resolved_addresses_destroy(r->resolved);
-  }
-  gpr_free(r);
+static void connector_ref(grpc_connector *con) {
+  connector *c = (connector *)con;
+  gpr_ref(&c->refs);
 }
 
-/* connection callback: tcp is either valid, or null on error */
-static void on_connect(void *rp, grpc_endpoint *tcp) {
-  request *r = rp;
-
-  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
-    if (tcp) {
-      grpc_endpoint_shutdown(tcp);
-      grpc_endpoint_destroy(tcp);
-    }
-    done(r, 0);
-    return;
+static void connector_unref(grpc_connector *con) {
+  connector *c = (connector *)con;
+  if (gpr_unref(&c->refs)) {
+    gpr_free(c);
   }
+}
 
-  if (!tcp) {
-    if (!maybe_try_next_resolved(r)) {
-      done(r, 0);
-      return;
-    } else {
-      return;
-    }
-  } else if (grpc_client_setup_cb_begin(r->cs_request)) {
-    grpc_create_chttp2_transport(
-        r->setup->setup_callback, r->setup->setup_user_data,
-        grpc_client_setup_get_channel_args(r->cs_request), tcp, NULL, 0,
-        grpc_client_setup_get_mdctx(r->cs_request), 1);
-    grpc_client_setup_cb_end(r->cs_request);
-    done(r, 1);
-    return;
+static void connected(void *arg, grpc_endpoint *tcp) {
+  connector *c = arg;
+  grpc_iomgr_closure *notify;
+  if (tcp != NULL) {
+    c->result->transport = grpc_create_chttp2_transport(
+        c->args.channel_args, tcp, c->args.metadata_context, 1);
+    grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0);
+    GPR_ASSERT(c->result->transport);
+    c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *));
+    c->result->filters[0] = &grpc_http_client_filter;
+    c->result->num_filters = 1;
   } else {
-    done(r, 0);
+    memset(c->result, 0, sizeof(*c->result));
+  }
+  notify = c->notify;
+  c->notify = NULL;
+  grpc_iomgr_add_callback(notify);
+}
+
+static void connector_connect(grpc_connector *con,
+                              const grpc_connect_in_args *args,
+                              grpc_connect_out_args *result,
+                              grpc_iomgr_closure *notify) {
+  connector *c = (connector *)con;
+  GPR_ASSERT(c->notify == NULL);
+  GPR_ASSERT(notify->cb);
+  c->notify = notify;
+  c->args = *args;
+  c->result = result;
+  grpc_tcp_client_connect(connected, c, args->interested_parties, args->addr,
+                          args->addr_len, args->deadline);
+}
+
+static const grpc_connector_vtable connector_vtable = {
+    connector_ref, connector_unref, connector_connect};
+
+typedef struct {
+  grpc_subchannel_factory base;
+  gpr_refcount refs;
+  grpc_mdctx *mdctx;
+  grpc_channel_args *merge_args;
+} subchannel_factory;
+
+static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  gpr_ref(&f->refs);
+}
+
+static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  if (gpr_unref(&f->refs)) {
+    grpc_channel_args_destroy(f->merge_args);
+    grpc_mdctx_unref(f->mdctx);
+    gpr_free(f);
   }
 }
 
-/* attempt to connect to the next available resolved address */
-static int maybe_try_next_resolved(request *r) {
-  grpc_resolved_address *addr;
-  if (!r->resolved) return 0;
-  if (r->resolved_index == r->resolved->naddrs) return 0;
-  addr = &r->resolved->addrs[r->resolved_index++];
-  grpc_tcp_client_connect(on_connect, r, (struct sockaddr *)&addr->addr,
-                          addr->len,
-                          grpc_client_setup_request_deadline(r->cs_request));
-  return 1;
+static grpc_subchannel *subchannel_factory_create_subchannel(
+    grpc_subchannel_factory *scf, grpc_subchannel_args *args) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  connector *c = gpr_malloc(sizeof(*c));
+  grpc_channel_args *final_args =
+      grpc_channel_args_merge(args->args, f->merge_args);
+  grpc_subchannel *s;
+  memset(c, 0, sizeof(*c));
+  c->base.vtable = &connector_vtable;
+  gpr_ref_init(&c->refs, 1);
+  args->mdctx = f->mdctx;
+  args->args = final_args;
+  s = grpc_subchannel_create(&c->base, args);
+  grpc_connector_unref(&c->base);
+  grpc_channel_args_destroy(final_args);
+  return s;
 }
 
-/* callback for when our target address has been resolved */
-static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
-  request *r = rp;
-
-  /* if we're not still the active request, abort */
-  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
-    if (resolved) {
-      grpc_resolved_addresses_destroy(resolved);
-    }
-    done(r, 0);
-    return;
-  }
-
-  if (!resolved) {
-    done(r, 0);
-    return;
-  } else {
-    r->resolved = resolved;
-    r->resolved_index = 0;
-    if (!maybe_try_next_resolved(r)) {
-      done(r, 0);
-    }
-  }
-}
-
-static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
-  request *r = gpr_malloc(sizeof(request));
-  r->setup = sp;
-  r->cs_request = cs_request;
-  r->resolved = NULL;
-  r->resolved_index = 0;
-  /* TODO(klempner): Make grpc_resolve_address respect deadline */
-  grpc_resolve_address(r->setup->target, "http", on_resolved, r);
-}
-
-static void done_setup(void *sp) {
-  setup *s = sp;
-  gpr_free((void *)s->target);
-  gpr_free(s);
-}
-
-static grpc_transport_setup_result complete_setup(void *channel_stack,
-                                                  grpc_transport *transport,
-                                                  grpc_mdctx *mdctx) {
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_http_client_filter};
-  return grpc_client_channel_transport_setup_complete(
-      channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
-      mdctx);
-}
+static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
+    subchannel_factory_ref, subchannel_factory_unref,
+    subchannel_factory_create_subchannel};
 
 /* Create a client channel:
    Asynchronously: - resolve target
@@ -189,28 +153,37 @@
                    - perform handshakes */
 grpc_channel *grpc_channel_create(const char *target,
                                   const grpc_channel_args *args) {
-  setup *s = gpr_malloc(sizeof(setup));
-  grpc_mdctx *mdctx = grpc_mdctx_create();
   grpc_channel *channel = NULL;
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
+  grpc_resolver *resolver;
+  subchannel_factory *f;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
   int n = 0;
-  filters[n++] = &grpc_client_surface_filter;
   /* TODO(census)
   if (grpc_channel_args_is_census_enabled(args)) {
     filters[n++] = &grpc_client_census_filter;
     } */
+  filters[n++] = &grpc_compress_filter;
   filters[n++] = &grpc_client_channel_filter;
   GPR_ASSERT(n <= MAX_FILTERS);
+
+  f = gpr_malloc(sizeof(*f));
+  f->base.vtable = &subchannel_factory_vtable;
+  gpr_ref_init(&f->refs, 1);
+  grpc_mdctx_ref(mdctx);
+  f->mdctx = mdctx;
+  f->merge_args = grpc_channel_args_copy(args);
+  resolver = grpc_resolver_create(target, &f->base);
+  if (!resolver) {
+    return NULL;
+  }
+
   channel = grpc_channel_create_from_filters(filters, n, args, mdctx, 1);
-
-  s->target = gpr_strdup(target);
-  s->setup_callback = complete_setup;
-  s->setup_user_data = grpc_channel_get_channel_stack(channel);
-
-  grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
-                                      args, mdctx, initiate_setup, done_setup,
-                                      s);
+  grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
+                                   resolver);
+  GRPC_RESOLVER_UNREF(resolver, "create");
+  grpc_subchannel_factory_unref(&f->base);
 
   return channel;
 }
diff --git a/src/core/surface/client.c b/src/core/surface/client.c
deleted file mode 100644
index 8ac4dd1..0000000
--- a/src/core/surface/client.c
+++ /dev/null
@@ -1,89 +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.
- *
- */
-
-#include "src/core/surface/client.h"
-
-#include "src/core/surface/call.h"
-#include "src/core/surface/channel.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-typedef struct { void *unused; } call_data;
-
-typedef struct { void *unused; } channel_data;
-
-static void client_start_transport_op(grpc_call_element *elem,
-                                      grpc_transport_op *op) {
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  grpc_call_next_op(elem, op);
-}
-
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  switch (op->type) {
-    case GRPC_ACCEPT_CALL:
-      gpr_log(GPR_ERROR, "Client cannot accept new calls");
-      break;
-    case GRPC_TRANSPORT_CLOSED:
-      grpc_client_channel_closed(elem);
-      break;
-    case GRPC_TRANSPORT_GOAWAY:
-      gpr_slice_unref(op->data.goaway.message);
-      break;
-    default:
-      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
-      grpc_channel_next_op(elem, op);
-  }
-}
-
-static void init_call_elem(grpc_call_element *elem,
-                           const void *transport_server_data,
-                           grpc_transport_op *initial_op) {}
-
-static void destroy_call_elem(grpc_call_element *elem) {}
-
-static void init_channel_elem(grpc_channel_element *elem,
-                              const grpc_channel_args *args, grpc_mdctx *mdctx,
-                              int is_first, int is_last) {
-  GPR_ASSERT(is_first);
-  GPR_ASSERT(!is_last);
-}
-
-static void destroy_channel_elem(grpc_channel_element *elem) {}
-
-const grpc_channel_filter grpc_client_surface_filter = {
-    client_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "client",
-};
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index b48fbac..8484418 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -45,251 +45,186 @@
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 
-#define NUM_TAG_BUCKETS 31
-
-/* A single event: extends grpc_event to form a linked list with a destruction
-   function (on_finish) that is hidden from outside this module */
-typedef struct event {
-  grpc_event base;
-  struct event *queue_next;
-  struct event *queue_prev;
-  struct event *bucket_next;
-  struct event *bucket_prev;
-} event;
-
 /* Completion queue structure */
 struct grpc_completion_queue {
-  /* TODO(ctiller): see if this can be removed */
-  int allow_polling;
-
-  /* When refs drops to zero, we are in shutdown mode, and will be destroyable
-     once all queued events are drained */
-  gpr_refcount refs;
-  /* Once owning_refs drops to zero, we will destroy the cq */
+  /** completed events */
+  grpc_cq_completion completed_head;
+  grpc_cq_completion *completed_tail;
+  /** Number of pending events (+1 if we're not shutdown) */
+  gpr_refcount pending_events;
+  /** Once owning_refs drops to zero, we will destroy the cq */
   gpr_refcount owning_refs;
-  /* the set of low level i/o things that concern this cq */
+  /** the set of low level i/o things that concern this cq */
   grpc_pollset pollset;
-  /* 0 initially, 1 once we've begun shutting down */
+  /** 0 initially, 1 once we've begun shutting down */
   int shutdown;
   int shutdown_called;
-  /* Head of a linked list of queued events (prev points to the last element) */
-  event *queue;
-  /* Fixed size chained hash table of events for pluck() */
-  event *buckets[NUM_TAG_BUCKETS];
+  int is_server_cq;
 };
 
 grpc_completion_queue *grpc_completion_queue_create(void) {
   grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
   memset(cc, 0, sizeof(*cc));
   /* Initial ref is dropped by grpc_completion_queue_shutdown */
-  gpr_ref_init(&cc->refs, 1);
+  gpr_ref_init(&cc->pending_events, 1);
   /* One for destroy(), one for pollset_shutdown */
   gpr_ref_init(&cc->owning_refs, 2);
   grpc_pollset_init(&cc->pollset);
-  cc->allow_polling = 1;
+  cc->completed_tail = &cc->completed_head;
+  cc->completed_head.next = (gpr_uintptr)cc->completed_tail;
   return cc;
 }
 
+#ifdef GRPC_CQ_REF_COUNT_DEBUG
+void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
+                          const char *file, int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p   ref %d -> %d %s", cc,
+          (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason);
+#else
 void grpc_cq_internal_ref(grpc_completion_queue *cc) {
+#endif
   gpr_ref(&cc->owning_refs);
 }
 
 static void on_pollset_destroy_done(void *arg) {
   grpc_completion_queue *cc = arg;
-  grpc_cq_internal_unref(cc);
+  GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy");
 }
 
+#ifdef GRPC_CQ_REF_COUNT_DEBUG
+void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason,
+                            const char *file, int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc,
+          (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason);
+#else
 void grpc_cq_internal_unref(grpc_completion_queue *cc) {
+#endif
   if (gpr_unref(&cc->owning_refs)) {
-    GPR_ASSERT(cc->queue == NULL);
+    GPR_ASSERT(cc->completed_head.next == (gpr_uintptr)&cc->completed_head);
     grpc_pollset_destroy(&cc->pollset);
     gpr_free(cc);
   }
 }
 
-void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc) {
-  cc->allow_polling = 0;
-}
-
-/* Create and append an event to the queue. Returns the event so that its data
-   members can be filled in.
-   Requires GRPC_POLLSET_MU(&cc->pollset) locked. */
-static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type,
-                         void *tag, grpc_call *call) {
-  event *ev = gpr_malloc(sizeof(event));
-  gpr_uintptr bucket = ((gpr_uintptr)tag) % NUM_TAG_BUCKETS;
-  ev->base.type = type;
-  ev->base.tag = tag;
-  if (cc->queue == NULL) {
-    cc->queue = ev->queue_next = ev->queue_prev = ev;
-  } else {
-    ev->queue_next = cc->queue;
-    ev->queue_prev = cc->queue->queue_prev;
-    ev->queue_next->queue_prev = ev->queue_prev->queue_next = ev;
-  }
-  if (cc->buckets[bucket] == NULL) {
-    cc->buckets[bucket] = ev->bucket_next = ev->bucket_prev = ev;
-  } else {
-    ev->bucket_next = cc->buckets[bucket];
-    ev->bucket_prev = cc->buckets[bucket]->bucket_prev;
-    ev->bucket_next->bucket_prev = ev->bucket_prev->bucket_next = ev;
-  }
-  gpr_cv_broadcast(GRPC_POLLSET_CV(&cc->pollset));
-  grpc_pollset_kick(&cc->pollset);
-  return ev;
-}
-
-void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call) {
-  gpr_ref(&cc->refs);
-  if (call) GRPC_CALL_INTERNAL_REF(call, "cq");
+void grpc_cq_begin_op(grpc_completion_queue *cc) {
+  gpr_ref(&cc->pending_events);
 }
 
 /* Signal the end of an operation - if this is the last waiting-to-be-queued
    event, then enter shutdown mode */
-void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
-                    int success) {
-  event *ev;
-  int shutdown = 0;
+/* Queue a GRPC_OP_COMPLETED operation */
+void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
+                    void (*done)(void *done_arg, grpc_cq_completion *storage),
+                    void *done_arg, grpc_cq_completion *storage) {
+  int shutdown;
+
+  storage->tag = tag;
+  storage->done = done;
+  storage->done_arg = done_arg;
+  storage->next =
+      ((gpr_uintptr)&cc->completed_head) | ((gpr_uintptr)(success != 0));
+
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
-  ev = add_locked(cc, GRPC_OP_COMPLETE, tag, call);
-  ev->base.success = success;
-  if (gpr_unref(&cc->refs)) {
+  shutdown = gpr_unref(&cc->pending_events);
+  if (!shutdown) {
+    cc->completed_tail->next =
+        ((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next);
+    cc->completed_tail = storage;
+    grpc_pollset_kick(&cc->pollset);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+  } else {
+    cc->completed_tail->next =
+        ((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next);
+    cc->completed_tail = storage;
     GPR_ASSERT(!cc->shutdown);
     GPR_ASSERT(cc->shutdown_called);
     cc->shutdown = 1;
-    gpr_cv_broadcast(GRPC_POLLSET_CV(&cc->pollset));
-    shutdown = 1;
-  }
-  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-  if (call) GRPC_CALL_INTERNAL_UNREF(call, "cq", 0);
-  if (shutdown) {
+    gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
     grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
   }
 }
 
-/* Create a GRPC_QUEUE_SHUTDOWN event without queuing it anywhere */
-static event *create_shutdown_event(void) {
-  event *ev = gpr_malloc(sizeof(event));
-  ev->base.type = GRPC_QUEUE_SHUTDOWN;
-  ev->base.tag = NULL;
-  return ev;
-}
-
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
                                       gpr_timespec deadline) {
-  event *ev = NULL;
   grpc_event ret;
 
-  grpc_cq_internal_ref(cc);
+  GRPC_CQ_INTERNAL_REF(cc, "next");
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   for (;;) {
-    if (cc->queue != NULL) {
-      gpr_uintptr bucket;
-      ev = cc->queue;
-      bucket = ((gpr_uintptr)ev->base.tag) % NUM_TAG_BUCKETS;
-      cc->queue = ev->queue_next;
-      ev->queue_next->queue_prev = ev->queue_prev;
-      ev->queue_prev->queue_next = ev->queue_next;
-      ev->bucket_next->bucket_prev = ev->bucket_prev;
-      ev->bucket_prev->bucket_next = ev->bucket_next;
-      if (ev == cc->buckets[bucket]) {
-        cc->buckets[bucket] = ev->bucket_next;
-        if (ev == cc->buckets[bucket]) {
-          cc->buckets[bucket] = NULL;
-        }
+    if (cc->completed_tail != &cc->completed_head) {
+      grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
+      cc->completed_head.next = c->next & ~(gpr_uintptr)1;
+      if (c == cc->completed_tail) {
+        cc->completed_tail = &cc->completed_head;
       }
-      if (cc->queue == ev) {
-        cc->queue = NULL;
-      }
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      ret.type = GRPC_OP_COMPLETE;
+      ret.success = c->next & 1u;
+      ret.tag = c->tag;
+      c->done(c->done_arg, c);
       break;
     }
     if (cc->shutdown) {
-      ev = create_shutdown_event();
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_SHUTDOWN;
       break;
     }
-    if (cc->allow_polling && grpc_pollset_work(&cc->pollset, deadline)) {
-      continue;
-    }
-    if (gpr_cv_wait(GRPC_POLLSET_CV(&cc->pollset),
-                    GRPC_POLLSET_MU(&cc->pollset), deadline)) {
+    if (!grpc_pollset_work(&cc->pollset, deadline)) {
       gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
-      GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-      grpc_cq_internal_unref(cc);
-      return ret;
+      break;
     }
   }
-  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-  ret = ev->base;
-  gpr_free(ev);
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-  grpc_cq_internal_unref(cc);
+  GRPC_CQ_INTERNAL_UNREF(cc, "next");
   return ret;
 }
 
-static event *pluck_event(grpc_completion_queue *cc, void *tag) {
-  gpr_uintptr bucket = ((gpr_uintptr)tag) % NUM_TAG_BUCKETS;
-  event *ev = cc->buckets[bucket];
-  if (ev == NULL) return NULL;
-  do {
-    if (ev->base.tag == tag) {
-      ev->queue_next->queue_prev = ev->queue_prev;
-      ev->queue_prev->queue_next = ev->queue_next;
-      ev->bucket_next->bucket_prev = ev->bucket_prev;
-      ev->bucket_prev->bucket_next = ev->bucket_next;
-      if (ev == cc->buckets[bucket]) {
-        cc->buckets[bucket] = ev->bucket_next;
-        if (ev == cc->buckets[bucket]) {
-          cc->buckets[bucket] = NULL;
-        }
-      }
-      if (cc->queue == ev) {
-        cc->queue = ev->queue_next;
-        if (cc->queue == ev) {
-          cc->queue = NULL;
-        }
-      }
-      return ev;
-    }
-    ev = ev->bucket_next;
-  } while (ev != cc->buckets[bucket]);
-  return NULL;
-}
-
 grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
                                        gpr_timespec deadline) {
-  event *ev = NULL;
   grpc_event ret;
+  grpc_cq_completion *c;
+  grpc_cq_completion *prev;
 
-  grpc_cq_internal_ref(cc);
+  GRPC_CQ_INTERNAL_REF(cc, "pluck");
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   for (;;) {
-    if ((ev = pluck_event(cc, tag))) {
-      break;
+    prev = &cc->completed_head;
+    while ((c = (grpc_cq_completion *)(prev->next & ~(gpr_uintptr)1)) !=
+           &cc->completed_head) {
+      if (c->tag == tag) {
+        prev->next =
+            (prev->next & (gpr_uintptr)1) | (c->next & ~(gpr_uintptr)1);
+        if (c == cc->completed_tail) {
+          cc->completed_tail = prev;
+        }
+        gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+        ret.type = GRPC_OP_COMPLETE;
+        ret.success = c->next & 1u;
+        ret.tag = c->tag;
+        c->done(c->done_arg, c);
+        goto done;
+      }
+      prev = c;
     }
     if (cc->shutdown) {
-      ev = create_shutdown_event();
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_SHUTDOWN;
       break;
     }
-    if (cc->allow_polling && grpc_pollset_work(&cc->pollset, deadline)) {
-      continue;
-    }
-    if (gpr_cv_wait(GRPC_POLLSET_CV(&cc->pollset),
-                    GRPC_POLLSET_MU(&cc->pollset), deadline)) {
+    if (!grpc_pollset_work(&cc->pollset, deadline)) {
       gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
-      GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-      grpc_cq_internal_unref(cc);
-      return ret;
+      break;
     }
   }
-  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-  ret = ev->base;
-  gpr_free(ev);
+done:
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-  grpc_cq_internal_unref(cc);
+  GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
   return ret;
 }
 
@@ -297,21 +232,25 @@
    to zero here, then enter shutdown mode and wake up any waiters */
 void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+  if (cc->shutdown_called) {
+    gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+    return;
+  }
   cc->shutdown_called = 1;
   gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
 
-  if (gpr_unref(&cc->refs)) {
+  if (gpr_unref(&cc->pending_events)) {
     gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
     GPR_ASSERT(!cc->shutdown);
     cc->shutdown = 1;
-    gpr_cv_broadcast(GRPC_POLLSET_CV(&cc->pollset));
     gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
     grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
   }
 }
 
 void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
-  grpc_cq_internal_unref(cc);
+  grpc_completion_queue_shutdown(cc);
+  GRPC_CQ_INTERNAL_UNREF(cc, "destroy");
 }
 
 grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
@@ -322,6 +261,11 @@
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   grpc_pollset_kick(&cc->pollset);
   grpc_pollset_work(&cc->pollset,
-                    gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
+                    gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                 gpr_time_from_millis(100, GPR_TIMESPAN)));
   gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
 }
+
+void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; }
+
+int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; }
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 7b6fad9..f944f48 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -39,22 +39,47 @@
 #include "src/core/iomgr/pollset.h"
 #include <grpc/grpc.h>
 
+typedef struct grpc_cq_completion {
+  /** user supplied tag */
+  void *tag;
+  /** done callback - called when this queue element is no longer
+      needed by the completion queue */
+  void (*done)(void *done_arg, struct grpc_cq_completion *c);
+  void *done_arg;
+  /** next pointer; low bit is used to indicate success or not */
+  gpr_uintptr next;
+} grpc_cq_completion;
+
+#ifdef GRPC_CQ_REF_COUNT_DEBUG
+void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
+                          const char *file, int line);
+void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason,
+                            const char *file, int line);
+#define GRPC_CQ_INTERNAL_REF(cc, reason) \
+  grpc_cq_internal_ref(cc, reason, __FILE__, __LINE__)
+#define GRPC_CQ_INTERNAL_UNREF(cc, reason) \
+  grpc_cq_internal_unref(cc, reason, __FILE__, __LINE__)
+#else
 void grpc_cq_internal_ref(grpc_completion_queue *cc);
 void grpc_cq_internal_unref(grpc_completion_queue *cc);
+#define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc)
+#define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc)
+#endif
 
 /* Flag that an operation is beginning: the completion channel will not finish
    shutdown until a corrensponding grpc_cq_end_* call is made */
-void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call);
+void grpc_cq_begin_op(grpc_completion_queue *cc);
 
 /* Queue a GRPC_OP_COMPLETED operation */
-void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
-                    int success);
-
-/* disable polling for some tests */
-void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc);
+void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
+                    void (*done)(void *done_arg, grpc_cq_completion *storage),
+                    void *done_arg, grpc_cq_completion *storage);
 
 grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
 
 void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc);
 
+void grpc_cq_mark_server_cq(grpc_completion_queue *cc);
+int grpc_cq_is_server_cq(grpc_completion_queue *cc);
+
 #endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index ca61a38..04e27d3 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -31,9 +31,14 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/census.h>
 #include <grpc/grpc.h>
+#include <grpc/support/time.h>
 #include "src/core/channel/channel_stack.h"
+#include "src/core/client_config/resolver_registry.h"
+#include "src/core/client_config/resolvers/dns_resolver.h"
 #include "src/core/debug/trace.h"
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/profiling/timers.h"
@@ -42,6 +47,10 @@
 #include "src/core/surface/surface_trace.h"
 #include "src/core/transport/chttp2_transport.h"
 
+#ifdef GPR_POSIX_SOCKET
+#include "src/core/client_config/resolvers/unix_resolver_posix.h"
+#endif
+
 static gpr_once g_basic_init = GPR_ONCE_INIT;
 static gpr_mu g_init_mu;
 static int g_initializations;
@@ -56,6 +65,12 @@
 
   gpr_mu_lock(&g_init_mu);
   if (++g_initializations == 1) {
+    gpr_time_init();
+    grpc_resolver_registry_init("dns:///");
+    grpc_register_resolver_type("dns", grpc_dns_resolver_factory_create());
+#ifdef GPR_POSIX_SOCKET
+    grpc_register_resolver_type("unix", grpc_unix_resolver_factory_create());
+#endif
     grpc_register_tracer("channel", &grpc_trace_channel);
     grpc_register_tracer("surface", &grpc_surface_trace);
     grpc_register_tracer("http", &grpc_http_trace);
@@ -79,6 +94,7 @@
     census_shutdown();
     grpc_timers_global_destroy();
     grpc_tracer_shutdown();
+    grpc_resolver_registry_shutdown();
   }
   gpr_mu_unlock(&g_init_mu);
 }
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index a3b0b26..3f2bb5c 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -49,16 +49,16 @@
 
 typedef struct { grpc_mdctx *mdctx; } channel_data;
 
-static void lame_start_transport_op(grpc_call_element *elem,
-                                    grpc_transport_op *op) {
+static void lame_start_transport_stream_op(grpc_call_element *elem,
+                                           grpc_transport_stream_op *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  if (op->send_ops) {
+  if (op->send_ops != NULL) {
     grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops);
-    op->on_done_send(op->send_user_data, 0);
+    op->on_done_send->cb(op->on_done_send->cb_arg, 0);
   }
-  if (op->recv_ops) {
+  if (op->recv_ops != NULL) {
     char tmp[GPR_LTOA_MIN_BUFSIZE];
     grpc_metadata_batch mdb;
     gpr_ltoa(GRPC_STATUS_UNKNOWN, tmp);
@@ -72,38 +72,40 @@
     mdb.list.head = &calld->status;
     mdb.list.tail = &calld->details;
     mdb.garbage.head = mdb.garbage.tail = NULL;
-    mdb.deadline = gpr_inf_future;
+    mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
     grpc_sopb_add_metadata(op->recv_ops, mdb);
     *op->recv_state = GRPC_STREAM_CLOSED;
-    op->on_done_recv(op->recv_user_data, 1);
+    op->on_done_recv->cb(op->on_done_recv->cb_arg, 1);
+  }
+  if (op->on_consumed != NULL) {
+    op->on_consumed->cb(op->on_consumed->cb_arg, 0);
   }
 }
 
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  switch (op->type) {
-    case GRPC_CHANNEL_GOAWAY:
-      gpr_slice_unref(op->data.goaway.message);
-      break;
-    case GRPC_CHANNEL_DISCONNECT:
-      grpc_client_channel_closed(elem);
-      break;
-    default:
-      break;
+static void lame_start_transport_op(grpc_channel_element *elem,
+                                    grpc_transport_op *op) {
+  if (op->on_connectivity_state_change) {
+    GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE);
+    *op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
+    op->on_connectivity_state_change->cb(
+        op->on_connectivity_state_change->cb_arg, 1);
+  }
+  if (op->on_consumed != NULL) {
+    op->on_consumed->cb(op->on_consumed->cb_arg, 1);
   }
 }
 
 static void init_call_elem(grpc_call_element *elem,
                            const void *transport_server_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   if (initial_op) {
-    grpc_transport_op_finish_with_failure(initial_op);
+    grpc_transport_stream_op_finish_with_failure(initial_op);
   }
 }
 
 static void destroy_call_elem(grpc_call_element *elem) {}
 
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
                               int is_first, int is_last) {
   channel_data *chand = elem->channel_data;
@@ -115,9 +117,15 @@
 static void destroy_channel_elem(grpc_channel_element *elem) {}
 
 static const grpc_channel_filter lame_filter = {
-    lame_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
-    destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, "lame-client",
+    lame_start_transport_stream_op,
+    lame_start_transport_op,
+    sizeof(call_data),
+    init_call_elem,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    "lame-client",
 };
 
 grpc_channel *grpc_lame_client_channel_create(void) {
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 8b39934..d87ec97 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -31,173 +31,149 @@
  *
  */
 
-#include "src/core/iomgr/sockaddr.h"
-
 #include <grpc/grpc.h>
 
 #include <stdlib.h>
 #include <string.h>
 
-#include "src/core/channel/census_filter.h"
+#include <grpc/support/alloc.h>
+
 #include "src/core/channel/channel_args.h"
 #include "src/core/channel/client_channel.h"
-#include "src/core/channel/client_setup.h"
-#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/compress_filter.h"
 #include "src/core/channel/http_client_filter.h"
-#include "src/core/iomgr/resolve_address.h"
+#include "src/core/client_config/resolver_registry.h"
 #include "src/core/iomgr/tcp_client.h"
 #include "src/core/security/auth_filters.h"
 #include "src/core/security/credentials.h"
 #include "src/core/security/secure_transport_setup.h"
-#include "src/core/support/string.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/transport/chttp2_transport.h"
-#include <grpc/grpc_security.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 #include "src/core/tsi/transport_security_interface.h"
 
-typedef struct setup setup;
-
-/* A single setup request (started via initiate) */
 typedef struct {
-  grpc_client_setup_request *cs_request;
-  setup *setup;
-  /* Resolved addresses, or null if resolution not yet completed. */
-  grpc_resolved_addresses *resolved;
-  /* which address in resolved should we pick for the next connection attempt */
-  size_t resolved_index;
-} request;
+  grpc_connector base;
+  gpr_refcount refs;
 
-struct setup {
   grpc_channel_security_connector *security_connector;
-  const char *target;
-  grpc_transport_setup_callback setup_callback;
-  void *setup_user_data;
-};
 
-static int maybe_try_next_resolved(request *r);
+  grpc_iomgr_closure *notify;
+  grpc_connect_in_args args;
+  grpc_connect_out_args *result;
+} connector;
 
-static void done(request *r, int was_successful) {
-  grpc_client_setup_request_finish(r->cs_request, was_successful);
-  if (r->resolved) {
-    grpc_resolved_addresses_destroy(r->resolved);
-  }
-  gpr_free(r);
+static void connector_ref(grpc_connector *con) {
+  connector *c = (connector *)con;
+  gpr_ref(&c->refs);
 }
 
-static void on_secure_transport_setup_done(void *rp,
+static void connector_unref(grpc_connector *con) {
+  connector *c = (connector *)con;
+  if (gpr_unref(&c->refs)) {
+    gpr_free(c);
+  }
+}
+
+static void on_secure_transport_setup_done(void *arg,
                                            grpc_security_status status,
+                                           grpc_endpoint *wrapped_endpoint,
                                            grpc_endpoint *secure_endpoint) {
-  request *r = rp;
+  connector *c = arg;
+  grpc_iomgr_closure *notify;
   if (status != GRPC_SECURITY_OK) {
     gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
-    done(r, 0);
-  } else if (grpc_client_setup_cb_begin(r->cs_request)) {
-    grpc_create_chttp2_transport(
-        r->setup->setup_callback, r->setup->setup_user_data,
-        grpc_client_setup_get_channel_args(r->cs_request), secure_endpoint,
-        NULL, 0, grpc_client_setup_get_mdctx(r->cs_request), 1);
-    grpc_client_setup_cb_end(r->cs_request);
-    done(r, 1);
+    memset(c->result, 0, sizeof(*c->result));
   } else {
-    done(r, 0);
+    c->result->transport = grpc_create_chttp2_transport(
+        c->args.channel_args, secure_endpoint, c->args.metadata_context, 1);
+    grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0);
+    c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2);
+    c->result->filters[0] = &grpc_client_auth_filter;
+    c->result->filters[1] = &grpc_http_client_filter;
+    c->result->num_filters = 2;
   }
+  notify = c->notify;
+  c->notify = NULL;
+  grpc_iomgr_add_callback(notify);
 }
 
-/* connection callback: tcp is either valid, or null on error */
-static void on_connect(void *rp, grpc_endpoint *tcp) {
-  request *r = rp;
-
-  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
-    if (tcp) {
-      grpc_endpoint_shutdown(tcp);
-      grpc_endpoint_destroy(tcp);
-    }
-    done(r, 0);
-    return;
-  }
-
-  if (!tcp) {
-    if (!maybe_try_next_resolved(r)) {
-      done(r, 0);
-      return;
-    } else {
-      return;
-    }
+static void connected(void *arg, grpc_endpoint *tcp) {
+  connector *c = arg;
+  grpc_iomgr_closure *notify;
+  if (tcp != NULL) {
+    grpc_setup_secure_transport(&c->security_connector->base, tcp,
+                                on_secure_transport_setup_done, c);
   } else {
-    grpc_setup_secure_transport(&r->setup->security_connector->base, tcp,
-                                on_secure_transport_setup_done, r);
+    memset(c->result, 0, sizeof(*c->result));
+    notify = c->notify;
+    c->notify = NULL;
+    grpc_iomgr_add_callback(notify);
   }
 }
 
-/* attempt to connect to the next available resolved address */
-static int maybe_try_next_resolved(request *r) {
-  grpc_resolved_address *addr;
-  if (!r->resolved) return 0;
-  if (r->resolved_index == r->resolved->naddrs) return 0;
-  addr = &r->resolved->addrs[r->resolved_index++];
-  grpc_tcp_client_connect(on_connect, r, (struct sockaddr *)&addr->addr,
-                          addr->len,
-                          grpc_client_setup_request_deadline(r->cs_request));
-  return 1;
+static void connector_connect(grpc_connector *con,
+                              const grpc_connect_in_args *args,
+                              grpc_connect_out_args *result,
+                              grpc_iomgr_closure *notify) {
+  connector *c = (connector *)con;
+  GPR_ASSERT(c->notify == NULL);
+  GPR_ASSERT(notify->cb);
+  c->notify = notify;
+  c->args = *args;
+  c->result = result;
+  grpc_tcp_client_connect(connected, c, args->interested_parties, args->addr,
+                          args->addr_len, args->deadline);
 }
 
-/* callback for when our target address has been resolved */
-static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
-  request *r = rp;
+static const grpc_connector_vtable connector_vtable = {
+    connector_ref, connector_unref, connector_connect};
 
-  /* if we're not still the active request, abort */
-  if (!grpc_client_setup_request_should_continue(r->cs_request)) {
-    if (resolved) {
-      grpc_resolved_addresses_destroy(resolved);
-    }
-    done(r, 0);
-    return;
-  }
+typedef struct {
+  grpc_subchannel_factory base;
+  gpr_refcount refs;
+  grpc_mdctx *mdctx;
+  grpc_channel_args *merge_args;
+  grpc_channel_security_connector *security_connector;
+} subchannel_factory;
 
-  if (!resolved) {
-    done(r, 0);
-    return;
-  } else {
-    r->resolved = resolved;
-    r->resolved_index = 0;
-    if (!maybe_try_next_resolved(r)) {
-      done(r, 0);
-    }
+static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  gpr_ref(&f->refs);
+}
+
+static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  if (gpr_unref(&f->refs)) {
+    GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
+                                  "subchannel_factory");
+    grpc_channel_args_destroy(f->merge_args);
+    grpc_mdctx_unref(f->mdctx);
+    gpr_free(f);
   }
 }
 
-static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
-  request *r = gpr_malloc(sizeof(request));
-  r->setup = sp;
-  r->cs_request = cs_request;
-  r->resolved = NULL;
-  r->resolved_index = 0;
-  /* TODO(klempner): Make grpc_resolve_address respect deadline */
-  grpc_resolve_address(r->setup->target, "https", on_resolved, r);
+static grpc_subchannel *subchannel_factory_create_subchannel(
+    grpc_subchannel_factory *scf, grpc_subchannel_args *args) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  connector *c = gpr_malloc(sizeof(*c));
+  grpc_channel_args *final_args =
+      grpc_channel_args_merge(args->args, f->merge_args);
+  grpc_subchannel *s;
+  memset(c, 0, sizeof(*c));
+  c->base.vtable = &connector_vtable;
+  c->security_connector = f->security_connector;
+  gpr_ref_init(&c->refs, 1);
+  args->mdctx = f->mdctx;
+  args->args = final_args;
+  s = grpc_subchannel_create(&c->base, args);
+  grpc_connector_unref(&c->base);
+  grpc_channel_args_destroy(final_args);
+  return s;
 }
 
-static void done_setup(void *sp) {
-  setup *s = sp;
-  gpr_free((void *)s->target);
-  grpc_security_connector_unref(&s->security_connector->base);
-  gpr_free(s);
-}
-
-static grpc_transport_setup_result complete_setup(void *channel_stack,
-                                                  grpc_transport *transport,
-                                                  grpc_mdctx *mdctx) {
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_client_auth_filter, &grpc_http_client_filter};
-  return grpc_client_channel_transport_setup_complete(
-      channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
-      mdctx);
-}
+static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
+    subchannel_factory_ref, subchannel_factory_unref,
+    subchannel_factory_create_subchannel};
 
 /* Create a secure client channel:
    Asynchronously: - resolve target
@@ -206,13 +182,14 @@
 grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
                                          const char *target,
                                          const grpc_channel_args *args) {
-  setup *s;
   grpc_channel *channel;
   grpc_arg connector_arg;
   grpc_channel_args *args_copy;
   grpc_channel_args *new_args_from_connector;
   grpc_channel_security_connector *connector;
   grpc_mdctx *mdctx;
+  grpc_resolver *resolver;
+  subchannel_factory *f;
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
   int n = 0;
@@ -229,30 +206,42 @@
   }
   mdctx = grpc_mdctx_create();
 
-  s = gpr_malloc(sizeof(setup));
   connector_arg = grpc_security_connector_to_arg(&connector->base);
   args_copy = grpc_channel_args_copy_and_add(
       new_args_from_connector != NULL ? new_args_from_connector : args,
-      &connector_arg);
-  filters[n++] = &grpc_client_surface_filter;
+      &connector_arg, 1);
   /* TODO(census)
   if (grpc_channel_args_is_census_enabled(args)) {
     filters[n++] = &grpc_client_census_filter;
     } */
+  filters[n++] = &grpc_compress_filter;
   filters[n++] = &grpc_client_channel_filter;
   GPR_ASSERT(n <= MAX_FILTERS);
+
+  f = gpr_malloc(sizeof(*f));
+  f->base.vtable = &subchannel_factory_vtable;
+  gpr_ref_init(&f->refs, 1);
+  grpc_mdctx_ref(mdctx);
+  f->mdctx = mdctx;
+  GRPC_SECURITY_CONNECTOR_REF(&connector->base, "subchannel_factory");
+  f->security_connector = connector;
+  f->merge_args = grpc_channel_args_copy(args_copy);
+  resolver = grpc_resolver_create(target, &f->base);
+  if (!resolver) {
+    return NULL;
+  }
+
   channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
+  grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
+                                   resolver);
+  GRPC_RESOLVER_UNREF(resolver, "create");
+  grpc_subchannel_factory_unref(&f->base);
+  GRPC_SECURITY_CONNECTOR_UNREF(&connector->base, "channel_create");
+
   grpc_channel_args_destroy(args_copy);
   if (new_args_from_connector != NULL) {
     grpc_channel_args_destroy(new_args_from_connector);
   }
 
-  s->target = gpr_strdup(target);
-  s->setup_callback = complete_setup;
-  s->setup_user_data = grpc_channel_get_channel_stack(channel);
-  s->security_connector = connector;
-  grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
-                                      args, mdctx, initiate_setup, done_setup,
-                                      s);
   return channel;
 }
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 825ef66..f2d6b11 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -36,22 +36,22 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
 #include "src/core/channel/census_filter.h"
 #include "src/core/channel/channel_args.h"
 #include "src/core/channel/connected_channel.h"
 #include "src/core/iomgr/iomgr.h"
+#include "src/core/support/stack_lockfree.h"
 #include "src/core/support/string.h"
 #include "src/core/surface/call.h"
 #include "src/core/surface/channel.h"
 #include "src/core/surface/completion_queue.h"
 #include "src/core/surface/init.h"
 #include "src/core/transport/metadata.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-typedef enum { PENDING_START, ALL_CALLS, CALL_LIST_COUNT } call_list;
 
 typedef struct listener {
   void *arg;
@@ -72,12 +72,14 @@
 
 typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
 
-typedef struct {
+typedef struct requested_call {
   requested_call_type type;
   void *tag;
+  grpc_server *server;
   grpc_completion_queue *cq_bound_to_call;
   grpc_completion_queue *cq_for_notification;
   grpc_call **call;
+  grpc_cq_completion completion;
   union {
     struct {
       grpc_call_details *details;
@@ -92,20 +94,6 @@
   } data;
 } requested_call;
 
-typedef struct {
-  requested_call *calls;
-  size_t count;
-  size_t capacity;
-} requested_call_array;
-
-struct registered_method {
-  char *method;
-  char *host;
-  call_data *pending;
-  requested_call_array requested;
-  registered_method *next;
-};
-
 typedef struct channel_registered_method {
   registered_method *server_registered_method;
   grpc_mdstr *method;
@@ -114,6 +102,7 @@
 
 struct channel_data {
   grpc_server *server;
+  grpc_connectivity_state connectivity_state;
   grpc_channel *channel;
   grpc_mdstr *path_key;
   grpc_mdstr *authority_key;
@@ -123,42 +112,16 @@
   channel_registered_method *registered_methods;
   gpr_uint32 registered_method_slots;
   gpr_uint32 registered_method_max_probes;
-  grpc_iomgr_closure finish_shutdown_channel_closure;
   grpc_iomgr_closure finish_destroy_channel_closure;
+  grpc_iomgr_closure channel_connectivity_changed;
 };
 
 typedef struct shutdown_tag {
   void *tag;
   grpc_completion_queue *cq;
+  grpc_cq_completion completion;
 } shutdown_tag;
 
-struct grpc_server {
-  size_t channel_filter_count;
-  const grpc_channel_filter **channel_filters;
-  grpc_channel_args *channel_args;
-
-  grpc_completion_queue **cqs;
-  grpc_pollset **pollsets;
-  size_t cq_count;
-
-  gpr_mu mu;
-
-  registered_method *registered_methods;
-  requested_call_array requested_calls;
-
-  gpr_uint8 shutdown;
-  gpr_uint8 shutdown_published;
-  size_t num_shutdown_tags;
-  shutdown_tag *shutdown_tags;
-
-  call_data *lists[CALL_LIST_COUNT];
-  channel_data root_channel_data;
-
-  listener *listeners;
-  int listeners_destroyed;
-  gpr_refcount internal_refcount;
-};
-
 typedef enum {
   /* waiting for metadata */
   NOT_STARTED,
@@ -170,10 +133,16 @@
   ZOMBIED
 } call_state;
 
+typedef struct request_matcher request_matcher;
+
 struct call_data {
   grpc_call *call;
 
+  /** protects state */
+  gpr_mu mu_state;
+  /** the current state of a call - see call_state */
   call_state state;
+
   grpc_mdstr *path;
   grpc_mdstr *host;
   gpr_timespec deadline;
@@ -183,13 +152,72 @@
 
   grpc_stream_op_buffer *recv_ops;
   grpc_stream_state *recv_state;
-  void (*on_done_recv)(void *user_data, int success);
-  void *recv_user_data;
+  grpc_iomgr_closure *on_done_recv;
 
+  grpc_iomgr_closure server_on_recv;
   grpc_iomgr_closure kill_zombie_closure;
 
-  call_data **root[CALL_LIST_COUNT];
-  call_link links[CALL_LIST_COUNT];
+  call_data *pending_next;
+};
+
+struct request_matcher {
+  call_data *pending_head;
+  call_data *pending_tail;
+  gpr_stack_lockfree *requests;
+};
+
+struct registered_method {
+  char *method;
+  char *host;
+  request_matcher request_matcher;
+  registered_method *next;
+};
+
+typedef struct {
+  grpc_channel **channels;
+  size_t num_channels;
+} channel_broadcaster;
+
+struct grpc_server {
+  size_t channel_filter_count;
+  const grpc_channel_filter **channel_filters;
+  grpc_channel_args *channel_args;
+
+  grpc_completion_queue **cqs;
+  grpc_pollset **pollsets;
+  size_t cq_count;
+
+  /* The two following mutexes control access to server-state
+     mu_global controls access to non-call-related state (e.g., channel state)
+     mu_call controls access to call-related state (e.g., the call lists)
+
+     If they are ever required to be nested, you must lock mu_global
+     before mu_call. This is currently used in shutdown processing
+     (grpc_server_shutdown_and_notify and maybe_finish_shutdown) */
+  gpr_mu mu_global; /* mutex for server and channel state */
+  gpr_mu mu_call;   /* mutex for call-specific state */
+
+  registered_method *registered_methods;
+  request_matcher unregistered_request_matcher;
+  /** free list of available requested_calls indices */
+  gpr_stack_lockfree *request_freelist;
+  /** requested call backing data */
+  requested_call *requested_calls;
+  int max_requested_calls;
+
+  gpr_atm shutdown_flag;
+  gpr_uint8 shutdown_published;
+  size_t num_shutdown_tags;
+  shutdown_tag *shutdown_tags;
+
+  channel_data root_channel_data;
+
+  listener *listeners;
+  int listeners_destroyed;
+  gpr_refcount internal_refcount;
+
+  /** when did we print the last shutdown progress message */
+  gpr_timespec last_shutdown_message_time;
 };
 
 #define SERVER_FROM_CALL_ELEM(elem) \
@@ -198,70 +226,111 @@
 static void begin_call(grpc_server *server, call_data *calld,
                        requested_call *rc);
 static void fail_call(grpc_server *server, requested_call *rc);
+/* Before calling maybe_finish_shutdown, we must hold mu_global and not
+   hold mu_call */
+static void maybe_finish_shutdown(grpc_server *server);
 
-static int call_list_join(call_data **root, call_data *call, call_list list) {
-  GPR_ASSERT(!call->root[list]);
-  call->root[list] = root;
-  if (!*root) {
-    *root = call;
-    call->links[list].next = call->links[list].prev = call;
-  } else {
-    call->links[list].next = *root;
-    call->links[list].prev = (*root)->links[list].prev;
-    call->links[list].next->links[list].prev =
-        call->links[list].prev->links[list].next = call;
+/*
+ * channel broadcaster
+ */
+
+/* assumes server locked */
+static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) {
+  channel_data *c;
+  size_t count = 0;
+  for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
+    count++;
   }
-  return 1;
-}
-
-static call_data *call_list_remove_head(call_data **root, call_list list) {
-  call_data *out = *root;
-  if (out) {
-    out->root[list] = NULL;
-    if (out->links[list].next == out) {
-      *root = NULL;
-    } else {
-      *root = out->links[list].next;
-      out->links[list].next->links[list].prev = out->links[list].prev;
-      out->links[list].prev->links[list].next = out->links[list].next;
-    }
+  cb->num_channels = count;
+  cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels);
+  count = 0;
+  for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
+    cb->channels[count++] = c->channel;
+    GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast");
   }
-  return out;
 }
 
-static int call_list_remove(call_data *call, call_list list) {
-  call_data **root = call->root[list];
-  if (root == NULL) return 0;
-  call->root[list] = NULL;
-  if (*root == call) {
-    *root = call->links[list].next;
-    if (*root == call) {
-      *root = NULL;
-      return 1;
-    }
+struct shutdown_cleanup_args {
+  grpc_iomgr_closure closure;
+  gpr_slice slice;
+};
+
+static void shutdown_cleanup(void *arg, int iomgr_status_ignored) {
+  struct shutdown_cleanup_args *a = arg;
+  gpr_slice_unref(a->slice);
+  gpr_free(a);
+}
+
+static void send_shutdown(grpc_channel *channel, int send_goaway,
+                          int send_disconnect) {
+  grpc_transport_op op;
+  struct shutdown_cleanup_args *sc;
+  grpc_channel_element *elem;
+
+  memset(&op, 0, sizeof(op));
+  op.send_goaway = send_goaway;
+  sc = gpr_malloc(sizeof(*sc));
+  sc->slice = gpr_slice_from_copied_string("Server shutdown");
+  op.goaway_message = &sc->slice;
+  op.goaway_status = GRPC_STATUS_OK;
+  op.disconnect = send_disconnect;
+  grpc_iomgr_closure_init(&sc->closure, shutdown_cleanup, sc);
+  op.on_consumed = &sc->closure;
+
+  elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
+  elem->filter->start_transport_op(elem, &op);
+}
+
+static void channel_broadcaster_shutdown(channel_broadcaster *cb,
+                                         int send_goaway,
+                                         int force_disconnect) {
+  size_t i;
+
+  for (i = 0; i < cb->num_channels; i++) {
+    send_shutdown(cb->channels[i], send_goaway, force_disconnect);
+    GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast");
   }
-  GPR_ASSERT(*root != call);
-  call->links[list].next->links[list].prev = call->links[list].prev;
-  call->links[list].prev->links[list].next = call->links[list].next;
-  return 1;
+  gpr_free(cb->channels);
 }
 
-static void requested_call_array_destroy(requested_call_array *array) {
-  gpr_free(array->calls);
+/*
+ * request_matcher
+ */
+
+static void request_matcher_init(request_matcher *request_matcher,
+                                 int entries) {
+  memset(request_matcher, 0, sizeof(*request_matcher));
+  request_matcher->requests = gpr_stack_lockfree_create(entries);
 }
 
-static requested_call *requested_call_array_add(requested_call_array *array) {
-  requested_call *rc;
-  if (array->count == array->capacity) {
-    array->capacity = GPR_MAX(array->capacity + 8, array->capacity * 2);
-    array->calls =
-        gpr_realloc(array->calls, sizeof(requested_call) * array->capacity);
+static void request_matcher_destroy(request_matcher *request_matcher) {
+  GPR_ASSERT(gpr_stack_lockfree_pop(request_matcher->requests) == -1);
+  gpr_stack_lockfree_destroy(request_matcher->requests);
+}
+
+static void kill_zombie(void *elem, int success) {
+  grpc_call_destroy(grpc_call_from_top_element(elem));
+}
+
+static void request_matcher_zombify_all_pending_calls(
+    request_matcher *request_matcher) {
+  while (request_matcher->pending_head) {
+    call_data *calld = request_matcher->pending_head;
+    request_matcher->pending_head = calld->pending_next;
+    gpr_mu_lock(&calld->mu_state);
+    calld->state = ZOMBIED;
+    gpr_mu_unlock(&calld->mu_state);
+    grpc_iomgr_closure_init(
+        &calld->kill_zombie_closure, kill_zombie,
+        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
+    grpc_iomgr_add_callback(&calld->kill_zombie_closure);
   }
-  rc = &array->calls[array->count++];
-  memset(rc, 0, sizeof(*rc));
-  return rc;
 }
 
+/*
+ * server proper
+ */
+
 static void server_ref(grpc_server *server) {
   gpr_ref(&server->internal_refcount);
 }
@@ -270,22 +339,25 @@
   registered_method *rm;
   size_t i;
   grpc_channel_args_destroy(server->channel_args);
-  gpr_mu_destroy(&server->mu);
+  gpr_mu_destroy(&server->mu_global);
+  gpr_mu_destroy(&server->mu_call);
   gpr_free(server->channel_filters);
-  requested_call_array_destroy(&server->requested_calls);
   while ((rm = server->registered_methods) != NULL) {
     server->registered_methods = rm->next;
+    request_matcher_destroy(&rm->request_matcher);
     gpr_free(rm->method);
     gpr_free(rm->host);
-    requested_call_array_destroy(&rm->requested);
     gpr_free(rm);
   }
   for (i = 0; i < server->cq_count; i++) {
-    grpc_cq_internal_unref(server->cqs[i]);
+    GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server");
   }
+  request_matcher_destroy(&server->unregistered_request_matcher);
+  gpr_stack_lockfree_destroy(server->request_freelist);
   gpr_free(server->cqs);
   gpr_free(server->pollsets);
   gpr_free(server->shutdown_tags);
+  gpr_free(server->requested_calls);
   gpr_free(server);
 }
 
@@ -308,7 +380,7 @@
 static void finish_destroy_channel(void *cd, int success) {
   channel_data *chand = cd;
   grpc_server *server = chand->server;
-  grpc_channel_internal_unref(chand->channel);
+  GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server");
   server_unref(server);
 }
 
@@ -317,26 +389,36 @@
   GPR_ASSERT(chand->server != NULL);
   orphan_channel(chand);
   server_ref(chand->server);
+  maybe_finish_shutdown(chand->server);
   chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
   chand->finish_destroy_channel_closure.cb_arg = chand;
   grpc_iomgr_add_callback(&chand->finish_destroy_channel_closure);
 }
 
-static void finish_start_new_rpc_and_unlock(grpc_server *server,
-                                            grpc_call_element *elem,
-                                            call_data **pending_root,
-                                            requested_call_array *array) {
-  requested_call rc;
+static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
+                                 request_matcher *request_matcher) {
   call_data *calld = elem->call_data;
-  if (array->count == 0) {
+  int request_id;
+
+  request_id = gpr_stack_lockfree_pop(request_matcher->requests);
+  if (request_id == -1) {
+    gpr_mu_lock(&server->mu_call);
+    gpr_mu_lock(&calld->mu_state);
     calld->state = PENDING;
-    call_list_join(pending_root, calld, PENDING_START);
-    gpr_mu_unlock(&server->mu);
+    gpr_mu_unlock(&calld->mu_state);
+    if (request_matcher->pending_head == NULL) {
+      request_matcher->pending_tail = request_matcher->pending_head = calld;
+    } else {
+      request_matcher->pending_tail->pending_next = calld;
+      request_matcher->pending_tail = calld;
+    }
+    calld->pending_next = NULL;
+    gpr_mu_unlock(&server->mu_call);
   } else {
-    rc = array->calls[--array->count];
+    gpr_mu_lock(&calld->mu_state);
     calld->state = ACTIVATED;
-    gpr_mu_unlock(&server->mu);
-    begin_call(server, calld, &rc);
+    gpr_mu_unlock(&calld->mu_state);
+    begin_call(server, calld, &server->requested_calls[request_id]);
   }
 }
 
@@ -348,20 +430,18 @@
   gpr_uint32 hash;
   channel_registered_method *rm;
 
-  gpr_mu_lock(&server->mu);
   if (chand->registered_methods && calld->path && calld->host) {
     /* TODO(ctiller): unify these two searches */
     /* check for an exact match with host */
     hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash);
-    for (i = 0; i < chand->registered_method_max_probes; i++) {
+    for (i = 0; i <= chand->registered_method_max_probes; i++) {
       rm = &chand->registered_methods[(hash + i) %
                                       chand->registered_method_slots];
       if (!rm) break;
       if (rm->host != calld->host) continue;
       if (rm->method != calld->path) continue;
-      finish_start_new_rpc_and_unlock(server, elem,
-                                      &rm->server_registered_method->pending,
-                                      &rm->server_registered_method->requested);
+      finish_start_new_rpc(server, elem,
+                           &rm->server_registered_method->request_matcher);
       return;
     }
     /* check for a wildcard method definition (no host set) */
@@ -372,18 +452,12 @@
       if (!rm) break;
       if (rm->host != NULL) continue;
       if (rm->method != calld->path) continue;
-      finish_start_new_rpc_and_unlock(server, elem,
-                                      &rm->server_registered_method->pending,
-                                      &rm->server_registered_method->requested);
+      finish_start_new_rpc(server, elem,
+                           &rm->server_registered_method->request_matcher);
       return;
     }
   }
-  finish_start_new_rpc_and_unlock(server, elem, &server->lists[PENDING_START],
-                                  &server->requested_calls);
-}
-
-static void kill_zombie(void *elem, int success) {
-  grpc_call_destroy(grpc_call_from_top_element(elem));
+  finish_start_new_rpc(server, elem, &server->unregistered_request_matcher);
 }
 
 static int num_listeners(grpc_server *server) {
@@ -395,14 +469,47 @@
   return n;
 }
 
+static void done_shutdown_event(void *server, grpc_cq_completion *completion) {
+  server_unref(server);
+}
+
+static int num_channels(grpc_server *server) {
+  channel_data *chand;
+  int n = 0;
+  for (chand = server->root_channel_data.next;
+       chand != &server->root_channel_data; chand = chand->next) {
+    n++;
+  }
+  return n;
+}
+
 static void maybe_finish_shutdown(grpc_server *server) {
   size_t i;
-  if (server->shutdown && !server->shutdown_published && server->lists[ALL_CALLS] == NULL && server->listeners_destroyed == num_listeners(server)) {
-    server->shutdown_published = 1;
-    for (i = 0; i < server->num_shutdown_tags; i++) {
-      grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag,
-                     NULL, 1);
+  if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) {
+    return;
+  }
+
+  if (server->root_channel_data.next != &server->root_channel_data ||
+      server->listeners_destroyed < num_listeners(server)) {
+    if (gpr_time_cmp(gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME),
+                                  server->last_shutdown_message_time),
+                     gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) {
+      server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
+      gpr_log(GPR_DEBUG,
+              "Waiting for %d channels and %d/%d listeners to be destroyed"
+              " before shutting down server",
+              num_channels(server),
+              num_listeners(server) - server->listeners_destroyed,
+              num_listeners(server));
     }
+    return;
+  }
+  server->shutdown_published = 1;
+  for (i = 0; i < server->num_shutdown_tags; i++) {
+    server_ref(server);
+    grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag, 1,
+                   done_shutdown_event, server,
+                   &server->shutdown_tags[i].completion);
   }
 }
 
@@ -411,10 +518,10 @@
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
   if (md->key == chand->path_key) {
-    calld->path = grpc_mdstr_ref(md->value);
+    calld->path = GRPC_MDSTR_REF(md->value);
     return NULL;
   } else if (md->key == chand->authority_key) {
-    calld->host = grpc_mdstr_ref(md->value);
+    calld->host = GRPC_MDSTR_REF(md->value);
     return NULL;
   }
   return md;
@@ -423,7 +530,6 @@
 static void server_on_recv(void *ptr, int success) {
   grpc_call_element *elem = ptr;
   call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
 
   if (success && !calld->got_initial_metadata) {
     size_t i;
@@ -433,7 +539,8 @@
       grpc_stream_op *op = &ops[i];
       if (op->type != GRPC_OP_METADATA) continue;
       grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem);
-      if (0 != gpr_time_cmp(op->data.metadata.deadline, gpr_inf_future)) {
+      if (0 != gpr_time_cmp(op->data.metadata.deadline,
+                            gpr_inf_future(GPR_CLOCK_REALTIME))) {
         calld->deadline = op->data.metadata.deadline;
       }
       calld->got_initial_metadata = 1;
@@ -448,38 +555,39 @@
     case GRPC_STREAM_SEND_CLOSED:
       break;
     case GRPC_STREAM_RECV_CLOSED:
-      gpr_mu_lock(&chand->server->mu);
+      gpr_mu_lock(&calld->mu_state);
       if (calld->state == NOT_STARTED) {
         calld->state = ZOMBIED;
+        gpr_mu_unlock(&calld->mu_state);
         grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
         grpc_iomgr_add_callback(&calld->kill_zombie_closure);
+      } else {
+        gpr_mu_unlock(&calld->mu_state);
       }
-      gpr_mu_unlock(&chand->server->mu);
       break;
     case GRPC_STREAM_CLOSED:
-      gpr_mu_lock(&chand->server->mu);
+      gpr_mu_lock(&calld->mu_state);
       if (calld->state == NOT_STARTED) {
         calld->state = ZOMBIED;
+        gpr_mu_unlock(&calld->mu_state);
         grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
         grpc_iomgr_add_callback(&calld->kill_zombie_closure);
       } else if (calld->state == PENDING) {
-        call_list_remove(calld, PENDING_START);
         calld->state = ZOMBIED;
-        grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-        grpc_iomgr_add_callback(&calld->kill_zombie_closure);
-
+        gpr_mu_unlock(&calld->mu_state);
+        /* zombied call will be destroyed when it's removed from the pending
+           queue... later */
+      } else {
+        gpr_mu_unlock(&calld->mu_state);
       }
-      if (call_list_remove(calld, ALL_CALLS)) {
-        maybe_finish_shutdown(chand->server);
-      }
-      gpr_mu_unlock(&chand->server->mu);
       break;
   }
 
-  calld->on_done_recv(calld->recv_user_data, success);
+  calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
 }
 
-static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+static void server_mutate_op(grpc_call_element *elem,
+                             grpc_transport_stream_op *op) {
   call_data *calld = elem->call_data;
 
   if (op->recv_ops) {
@@ -487,80 +595,55 @@
     calld->recv_ops = op->recv_ops;
     calld->recv_state = op->recv_state;
     calld->on_done_recv = op->on_done_recv;
-    calld->recv_user_data = op->recv_user_data;
-    op->on_done_recv = server_on_recv;
-    op->recv_user_data = elem;
+    op->on_done_recv = &calld->server_on_recv;
   }
 }
 
-static void server_start_transport_op(grpc_call_element *elem,
-                                      grpc_transport_op *op) {
+static void server_start_transport_stream_op(grpc_call_element *elem,
+                                             grpc_transport_stream_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   server_mutate_op(elem, op);
   grpc_call_next_op(elem, op);
 }
 
-static void channel_op(grpc_channel_element *elem,
-                       grpc_channel_element *from_elem, grpc_channel_op *op) {
-  channel_data *chand = elem->channel_data;
-  grpc_server *server = chand->server;
-
-  switch (op->type) {
-    case GRPC_ACCEPT_CALL:
-      /* create a call */
-      grpc_call_create(chand->channel, NULL,
-                       op->data.accept_call.transport_server_data, NULL, 0,
-                       gpr_inf_future);
-      break;
-    case GRPC_TRANSPORT_CLOSED:
-      /* if the transport is closed for a server channel, we destroy the
-         channel */
-      gpr_mu_lock(&server->mu);
-      server_ref(server);
-      destroy_channel(chand);
-      gpr_mu_unlock(&server->mu);
-      server_unref(server);
-      break;
-    case GRPC_TRANSPORT_GOAWAY:
-      gpr_slice_unref(op->data.goaway.message);
-      break;
-    default:
-      GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
-      grpc_channel_next_op(elem, op);
-      break;
-  }
-}
-
-static void finish_shutdown_channel(void *cd, int success) {
+static void accept_stream(void *cd, grpc_transport *transport,
+                          const void *transport_server_data) {
   channel_data *chand = cd;
-  grpc_channel_op op;
-  op.type = GRPC_CHANNEL_DISCONNECT;
-  op.dir = GRPC_CALL_DOWN;
-  channel_op(grpc_channel_stack_element(
-                 grpc_channel_get_channel_stack(chand->channel), 0),
-             NULL, &op);
-  grpc_channel_internal_unref(chand->channel);
+  /* create a call */
+  grpc_call_create(chand->channel, NULL, transport_server_data, NULL, 0,
+                   gpr_inf_future(GPR_CLOCK_REALTIME));
 }
 
-static void shutdown_channel(channel_data *chand) {
-  grpc_channel_internal_ref(chand->channel);
-  chand->finish_shutdown_channel_closure.cb = finish_shutdown_channel;
-  chand->finish_shutdown_channel_closure.cb_arg = chand;
-  grpc_iomgr_add_callback(&chand->finish_shutdown_channel_closure);
+static void channel_connectivity_changed(void *cd, int iomgr_status_ignored) {
+  channel_data *chand = cd;
+  grpc_server *server = chand->server;
+  if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
+    grpc_transport_op op;
+    memset(&op, 0, sizeof(op));
+    op.on_connectivity_state_change = &chand->channel_connectivity_changed,
+    op.connectivity_state = &chand->connectivity_state;
+    grpc_channel_next_op(grpc_channel_stack_element(
+                             grpc_channel_get_channel_stack(chand->channel), 0),
+                         &op);
+  } else {
+    gpr_mu_lock(&server->mu_global);
+    destroy_channel(chand);
+    gpr_mu_unlock(&server->mu_global);
+    GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "connectivity");
+  }
 }
 
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   memset(calld, 0, sizeof(call_data));
-  calld->deadline = gpr_inf_future;
+  calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
   calld->call = grpc_call_from_top_element(elem);
+  gpr_mu_init(&calld->mu_state);
 
-  gpr_mu_lock(&chand->server->mu);
-  call_list_join(&chand->server->lists[ALL_CALLS], calld, ALL_CALLS);
-  gpr_mu_unlock(&chand->server->mu);
+  grpc_iomgr_closure_init(&calld->server_on_recv, server_on_recv, elem);
 
   server_ref(chand->server);
 
@@ -570,29 +653,22 @@
 static void destroy_call_elem(grpc_call_element *elem) {
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
-  int removed[CALL_LIST_COUNT];
-  size_t i;
 
-  gpr_mu_lock(&chand->server->mu);
-  for (i = 0; i < CALL_LIST_COUNT; i++) {
-    removed[i] = call_list_remove(elem->call_data, i);
-  }
-  if (removed[ALL_CALLS]) {
-    maybe_finish_shutdown(chand->server);
-  }
-  gpr_mu_unlock(&chand->server->mu);
+  GPR_ASSERT(calld->state != PENDING);
 
   if (calld->host) {
-    grpc_mdstr_unref(calld->host);
+    GRPC_MDSTR_UNREF(calld->host);
   }
   if (calld->path) {
-    grpc_mdstr_unref(calld->path);
+    GRPC_MDSTR_UNREF(calld->path);
   }
 
+  gpr_mu_destroy(&calld->mu_state);
+
   server_unref(chand->server);
 }
 
-static void init_channel_elem(grpc_channel_element *elem,
+static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
                               int is_last) {
@@ -605,6 +681,9 @@
   chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
   chand->next = chand->prev = chand;
   chand->registered_methods = NULL;
+  chand->connectivity_state = GRPC_CHANNEL_IDLE;
+  grpc_iomgr_closure_init(&chand->channel_connectivity_changed,
+                          channel_connectivity_changed, chand);
 }
 
 static void destroy_channel_elem(grpc_channel_element *elem) {
@@ -613,29 +692,30 @@
   if (chand->registered_methods) {
     for (i = 0; i < chand->registered_method_slots; i++) {
       if (chand->registered_methods[i].method) {
-        grpc_mdstr_unref(chand->registered_methods[i].method);
+        GRPC_MDSTR_UNREF(chand->registered_methods[i].method);
       }
       if (chand->registered_methods[i].host) {
-        grpc_mdstr_unref(chand->registered_methods[i].host);
+        GRPC_MDSTR_UNREF(chand->registered_methods[i].host);
       }
     }
     gpr_free(chand->registered_methods);
   }
   if (chand->server) {
-    gpr_mu_lock(&chand->server->mu);
+    gpr_mu_lock(&chand->server->mu_global);
     chand->next->prev = chand->prev;
     chand->prev->next = chand->next;
     chand->next = chand->prev = chand;
-    gpr_mu_unlock(&chand->server->mu);
-    grpc_mdstr_unref(chand->path_key);
-    grpc_mdstr_unref(chand->authority_key);
+    maybe_finish_shutdown(chand->server);
+    gpr_mu_unlock(&chand->server->mu_global);
+    GRPC_MDSTR_UNREF(chand->path_key);
+    GRPC_MDSTR_UNREF(chand->authority_key);
     server_unref(chand->server);
   }
 }
 
 static const grpc_channel_filter server_surface_filter = {
-    server_start_transport_op,
-    channel_op,
+    server_start_transport_stream_op,
+    grpc_channel_next_op,
     sizeof(call_data),
     init_call_elem,
     destroy_call_elem,
@@ -651,16 +731,17 @@
   for (i = 0; i < server->cq_count; i++) {
     if (server->cqs[i] == cq) return;
   }
-  grpc_cq_internal_ref(cq);
+  GRPC_CQ_INTERNAL_REF(cq, "server");
+  grpc_cq_mark_server_cq(cq);
   n = server->cq_count++;
   server->cqs = gpr_realloc(server->cqs,
                             server->cq_count * sizeof(grpc_completion_queue *));
   server->cqs[n] = cq;
 }
 
-grpc_server *grpc_server_create_from_filters(grpc_channel_filter **filters,
-                                             size_t filter_count,
-                                             const grpc_channel_args *args) {
+grpc_server *grpc_server_create_from_filters(
+    const grpc_channel_filter **filters, size_t filter_count,
+    const grpc_channel_args *args) {
   size_t i;
   /* TODO(census): restore this once we finalize census filter etc.
      int census_enabled = grpc_channel_args_is_census_enabled(args); */
@@ -672,13 +753,26 @@
 
   memset(server, 0, sizeof(grpc_server));
 
-  gpr_mu_init(&server->mu);
+  gpr_mu_init(&server->mu_global);
+  gpr_mu_init(&server->mu_call);
 
   /* decremented by grpc_server_destroy */
   gpr_ref_init(&server->internal_refcount, 1);
   server->root_channel_data.next = server->root_channel_data.prev =
       &server->root_channel_data;
 
+  /* TODO(ctiller): expose a channel_arg for this */
+  server->max_requested_calls = 32768;
+  server->request_freelist =
+      gpr_stack_lockfree_create(server->max_requested_calls);
+  for (i = 0; i < (size_t)server->max_requested_calls; i++) {
+    gpr_stack_lockfree_push(server->request_freelist, i);
+  }
+  request_matcher_init(&server->unregistered_request_matcher,
+                       server->max_requested_calls);
+  server->requested_calls = gpr_malloc(server->max_requested_calls *
+                                       sizeof(*server->requested_calls));
+
   /* Server filter stack is:
 
      server_surface_filter - for making surface API calls
@@ -713,7 +807,8 @@
                                   const char *host) {
   registered_method *m;
   if (!method) {
-    gpr_log(GPR_ERROR, "grpc_server_register_method method string cannot be NULL");
+    gpr_log(GPR_ERROR,
+            "grpc_server_register_method method string cannot be NULL");
     return NULL;
   }
   for (m = server->registered_methods; m; m = m->next) {
@@ -725,6 +820,7 @@
   }
   m = gpr_malloc(sizeof(registered_method));
   memset(m, 0, sizeof(*m));
+  request_matcher_init(&m->request_matcher, server->max_requested_calls);
   m->method = gpr_strdup(method);
   m->host = gpr_strdup(host);
   m->next = server->registered_methods;
@@ -746,10 +842,10 @@
   }
 }
 
-grpc_transport_setup_result grpc_server_setup_transport(
-    grpc_server *s, grpc_transport *transport,
-    grpc_channel_filter const **extra_filters, size_t num_extra_filters,
-    grpc_mdctx *mdctx, const grpc_channel_args *args) {
+void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
+                                 grpc_channel_filter const **extra_filters,
+                                 size_t num_extra_filters, grpc_mdctx *mdctx,
+                                 const grpc_channel_args *args) {
   size_t num_filters = s->channel_filter_count + num_extra_filters + 1;
   grpc_channel_filter const **filters =
       gpr_malloc(sizeof(grpc_channel_filter *) * num_filters);
@@ -766,7 +862,7 @@
   gpr_uint32 slots;
   gpr_uint32 probes;
   gpr_uint32 max_probes = 0;
-  grpc_transport_setup_result result;
+  grpc_transport_op op;
 
   for (i = 0; i < s->channel_filter_count; i++) {
     filters[i] = s->channel_filters[i];
@@ -777,7 +873,9 @@
   filters[i] = &grpc_connected_channel_filter;
 
   for (i = 0; i < s->cq_count; i++) {
-    grpc_transport_add_to_pollset(transport, grpc_cq_pollset(s->cqs[i]));
+    memset(&op, 0, sizeof(op));
+    op.bind_pollset = grpc_cq_pollset(s->cqs[i]);
+    grpc_transport_perform_op(transport, &op);
   }
 
   channel =
@@ -818,168 +916,139 @@
     chand->registered_method_max_probes = max_probes;
   }
 
-  result = grpc_connected_channel_bind_transport(
-      grpc_channel_get_channel_stack(channel), transport);
+  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
+                                        transport);
 
-  gpr_mu_lock(&s->mu);
+  gpr_mu_lock(&s->mu_global);
   chand->next = &s->root_channel_data;
   chand->prev = chand->next->prev;
   chand->next->prev = chand->prev->next = chand;
-  gpr_mu_unlock(&s->mu);
+  gpr_mu_unlock(&s->mu_global);
 
   gpr_free(filters);
 
-  return result;
+  GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
+  memset(&op, 0, sizeof(op));
+  op.set_accept_stream = accept_stream;
+  op.set_accept_stream_user_data = chand;
+  op.on_connectivity_state_change = &chand->channel_connectivity_changed;
+  op.connectivity_state = &chand->connectivity_state;
+  grpc_transport_perform_op(transport, &op);
+}
+
+typedef struct {
+  requested_call **requests;
+  size_t count;
+  size_t capacity;
+} request_killer;
+
+static void request_killer_init(request_killer *rk) {
+  memset(rk, 0, sizeof(*rk));
+}
+
+static void request_killer_add(request_killer *rk, requested_call *rc) {
+  if (rk->capacity == rk->count) {
+    rk->capacity = GPR_MAX(8, rk->capacity * 2);
+    rk->requests =
+        gpr_realloc(rk->requests, rk->capacity * sizeof(*rk->requests));
+  }
+  rk->requests[rk->count++] = rc;
+}
+
+static void request_killer_add_request_matcher(request_killer *rk,
+                                               grpc_server *server,
+                                               request_matcher *rm) {
+  int request_id;
+  while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) {
+    request_killer_add(rk, &server->requested_calls[request_id]);
+  }
+}
+
+static void request_killer_run(request_killer *rk, grpc_server *server) {
+  size_t i;
+  for (i = 0; i < rk->count; i++) {
+    fail_call(server, rk->requests[i]);
+  }
+  gpr_free(rk->requests);
 }
 
 void grpc_server_shutdown_and_notify(grpc_server *server,
                                      grpc_completion_queue *cq, void *tag) {
   listener *l;
-  requested_call_array requested_calls;
-  channel_data **channels;
-  channel_data *c;
-  size_t nchannels;
-  size_t i;
-  grpc_channel_op op;
-  grpc_channel_element *elem;
   registered_method *rm;
   shutdown_tag *sdt;
+  channel_broadcaster broadcaster;
+  request_killer reqkill;
 
   /* lock, and gather up some stuff to do */
-  gpr_mu_lock(&server->mu);
-  grpc_cq_begin_op(cq, NULL);
+  gpr_mu_lock(&server->mu_global);
+  grpc_cq_begin_op(cq);
   server->shutdown_tags =
       gpr_realloc(server->shutdown_tags,
                   sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
   sdt = &server->shutdown_tags[server->num_shutdown_tags++];
   sdt->tag = tag;
   sdt->cq = cq;
-  if (server->shutdown) {
-    gpr_mu_unlock(&server->mu);
+  if (gpr_atm_acq_load(&server->shutdown_flag)) {
+    gpr_mu_unlock(&server->mu_global);
     return;
   }
 
-  nchannels = 0;
-  for (c = server->root_channel_data.next; c != &server->root_channel_data;
-       c = c->next) {
-    nchannels++;
-  }
-  channels = gpr_malloc(sizeof(channel_data *) * nchannels);
-  i = 0;
-  for (c = server->root_channel_data.next; c != &server->root_channel_data;
-       c = c->next) {
-    grpc_channel_internal_ref(c->channel);
-    channels[i] = c;
-    i++;
-  }
+  server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
+
+  channel_broadcaster_init(server, &broadcaster);
+  request_killer_init(&reqkill);
 
   /* collect all unregistered then registered calls */
-  requested_calls = server->requested_calls;
-  memset(&server->requested_calls, 0, sizeof(server->requested_calls));
+  gpr_mu_lock(&server->mu_call);
+  request_killer_add_request_matcher(&reqkill, server,
+                                     &server->unregistered_request_matcher);
+  request_matcher_zombify_all_pending_calls(
+      &server->unregistered_request_matcher);
   for (rm = server->registered_methods; rm; rm = rm->next) {
-    if (requested_calls.count + rm->requested.count >
-        requested_calls.capacity) {
-      requested_calls.capacity =
-          GPR_MAX(requested_calls.count + rm->requested.count,
-                  2 * requested_calls.capacity);
-      requested_calls.calls =
-          gpr_realloc(requested_calls.calls, sizeof(*requested_calls.calls) *
-                                                 requested_calls.capacity);
-    }
-    memcpy(requested_calls.calls + requested_calls.count, rm->requested.calls,
-           sizeof(*requested_calls.calls) * rm->requested.count);
-    requested_calls.count += rm->requested.count;
-    gpr_free(rm->requested.calls);
-    memset(&rm->requested, 0, sizeof(rm->requested));
+    request_killer_add_request_matcher(&reqkill, server, &rm->request_matcher);
+    request_matcher_zombify_all_pending_calls(&rm->request_matcher);
   }
+  gpr_mu_unlock(&server->mu_call);
 
-  server->shutdown = 1;
+  gpr_atm_rel_store(&server->shutdown_flag, 1);
   maybe_finish_shutdown(server);
-  gpr_mu_unlock(&server->mu);
-
-  for (i = 0; i < nchannels; i++) {
-    c = channels[i];
-    elem = grpc_channel_stack_element(
-        grpc_channel_get_channel_stack(c->channel), 0);
-
-    op.type = GRPC_CHANNEL_GOAWAY;
-    op.dir = GRPC_CALL_DOWN;
-    op.data.goaway.status = GRPC_STATUS_OK;
-    op.data.goaway.message = gpr_slice_from_copied_string("Server shutdown");
-    elem->filter->channel_op(elem, NULL, &op);
-
-    grpc_channel_internal_unref(c->channel);
-  }
-  gpr_free(channels);
+  gpr_mu_unlock(&server->mu_global);
 
   /* terminate all the requested calls */
-  for (i = 0; i < requested_calls.count; i++) {
-    fail_call(server, &requested_calls.calls[i]);
-  }
-  gpr_free(requested_calls.calls);
+  request_killer_run(&reqkill, server);
 
   /* Shutdown listeners */
   for (l = server->listeners; l; l = l->next) {
     l->destroy(server, l->arg);
   }
+
+  channel_broadcaster_shutdown(&broadcaster, 1, 0);
 }
 
 void grpc_server_listener_destroy_done(void *s) {
   grpc_server *server = s;
-  gpr_mu_lock(&server->mu);
+  gpr_mu_lock(&server->mu_global);
   server->listeners_destroyed++;
   maybe_finish_shutdown(server);
-  gpr_mu_unlock(&server->mu);
+  gpr_mu_unlock(&server->mu_global);
 }
 
 void grpc_server_cancel_all_calls(grpc_server *server) {
-  call_data *calld;
-  grpc_call **calls;
-  size_t call_count;
-  size_t call_capacity;
-  int is_first = 1;
-  size_t i;
+  channel_broadcaster broadcaster;
 
-  gpr_mu_lock(&server->mu);
+  gpr_mu_lock(&server->mu_global);
+  channel_broadcaster_init(server, &broadcaster);
+  gpr_mu_unlock(&server->mu_global);
 
-  GPR_ASSERT(server->shutdown);
-
-  if (!server->lists[ALL_CALLS]) {
-    gpr_mu_unlock(&server->mu);
-    return;
-  }
-
-  call_capacity = 8;
-  call_count = 0;
-  calls = gpr_malloc(sizeof(grpc_call *) * call_capacity);
-
-  for (calld = server->lists[ALL_CALLS]; calld != server->lists[ALL_CALLS] || is_first; calld = calld->links[ALL_CALLS].next) {
-    if (call_count == call_capacity) {
-      call_capacity *= 2;
-      calls = gpr_realloc(calls, sizeof(grpc_call *) * call_capacity);
-    }
-    calls[call_count++] = calld->call;
-    GRPC_CALL_INTERNAL_REF(calld->call, "cancel_all");
-    is_first = 0;
-  }
-
-  gpr_mu_unlock(&server->mu);
-
-  for (i = 0; i < call_count; i++) {
-    grpc_call_cancel_with_status(calls[i], GRPC_STATUS_UNAVAILABLE, "Unavailable");
-    GRPC_CALL_INTERNAL_UNREF(calls[i], "cancel_all", 1);
-  }
-
-  gpr_free(calls);
+  channel_broadcaster_shutdown(&broadcaster, 0, 1);
 }
 
 void grpc_server_destroy(grpc_server *server) {
-  channel_data *c;
   listener *l;
-  call_data *calld;
 
-  gpr_mu_lock(&server->mu);
-  GPR_ASSERT(server->shutdown || !server->listeners);
+  gpr_mu_lock(&server->mu_global);
+  GPR_ASSERT(gpr_atm_acq_load(&server->shutdown_flag) || !server->listeners);
   GPR_ASSERT(server->listeners_destroyed == num_listeners(server));
 
   while (server->listeners) {
@@ -988,20 +1057,7 @@
     gpr_free(l);
   }
 
-  while ((calld = call_list_remove_head(&server->lists[PENDING_START],
-                                        PENDING_START)) != NULL) {
-    calld->state = ZOMBIED;
-    grpc_iomgr_closure_init(
-        &calld->kill_zombie_closure, kill_zombie,
-        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-    grpc_iomgr_add_callback(&calld->kill_zombie_closure);
-  }
-
-  for (c = server->root_channel_data.next; c != &server->root_channel_data;
-       c = c->next) {
-    shutdown_channel(c);
-  }
-  gpr_mu_unlock(&server->mu);
+  gpr_mu_unlock(&server->mu_global);
 
   server_unref(server);
 }
@@ -1022,36 +1078,55 @@
 static grpc_call_error queue_call_request(grpc_server *server,
                                           requested_call *rc) {
   call_data *calld = NULL;
-  requested_call_array *requested_calls = NULL;
-  gpr_mu_lock(&server->mu);
-  if (server->shutdown) {
-    gpr_mu_unlock(&server->mu);
+  request_matcher *request_matcher = NULL;
+  int request_id;
+  if (gpr_atm_acq_load(&server->shutdown_flag)) {
+    fail_call(server, rc);
+    return GRPC_CALL_OK;
+  }
+  request_id = gpr_stack_lockfree_pop(server->request_freelist);
+  if (request_id == -1) {
+    /* out of request ids: just fail this one */
     fail_call(server, rc);
     return GRPC_CALL_OK;
   }
   switch (rc->type) {
     case BATCH_CALL:
-      calld =
-          call_list_remove_head(&server->lists[PENDING_START], PENDING_START);
-      requested_calls = &server->requested_calls;
+      request_matcher = &server->unregistered_request_matcher;
       break;
     case REGISTERED_CALL:
-      calld = call_list_remove_head(
-          &rc->data.registered.registered_method->pending, PENDING_START);
-      requested_calls = &rc->data.registered.registered_method->requested;
+      request_matcher = &rc->data.registered.registered_method->request_matcher;
       break;
   }
-  if (calld) {
-    GPR_ASSERT(calld->state == PENDING);
-    calld->state = ACTIVATED;
-    gpr_mu_unlock(&server->mu);
-    begin_call(server, calld, rc);
-    return GRPC_CALL_OK;
-  } else {
-    *requested_call_array_add(requested_calls) = *rc;
-    gpr_mu_unlock(&server->mu);
-    return GRPC_CALL_OK;
+  server->requested_calls[request_id] = *rc;
+  gpr_free(rc);
+  if (gpr_stack_lockfree_push(request_matcher->requests, request_id)) {
+    /* this was the first queued request: we need to lock and start
+       matching calls */
+    gpr_mu_lock(&server->mu_call);
+    while ((calld = request_matcher->pending_head) != NULL) {
+      request_id = gpr_stack_lockfree_pop(request_matcher->requests);
+      if (request_id == -1) break;
+      request_matcher->pending_head = calld->pending_next;
+      gpr_mu_unlock(&server->mu_call);
+      gpr_mu_lock(&calld->mu_state);
+      if (calld->state == ZOMBIED) {
+        gpr_mu_unlock(&calld->mu_state);
+        grpc_iomgr_closure_init(
+            &calld->kill_zombie_closure, kill_zombie,
+            grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
+        grpc_iomgr_add_callback(&calld->kill_zombie_closure);
+      } else {
+        GPR_ASSERT(calld->state == PENDING);
+        calld->state = ACTIVATED;
+        gpr_mu_unlock(&calld->mu_state);
+        begin_call(server, calld, &server->requested_calls[request_id]);
+      }
+      gpr_mu_lock(&server->mu_call);
+    }
+    gpr_mu_unlock(&server->mu_call);
   }
+  return GRPC_CALL_OK;
 }
 
 grpc_call_error grpc_server_request_call(
@@ -1059,19 +1134,24 @@
     grpc_metadata_array *initial_metadata,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag) {
-  requested_call rc;
+  requested_call *rc = gpr_malloc(sizeof(*rc));
   GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details,
                                initial_metadata, cq_bound_to_call,
                                cq_for_notification, tag);
-  grpc_cq_begin_op(cq_for_notification, NULL);
-  rc.type = BATCH_CALL;
-  rc.tag = tag;
-  rc.cq_bound_to_call = cq_bound_to_call;
-  rc.cq_for_notification = cq_for_notification;
-  rc.call = call;
-  rc.data.batch.details = details;
-  rc.data.batch.initial_metadata = initial_metadata;
-  return queue_call_request(server, &rc);
+  if (!grpc_cq_is_server_cq(cq_for_notification)) {
+    gpr_free(rc);
+    return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+  }
+  grpc_cq_begin_op(cq_for_notification);
+  rc->type = BATCH_CALL;
+  rc->server = server;
+  rc->tag = tag;
+  rc->cq_bound_to_call = cq_bound_to_call;
+  rc->cq_for_notification = cq_for_notification;
+  rc->call = call;
+  rc->data.batch.details = details;
+  rc->data.batch.initial_metadata = initial_metadata;
+  return queue_call_request(server, rc);
 }
 
 grpc_call_error grpc_server_request_registered_call(
@@ -1079,19 +1159,24 @@
     grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag) {
-  requested_call rc;
+  requested_call *rc = gpr_malloc(sizeof(*rc));
   registered_method *registered_method = rm;
-  grpc_cq_begin_op(cq_for_notification, NULL);
-  rc.type = REGISTERED_CALL;
-  rc.tag = tag;
-  rc.cq_bound_to_call = cq_bound_to_call;
-  rc.cq_for_notification = cq_for_notification;
-  rc.call = call;
-  rc.data.registered.registered_method = registered_method;
-  rc.data.registered.deadline = deadline;
-  rc.data.registered.initial_metadata = initial_metadata;
-  rc.data.registered.optional_payload = optional_payload;
-  return queue_call_request(server, &rc);
+  if (!grpc_cq_is_server_cq(cq_for_notification)) {
+    gpr_free(rc);
+    return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+  }
+  grpc_cq_begin_op(cq_for_notification);
+  rc->type = REGISTERED_CALL;
+  rc->server = server;
+  rc->tag = tag;
+  rc->cq_bound_to_call = cq_bound_to_call;
+  rc->cq_for_notification = cq_for_notification;
+  rc->call = call;
+  rc->data.registered.registered_method = registered_method;
+  rc->data.registered.deadline = deadline;
+  rc->data.registered.initial_metadata = initial_metadata;
+  rc->data.registered.optional_payload = optional_payload;
+  return queue_call_request(server, rc);
 }
 
 static void publish_registered_or_batch(grpc_call *call, int success,
@@ -1128,6 +1213,8 @@
   calld->cq_new = rc->cq_for_notification;
   switch (rc->type) {
     case BATCH_CALL:
+      GPR_ASSERT(calld->host != NULL);
+      GPR_ASSERT(calld->path != NULL);
       cpstr(&rc->data.batch.details->host,
             &rc->data.batch.details->host_capacity, calld->host);
       cpstr(&rc->data.batch.details->method,
@@ -1156,8 +1243,20 @@
   }
 
   GRPC_CALL_INTERNAL_REF(calld->call, "server");
-  grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish,
-                                      rc->tag);
+  grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc);
+}
+
+static void done_request_event(void *req, grpc_cq_completion *c) {
+  requested_call *rc = req;
+  grpc_server *server = rc->server;
+
+  if (rc >= server->requested_calls &&
+      rc < server->requested_calls + server->max_requested_calls) {
+    gpr_stack_lockfree_push(server->request_freelist,
+                            rc - server->requested_calls);
+  } else {
+    gpr_free(req);
+  }
 }
 
 static void fail_call(grpc_server *server, requested_call *rc) {
@@ -1170,15 +1269,19 @@
       rc->data.registered.initial_metadata->count = 0;
       break;
   }
-  grpc_cq_end_op(rc->cq_for_notification, rc->tag, NULL, 0);
+  grpc_cq_end_op(rc->cq_for_notification, rc->tag, 0, done_request_event, rc,
+                 &rc->completion);
 }
 
 static void publish_registered_or_batch(grpc_call *call, int success,
-                                        void *tag) {
+                                        void *prc) {
   grpc_call_element *elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
+  requested_call *rc = prc;
   call_data *calld = elem->call_data;
-  grpc_cq_end_op(calld->cq_new, tag, call, success);
+  grpc_cq_end_op(calld->cq_new, rc->tag, success, done_request_event, rc,
+                 &rc->completion);
+  GRPC_CALL_INTERNAL_UNREF(call, "server", 0);
 }
 
 const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
@@ -1187,9 +1290,8 @@
 
 int grpc_server_has_open_connections(grpc_server *server) {
   int r;
-  gpr_mu_lock(&server->mu);
+  gpr_mu_lock(&server->mu_global);
   r = server->root_channel_data.next != &server->root_channel_data;
-  gpr_mu_unlock(&server->mu);
+  gpr_mu_unlock(&server->mu_global);
   return r;
 }
-
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index 91a1a2a..c638d68 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -39,9 +39,9 @@
 #include "src/core/transport/transport.h"
 
 /* Create a server */
-grpc_server *grpc_server_create_from_filters(grpc_channel_filter **filters,
-                                             size_t filter_count,
-                                             const grpc_channel_args *args);
+grpc_server *grpc_server_create_from_filters(
+    const grpc_channel_filter **filters, size_t filter_count,
+    const grpc_channel_args *args);
 
 /* Add a listener to the server: when the server starts, it will call start,
    and when it shuts down, it will call destroy */
@@ -55,10 +55,10 @@
 
 /* Setup a transport - creates a channel stack, binds the transport to the
    server */
-grpc_transport_setup_result grpc_server_setup_transport(
-    grpc_server *server, grpc_transport *transport,
-    grpc_channel_filter const **extra_filters, size_t num_extra_filters,
-    grpc_mdctx *mdctx, const grpc_channel_args *args);
+void grpc_server_setup_transport(grpc_server *server, grpc_transport *transport,
+                                 grpc_channel_filter const **extra_filters,
+                                 size_t num_extra_filters, grpc_mdctx *mdctx,
+                                 const grpc_channel_args *args);
 
 const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
 
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 7e49a53..78c5346 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -42,14 +42,13 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-static grpc_transport_setup_result setup_transport(void *server,
-                                                   grpc_transport *transport,
-                                                   grpc_mdctx *mdctx) {
+static void setup_transport(void *server, grpc_transport *transport,
+                            grpc_mdctx *mdctx) {
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  return grpc_server_setup_transport(server, transport, extra_filters,
-                                     GPR_ARRAY_SIZE(extra_filters), mdctx,
-                                     grpc_server_get_channel_args(server));
+  grpc_server_setup_transport(server, transport, extra_filters,
+                              GPR_ARRAY_SIZE(extra_filters), mdctx,
+                              grpc_server_get_channel_args(server));
 }
 
 static void new_transport(void *server, grpc_endpoint *tcp) {
@@ -60,9 +59,11 @@
    * (as in server_secure_chttp2.c) needs to add synchronization to avoid this
    * case.
    */
-  grpc_create_chttp2_transport(setup_transport, server,
-                               grpc_server_get_channel_args(server), tcp, NULL,
-                               0, grpc_mdctx_create(), 0);
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+  grpc_transport *transport = grpc_create_chttp2_transport(
+      grpc_server_get_channel_args(server), tcp, mdctx, 0);
+  setup_transport(server, transport, mdctx);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 /* Server callback: start listening on our ports */
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
index b739067..1e26c67 100644
--- a/src/core/surface/server_create.c
+++ b/src/core/surface/server_create.c
@@ -34,7 +34,10 @@
 #include <grpc/grpc.h>
 #include "src/core/surface/completion_queue.h"
 #include "src/core/surface/server.h"
+#include "src/core/channel/compress_filter.h"
 
 grpc_server *grpc_server_create(const grpc_channel_args *args) {
-  return grpc_server_create_from_filters(NULL, 0, args);
+  const grpc_channel_filter *filters[] = {&grpc_compress_filter};
+  return grpc_server_create_from_filters(filters, GPR_ARRAY_SIZE(filters),
+                                         args);
 }
diff --git a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h b/src/core/surface/version.c
similarity index 89%
rename from src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
rename to src/core/surface/version.c
index 28c7374..4f5d648 100644
--- a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
+++ b/src/core/surface/version.c
@@ -31,10 +31,11 @@
  *
  */
 
-#import <Foundation/Foundation.h>
+/* This file is autogenerated from:
+   templates/src/core/surface/version.c.template */
 
-#import "GRPCMethodName.h"
+#include <grpc/grpc.h>
 
-@interface GRPCMethodName (HTTP2Encoding)
-- (NSString *)HTTP2Path;
-@end
+const char *grpc_version_string(void) {
+	return "0.10.0.0";
+}
diff --git a/src/core/transport/chttp2/alpn.h b/src/core/transport/chttp2/alpn.h
index fcbefc0..f38b4c3 100644
--- a/src/core/transport/chttp2/alpn.h
+++ b/src/core/transport/chttp2/alpn.h
@@ -46,4 +46,4 @@
  * grpc_chttp2_num_alpn_versions()) */
 const char *grpc_chttp2_get_alpn_version_index(size_t i);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_ALPN_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_ALPN_H */
diff --git a/src/core/transport/chttp2/bin_encoder.c b/src/core/transport/chttp2/bin_encoder.c
index f5ca6c4..dee6dbe 100644
--- a/src/core/transport/chttp2/bin_encoder.c
+++ b/src/core/transport/chttp2/bin_encoder.c
@@ -46,70 +46,18 @@
   gpr_uint8 length;
 } b64_huff_sym;
 
-static const b64_huff_sym huff_alphabet[64] = {{0x21, 6},
-                                               {0x5d, 7},
-                                               {0x5e, 7},
-                                               {0x5f, 7},
-                                               {0x60, 7},
-                                               {0x61, 7},
-                                               {0x62, 7},
-                                               {0x63, 7},
-                                               {0x64, 7},
-                                               {0x65, 7},
-                                               {0x66, 7},
-                                               {0x67, 7},
-                                               {0x68, 7},
-                                               {0x69, 7},
-                                               {0x6a, 7},
-                                               {0x6b, 7},
-                                               {0x6c, 7},
-                                               {0x6d, 7},
-                                               {0x6e, 7},
-                                               {0x6f, 7},
-                                               {0x70, 7},
-                                               {0x71, 7},
-                                               {0x72, 7},
-                                               {0xfc, 8},
-                                               {0x73, 7},
-                                               {0xfd, 8},
-                                               {0x3, 5},
-                                               {0x23, 6},
-                                               {0x4, 5},
-                                               {0x24, 6},
-                                               {0x5, 5},
-                                               {0x25, 6},
-                                               {0x26, 6},
-                                               {0x27, 6},
-                                               {0x6, 5},
-                                               {0x74, 7},
-                                               {0x75, 7},
-                                               {0x28, 6},
-                                               {0x29, 6},
-                                               {0x2a, 6},
-                                               {0x7, 5},
-                                               {0x2b, 6},
-                                               {0x76, 7},
-                                               {0x2c, 6},
-                                               {0x8, 5},
-                                               {0x9, 5},
-                                               {0x2d, 6},
-                                               {0x77, 7},
-                                               {0x78, 7},
-                                               {0x79, 7},
-                                               {0x7a, 7},
-                                               {0x7b, 7},
-                                               {0x0, 5},
-                                               {0x1, 5},
-                                               {0x2, 5},
-                                               {0x19, 6},
-                                               {0x1a, 6},
-                                               {0x1b, 6},
-                                               {0x1c, 6},
-                                               {0x1d, 6},
-                                               {0x1e, 6},
-                                               {0x1f, 6},
-                                               {0x7fb, 11},
-                                               {0x18, 6}};
+static const b64_huff_sym huff_alphabet[64] = {
+    {0x21, 6}, {0x5d, 7}, {0x5e, 7},   {0x5f, 7}, {0x60, 7}, {0x61, 7},
+    {0x62, 7}, {0x63, 7}, {0x64, 7},   {0x65, 7}, {0x66, 7}, {0x67, 7},
+    {0x68, 7}, {0x69, 7}, {0x6a, 7},   {0x6b, 7}, {0x6c, 7}, {0x6d, 7},
+    {0x6e, 7}, {0x6f, 7}, {0x70, 7},   {0x71, 7}, {0x72, 7}, {0xfc, 8},
+    {0x73, 7}, {0xfd, 8}, {0x3, 5},    {0x23, 6}, {0x4, 5},  {0x24, 6},
+    {0x5, 5},  {0x25, 6}, {0x26, 6},   {0x27, 6}, {0x6, 5},  {0x74, 7},
+    {0x75, 7}, {0x28, 6}, {0x29, 6},   {0x2a, 6}, {0x7, 5},  {0x2b, 6},
+    {0x76, 7}, {0x2c, 6}, {0x8, 5},    {0x9, 5},  {0x2d, 6}, {0x77, 7},
+    {0x78, 7}, {0x79, 7}, {0x7a, 7},   {0x7b, 7}, {0x0, 5},  {0x1, 5},
+    {0x2, 5},  {0x19, 6}, {0x1a, 6},   {0x1b, 6}, {0x1c, 6}, {0x1d, 6},
+    {0x1e, 6}, {0x1f, 6}, {0x7fb, 11}, {0x18, 6}};
 
 static const gpr_uint8 tail_xtra[3] = {0, 2, 3};
 
diff --git a/src/core/transport/chttp2/bin_encoder.h b/src/core/transport/chttp2/bin_encoder.h
index 9c88ac9..d3e5a85 100644
--- a/src/core/transport/chttp2/bin_encoder.h
+++ b/src/core/transport/chttp2/bin_encoder.h
@@ -53,4 +53,4 @@
 
 int grpc_is_binary_header(const char *key, size_t length);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H */
diff --git a/src/core/transport/chttp2/frame.h b/src/core/transport/chttp2/frame.h
index c9e3e13..879ee03 100644
--- a/src/core/transport/chttp2/frame.h
+++ b/src/core/transport/chttp2/frame.h
@@ -45,23 +45,9 @@
   GRPC_CHTTP2_CONNECTION_ERROR
 } grpc_chttp2_parse_error;
 
-typedef struct {
-  gpr_uint8 end_of_stream;
-  gpr_uint8 need_flush_reads;
-  gpr_uint8 metadata_boundary;
-  gpr_uint8 ack_settings;
-  gpr_uint8 send_ping_ack;
-  gpr_uint8 process_ping_reply;
-  gpr_uint8 goaway;
-  gpr_uint8 rst_stream;
-
-  gpr_int64 initial_window_update;
-  gpr_uint32 window_update;
-  gpr_uint32 goaway_last_stream_index;
-  gpr_uint32 goaway_error;
-  gpr_slice goaway_text;
-  gpr_uint32 rst_stream_reason;
-} grpc_chttp2_parse_state;
+/* defined in internal.h */
+typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing;
+typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing;
 
 #define GRPC_CHTTP2_FRAME_DATA 0
 #define GRPC_CHTTP2_FRAME_HEADER 1
@@ -80,4 +66,4 @@
 #define GRPC_CHTTP2_DATA_FLAG_PADDED 8
 #define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_H */
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index a1ae9ed..7a4c355 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -35,6 +35,7 @@
 
 #include <string.h>
 
+#include "src/core/transport/chttp2/internal.h"
 #include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -69,16 +70,16 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last) {
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
   grpc_chttp2_data_parser *p = parser;
+  gpr_uint32 message_flags = 0;
 
   if (is_last && p->is_last_frame) {
-    state->end_of_stream = 1;
-    state->need_flush_reads = 1;
+    stream_parsing->received_close = 1;
   }
 
   if (cur == end) {
@@ -89,67 +90,73 @@
   fh_0:
     case GRPC_CHTTP2_DATA_FH_0:
       p->frame_type = *cur;
-      if (++cur == end) {
-        p->state = GRPC_CHTTP2_DATA_FH_1;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
       switch (p->frame_type) {
         case 0:
+          /* noop */
           break;
         case 1:
-          gpr_log(GPR_ERROR, "Compressed GRPC frames not yet supported");
-          return GRPC_CHTTP2_STREAM_ERROR;
+          p->is_frame_compressed = 1;  /* GPR_TRUE */
+          break;
         default:
           gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
           return GRPC_CHTTP2_STREAM_ERROR;
       }
+      if (++cur == end) {
+        p->state = GRPC_CHTTP2_DATA_FH_1;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_1:
-      p->frame_size = ((gpr_uint32) * cur) << 24;
+      p->frame_size = ((gpr_uint32)*cur) << 24;
       if (++cur == end) {
         p->state = GRPC_CHTTP2_DATA_FH_2;
         return GRPC_CHTTP2_PARSE_OK;
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_2:
-      p->frame_size |= ((gpr_uint32) * cur) << 16;
+      p->frame_size |= ((gpr_uint32)*cur) << 16;
       if (++cur == end) {
         p->state = GRPC_CHTTP2_DATA_FH_3;
         return GRPC_CHTTP2_PARSE_OK;
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_3:
-      p->frame_size |= ((gpr_uint32) * cur) << 8;
+      p->frame_size |= ((gpr_uint32)*cur) << 8;
       if (++cur == end) {
         p->state = GRPC_CHTTP2_DATA_FH_4;
         return GRPC_CHTTP2_PARSE_OK;
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_4:
-      p->frame_size |= ((gpr_uint32) * cur);
+      p->frame_size |= ((gpr_uint32)*cur);
       p->state = GRPC_CHTTP2_DATA_FRAME;
       ++cur;
-      state->need_flush_reads = 1;
-      grpc_sopb_add_begin_message(&p->incoming_sopb, p->frame_size, 0);
+      if (p->is_frame_compressed) {
+        message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+      }
+      grpc_sopb_add_begin_message(&p->incoming_sopb, p->frame_size,
+                                  message_flags);
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FRAME:
       if (cur == end) {
+        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                                 stream_parsing);
         return GRPC_CHTTP2_PARSE_OK;
-      } else if ((gpr_uint32)(end - cur) == p->frame_size) {
-        state->need_flush_reads = 1;
+      }
+      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                               stream_parsing);
+      if ((gpr_uint32)(end - cur) == p->frame_size) {
         grpc_sopb_add_slice(&p->incoming_sopb,
                             gpr_slice_sub(slice, cur - beg, end - beg));
         p->state = GRPC_CHTTP2_DATA_FH_0;
         return GRPC_CHTTP2_PARSE_OK;
       } else if ((gpr_uint32)(end - cur) > p->frame_size) {
-        state->need_flush_reads = 1;
         grpc_sopb_add_slice(
             &p->incoming_sopb,
             gpr_slice_sub(slice, cur - beg, cur + p->frame_size - beg));
         cur += p->frame_size;
         goto fh_0; /* loop */
       } else {
-        state->need_flush_reads = 1;
         grpc_sopb_add_slice(&p->incoming_sopb,
                             gpr_slice_sub(slice, cur - beg, end - beg));
         p->frame_size -= (end - cur);
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
index 24e557a..23957b0 100644
--- a/src/core/transport/chttp2/frame_data.h
+++ b/src/core/transport/chttp2/frame_data.h
@@ -56,6 +56,7 @@
   gpr_uint8 frame_type;
   gpr_uint32 frame_size;
 
+  int is_frame_compressed;
   grpc_stream_op_buffer incoming_sopb;
 } grpc_chttp2_data_parser;
 
@@ -72,9 +73,10 @@
 /* handle a slice of a data frame - is_last indicates the last slice of a
    frame */
 grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
 /* create a slice with an empty data frame and is_last set */
 gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H */
diff --git a/src/core/transport/chttp2/frame_goaway.c b/src/core/transport/chttp2/frame_goaway.c
index 95b75d4..1ccbba8 100644
--- a/src/core/transport/chttp2/frame_goaway.c
+++ b/src/core/transport/chttp2/frame_goaway.c
@@ -32,6 +32,7 @@
  */
 
 #include "src/core/transport/chttp2/frame_goaway.h"
+#include "src/core/transport/chttp2/internal.h"
 
 #include <string.h>
 
@@ -62,8 +63,8 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last) {
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
@@ -75,7 +76,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI0;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->last_stream_id = ((gpr_uint32) * cur) << 24;
+      p->last_stream_id = ((gpr_uint32)*cur) << 24;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_LSI1:
@@ -83,7 +84,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI1;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->last_stream_id |= ((gpr_uint32) * cur) << 16;
+      p->last_stream_id |= ((gpr_uint32)*cur) << 16;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_LSI2:
@@ -91,7 +92,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI2;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->last_stream_id |= ((gpr_uint32) * cur) << 8;
+      p->last_stream_id |= ((gpr_uint32)*cur) << 8;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_LSI3:
@@ -99,7 +100,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI3;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->last_stream_id |= ((gpr_uint32) * cur);
+      p->last_stream_id |= ((gpr_uint32)*cur);
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR0:
@@ -107,7 +108,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR0;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->error_code = ((gpr_uint32) * cur) << 24;
+      p->error_code = ((gpr_uint32)*cur) << 24;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR1:
@@ -115,7 +116,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR1;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->error_code |= ((gpr_uint32) * cur) << 16;
+      p->error_code |= ((gpr_uint32)*cur) << 16;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR2:
@@ -123,7 +124,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR2;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->error_code |= ((gpr_uint32) * cur) << 8;
+      p->error_code |= ((gpr_uint32)*cur) << 8;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR3:
@@ -131,7 +132,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR3;
         return GRPC_CHTTP2_PARSE_OK;
       }
-      p->error_code |= ((gpr_uint32) * cur);
+      p->error_code |= ((gpr_uint32)*cur);
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_DEBUG:
@@ -139,10 +140,11 @@
       p->debug_pos += end - cur;
       p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
       if (is_last) {
-        state->goaway = 1;
-        state->goaway_last_stream_index = p->last_stream_id;
-        state->goaway_error = p->error_code;
-        state->goaway_text =
+        transport_parsing->goaway_received = 1;
+        transport_parsing->goaway_last_stream_index = p->last_stream_id;
+        gpr_slice_unref(transport_parsing->goaway_text);
+        transport_parsing->goaway_error = p->error_code;
+        transport_parsing->goaway_text =
             gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
         p->debug_data = NULL;
       }
diff --git a/src/core/transport/chttp2/frame_goaway.h b/src/core/transport/chttp2/frame_goaway.h
index 7638891..9c5edfc 100644
--- a/src/core/transport/chttp2/frame_goaway.h
+++ b/src/core/transport/chttp2/frame_goaway.h
@@ -65,10 +65,11 @@
 grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
     grpc_chttp2_goaway_parser *parser, gpr_uint32 length, gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
 void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code,
                                gpr_slice debug_data,
                                gpr_slice_buffer *slice_buffer);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H */
diff --git a/src/core/transport/chttp2/frame_ping.c b/src/core/transport/chttp2/frame_ping.c
index 26004b3..05451c7 100644
--- a/src/core/transport/chttp2/frame_ping.c
+++ b/src/core/transport/chttp2/frame_ping.c
@@ -32,9 +32,11 @@
  */
 
 #include "src/core/transport/chttp2/frame_ping.h"
+#include "src/core/transport/chttp2/internal.h"
 
 #include <string.h>
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 gpr_slice grpc_chttp2_ping_create(gpr_uint8 ack, gpr_uint8 *opaque_8bytes) {
@@ -67,12 +69,13 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last) {
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
   grpc_chttp2_ping_parser *p = parser;
+  grpc_chttp2_outstanding_ping *ping;
 
   while (p->byte != 8 && cur != end) {
     p->opaque_8bytes[p->byte] = *cur;
@@ -83,9 +86,18 @@
   if (p->byte == 8) {
     GPR_ASSERT(is_last);
     if (p->is_ack) {
-      state->process_ping_reply = 1;
+      for (ping = transport_parsing->pings.next;
+           ping != &transport_parsing->pings; ping = ping->next) {
+        if (0 == memcmp(p->opaque_8bytes, ping->id, 8)) {
+          grpc_iomgr_add_delayed_callback(ping->on_recv, 1);
+        }
+        ping->next->prev = ping->prev;
+        ping->prev->next = ping->next;
+        gpr_free(ping);
+      }
     } else {
-      state->send_ping_ack = 1;
+      gpr_slice_buffer_add(&transport_parsing->qbuf,
+                           grpc_chttp2_ping_create(1, p->opaque_8bytes));
     }
   }
 
diff --git a/src/core/transport/chttp2/frame_ping.h b/src/core/transport/chttp2/frame_ping.h
index 11d38b8..99197e8 100644
--- a/src/core/transport/chttp2/frame_ping.h
+++ b/src/core/transport/chttp2/frame_ping.h
@@ -48,6 +48,7 @@
 grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
     grpc_chttp2_ping_parser *parser, gpr_uint32 length, gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H */
diff --git a/src/core/transport/chttp2/frame_rst_stream.c b/src/core/transport/chttp2/frame_rst_stream.c
index 3016aac..a878d93 100644
--- a/src/core/transport/chttp2/frame_rst_stream.c
+++ b/src/core/transport/chttp2/frame_rst_stream.c
@@ -32,6 +32,7 @@
  */
 
 #include "src/core/transport/chttp2/frame_rst_stream.h"
+#include "src/core/transport/chttp2/internal.h"
 
 #include <grpc/support/log.h>
 
@@ -61,7 +62,8 @@
 grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser *parser, gpr_uint32 length, gpr_uint8 flags) {
   if (length != 4) {
-    gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length, flags);
+    gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length,
+            flags);
     return GRPC_CHTTP2_CONNECTION_ERROR;
   }
   parser->byte = 0;
@@ -69,8 +71,8 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last) {
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
@@ -84,12 +86,13 @@
 
   if (p->byte == 4) {
     GPR_ASSERT(is_last);
-    state->rst_stream = 1;
-    state->rst_stream_reason = 
-      (((gpr_uint32)p->reason_bytes[0]) << 24) |
-      (((gpr_uint32)p->reason_bytes[1]) << 16) |
-      (((gpr_uint32)p->reason_bytes[2]) << 8) |
-      (((gpr_uint32)p->reason_bytes[3]));
+    stream_parsing->received_close = 1;
+    stream_parsing->saw_rst_stream = 1;
+    stream_parsing->rst_stream_reason =
+        (((gpr_uint32)p->reason_bytes[0]) << 24) |
+        (((gpr_uint32)p->reason_bytes[1]) << 16) |
+        (((gpr_uint32)p->reason_bytes[2]) << 8) |
+        (((gpr_uint32)p->reason_bytes[3]));
   }
 
   return GRPC_CHTTP2_PARSE_OK;
diff --git a/src/core/transport/chttp2/frame_rst_stream.h b/src/core/transport/chttp2/frame_rst_stream.h
index 07a3c98..ed69e58 100644
--- a/src/core/transport/chttp2/frame_rst_stream.h
+++ b/src/core/transport/chttp2/frame_rst_stream.h
@@ -47,6 +47,7 @@
 grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser *parser, gpr_uint32 length, gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H */
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
index 2ffce73..d42bc00 100644
--- a/src/core/transport/chttp2/frame_settings.c
+++ b/src/core/transport/chttp2/frame_settings.c
@@ -32,6 +32,7 @@
  */
 
 #include "src/core/transport/chttp2/frame_settings.h"
+#include "src/core/transport/chttp2/internal.h"
 
 #include <string.h>
 
@@ -137,7 +138,8 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
-    void *p, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last) {
+    void *p, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   grpc_chttp2_settings_parser *parser = p;
   const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
   const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
@@ -152,9 +154,11 @@
         if (cur == end) {
           parser->state = GRPC_CHTTP2_SPS_ID0;
           if (is_last) {
+            transport_parsing->settings_updated = 1;
             memcpy(parser->target_settings, parser->incoming_settings,
                    GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
-            state->ack_settings = 1;
+            gpr_slice_buffer_add(&transport_parsing->qbuf,
+                                 grpc_chttp2_settings_ack_create());
           }
           return GRPC_CHTTP2_PARSE_OK;
         }
@@ -220,15 +224,16 @@
           }
           if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
               parser->incoming_settings[parser->id] != parser->value) {
-            state->initial_window_update =
+            transport_parsing->initial_window_update =
                 (gpr_int64)parser->value -
                 parser->incoming_settings[parser->id];
             gpr_log(GPR_DEBUG, "adding %d for initial_window change",
-                    (int)state->initial_window_update);
+                    (int)transport_parsing->initial_window_update);
           }
           parser->incoming_settings[parser->id] = parser->value;
           if (grpc_http_trace) {
-            gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id,
+            gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
+                    transport_parsing->is_client ? "CLI" : "SVR", parser->id,
                     parser->value);
           }
         } else {
diff --git a/src/core/transport/chttp2/frame_settings.h b/src/core/transport/chttp2/frame_settings.h
index 1876563..0ac68a9 100644
--- a/src/core/transport/chttp2/frame_settings.h
+++ b/src/core/transport/chttp2/frame_settings.h
@@ -94,6 +94,7 @@
     grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
     gpr_uint32 *settings);
 grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H */
diff --git a/src/core/transport/chttp2/frame_window_update.c b/src/core/transport/chttp2/frame_window_update.c
index a8db7d6..d624298 100644
--- a/src/core/transport/chttp2/frame_window_update.c
+++ b/src/core/transport/chttp2/frame_window_update.c
@@ -32,6 +32,7 @@
  */
 
 #include "src/core/transport/chttp2/frame_window_update.h"
+#include "src/core/transport/chttp2/internal.h"
 
 #include <grpc/support/log.h>
 
@@ -73,15 +74,15 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last) {
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
   grpc_chttp2_window_update_parser *p = parser;
 
   while (p->byte != 4 && cur != end) {
-    p->amount |= ((gpr_uint32) * cur) << (8 * (3 - p->byte));
+    p->amount |= ((gpr_uint32)*cur) << (8 * (3 - p->byte));
     cur++;
     p->byte++;
   }
@@ -92,7 +93,21 @@
       return GRPC_CHTTP2_CONNECTION_ERROR;
     }
     GPR_ASSERT(is_last);
-    state->window_update = p->amount;
+
+    if (transport_parsing->incoming_stream_id != 0) {
+      if (stream_parsing != NULL) {
+        GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("update", transport_parsing,
+                                         stream_parsing, outgoing_window_update,
+                                         p->amount);
+        stream_parsing->outgoing_window_update += p->amount;
+        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                                 stream_parsing);
+      }
+    } else {
+      GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("update", transport_parsing,
+                                          outgoing_window_update, p->amount);
+      transport_parsing->outgoing_window_update += p->amount;
+    }
   }
 
   return GRPC_CHTTP2_PARSE_OK;
diff --git a/src/core/transport/chttp2/frame_window_update.h b/src/core/transport/chttp2/frame_window_update.h
index 85475a8..deba801 100644
--- a/src/core/transport/chttp2/frame_window_update.h
+++ b/src/core/transport/chttp2/frame_window_update.h
@@ -50,6 +50,7 @@
     grpc_chttp2_window_update_parser *parser, gpr_uint32 length,
     gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
-    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H */
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
index a489543..f8bff42 100644
--- a/src/core/transport/chttp2/hpack_parser.c
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -32,6 +32,7 @@
  */
 
 #include "src/core/transport/chttp2/hpack_parser.h"
+#include "src/core/transport/chttp2/internal.h"
 
 #include <stddef.h>
 #include <string.h>
@@ -149,10 +150,12 @@
 /* jump table of parse state functions -- order must match first_byte_type
    above */
 static const grpc_chttp2_hpack_parser_state first_byte_action[] = {
-    parse_indexed_field,   parse_indexed_field_x, parse_lithdr_incidx,
-    parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx,
-    parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx,
-    parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size,
+    parse_indexed_field,   parse_indexed_field_x,
+    parse_lithdr_incidx,   parse_lithdr_incidx_x,
+    parse_lithdr_incidx_v, parse_lithdr_notidx,
+    parse_lithdr_notidx_x, parse_lithdr_notidx_v,
+    parse_lithdr_nvridx,   parse_lithdr_nvridx_x,
+    parse_lithdr_nvridx_v, parse_max_tbl_size,
     parse_max_tbl_size_x,  parse_error};
 
 /* indexes the first byte to a parse state function - generated by
@@ -221,7 +224,8 @@
     INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
     INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
     INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD,
-    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD_X, };
+    INDEXED_FIELD,   INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD_X,
+};
 
 /* state table for huffman decoding: given a state, gives an index/16 into
    next_sub_tbl. Taking that index and adding the value of the nibble being
@@ -241,7 +245,8 @@
     38, 1,  1,  1,  1,  1,  1, 1,  15, 2, 2,  2,  2,  26, 3,  3,  39, 1,  1,  1,
     1,  1,  1,  1,  1,  1,  1, 1,  2,  2, 2,  2,  2,  2,  7,  3,  3,  3,  40, 2,
     41, 1,  1,  1,  42, 43, 1, 1,  44, 1, 1,  1,  1,  15, 2,  2,  2,  2,  2,  2,
-    3,  3,  3,  45, 46, 1,  1, 2,  2,  2, 35, 3,  3,  18, 47, 2, };
+    3,  3,  3,  45, 46, 1,  1, 2,  2,  2, 35, 3,  3,  18, 47, 2,
+};
 /* next state, based upon current state and the current nibble: see above.
    generated by gen_hpack_tables.c */
 static const gpr_int16 next_sub_tbl[48 * 16] = {
@@ -296,7 +301,8 @@
     4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   245, 246, 247, 248, 249, 250, 251, 252,
     253, 254, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   255, };
+    0,   0,   255,
+};
 /* emission table: indexed like next_tbl, ultimately gives the byte to be
    emitted, or -1 for no byte, or 256 for end of stream
 
@@ -319,7 +325,8 @@
     204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
     219, 220, 221, 0,   222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
     233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
-    248, };
+    248,
+};
 /* generated by gen_hpack_tables.c */
 static const gpr_int16 emit_sub_tbl[249 * 16] = {
     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
@@ -587,7 +594,8 @@
     251, 251, 252, 252, 253, 253, 254, 254, 2,   3,   4,   5,   6,   7,   8,
     11,  12,  14,  15,  16,  17,  18,  19,  20,  21,  23,  24,  25,  26,  27,
     28,  29,  30,  31,  127, 220, 249, -1,  10,  10,  10,  10,  13,  13,  13,
-    13,  22,  22,  22,  22,  256, 256, 256, 256, };
+    13,  22,  22,  22,  22,  256, 256, 256, 256,
+};
 
 static const gpr_uint8 inverse_base64[256] = {
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@@ -607,13 +615,14 @@
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-    255, };
+    255,
+};
 
 /* emission helpers */
 static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
                    int add_to_table) {
   if (add_to_table) {
-    grpc_mdelem_ref(md);
+    GRPC_MDELEM_REF(md);
     grpc_chttp2_hptbl_add(&p->table, md);
   }
   p->on_header(p->on_header_user_data, md);
@@ -702,7 +711,7 @@
 static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  grpc_mdelem_ref(md);
+  GRPC_MDELEM_REF(md);
   on_hdr(p, md, 0);
   return parse_begin(p, cur, end);
 }
@@ -731,7 +740,7 @@
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
-                                              grpc_mdstr_ref(md->key),
+                                              GRPC_MDSTR_REF(md->key),
                                               take_string(p, &p->value)),
          1);
   return parse_begin(p, cur, end);
@@ -784,7 +793,7 @@
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
-                                              grpc_mdstr_ref(md->key),
+                                              GRPC_MDSTR_REF(md->key),
                                               take_string(p, &p->value)),
          0);
   return parse_begin(p, cur, end);
@@ -837,7 +846,7 @@
                                 const gpr_uint8 *cur, const gpr_uint8 *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx,
-                                              grpc_mdstr_ref(md->key),
+                                              GRPC_MDSTR_REF(md->key),
                                               take_string(p, &p->value)),
          0);
   return parse_begin(p, cur, end);
@@ -945,7 +954,7 @@
     return 1;
   }
 
-  *p->parsing.value += (((gpr_uint32) * cur) & 0x7f) << 7;
+  *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 7;
 
   if ((*cur) & 0x80) {
     return parse_value2(p, cur + 1, end);
@@ -963,7 +972,7 @@
     return 1;
   }
 
-  *p->parsing.value += (((gpr_uint32) * cur) & 0x7f) << 14;
+  *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 14;
 
   if ((*cur) & 0x80) {
     return parse_value3(p, cur + 1, end);
@@ -981,7 +990,7 @@
     return 1;
   }
 
-  *p->parsing.value += (((gpr_uint32) * cur) & 0x7f) << 21;
+  *p->parsing.value += (((gpr_uint32)*cur) & 0x7f) << 21;
 
   if ((*cur) & 0x80) {
     return parse_value4(p, cur + 1, end);
@@ -1320,17 +1329,14 @@
 /* PUBLIC INTERFACE */
 
 static void on_header_not_set(void *user_data, grpc_mdelem *md) {
-  char *keyhex =
-      gpr_hexdump(grpc_mdstr_as_c_string(md->key),
-                  GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT);
+  char *keyhex = gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
   char *valuehex =
-      gpr_hexdump(grpc_mdstr_as_c_string(md->value),
-                  GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT);
+      gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
   gpr_log(GPR_ERROR, "on_header callback not set; key=%s value=%s", keyhex,
           valuehex);
   gpr_free(keyhex);
   gpr_free(valuehex);
-  grpc_mdelem_unref(md);
+  GRPC_MDELEM_UNREF(md);
   abort();
 }
 
@@ -1369,8 +1375,8 @@
 }
 
 grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
-    void *hpack_parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last) {
+    void *hpack_parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
   grpc_chttp2_hpack_parser *parser = hpack_parser;
   if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
                                       GPR_SLICE_END_PTR(slice))) {
@@ -1382,9 +1388,16 @@
               "end of header frame not aligned with a hpack record boundary");
       return GRPC_CHTTP2_CONNECTION_ERROR;
     }
-    state->metadata_boundary = parser->is_boundary;
-    state->end_of_stream = parser->is_eof;
-    state->need_flush_reads = parser->is_eof;
+    if (parser->is_boundary) {
+      grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
+          &stream_parsing->incoming_metadata,
+          &stream_parsing->data_parser.incoming_sopb);
+      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                               stream_parsing);
+    }
+    if (parser->is_eof) {
+      stream_parsing->received_close = 1;
+    }
     parser->on_header = on_header_not_set;
     parser->on_header_user_data = NULL;
     parser->is_boundary = 0xde;
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
index bfc06b3..c1768d9 100644
--- a/src/core/transport/chttp2/hpack_parser.h
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -107,7 +107,7 @@
 /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
    the transport */
 grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
-    void *hpack_parser, grpc_chttp2_parse_state *state, gpr_slice slice,
-    int is_last);
+    void *hpack_parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H */
diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c
index 2c01592..4fc1543 100644
--- a/src/core/transport/chttp2/hpack_table.c
+++ b/src/core/transport/chttp2/hpack_table.c
@@ -43,68 +43,69 @@
   const char *key;
   const char *value;
 } static_table[] = {
-      /* 0: */ {NULL, NULL},
-      /* 1: */ {":authority", ""},
-      /* 2: */ {":method", "GET"},
-      /* 3: */ {":method", "POST"},
-      /* 4: */ {":path", "/"},
-      /* 5: */ {":path", "/index.html"},
-      /* 6: */ {":scheme", "http"},
-      /* 7: */ {":scheme", "https"},
-      /* 8: */ {":status", "200"},
-      /* 9: */ {":status", "204"},
-      /* 10: */ {":status", "206"},
-      /* 11: */ {":status", "304"},
-      /* 12: */ {":status", "400"},
-      /* 13: */ {":status", "404"},
-      /* 14: */ {":status", "500"},
-      /* 15: */ {"accept-charset", ""},
-      /* 16: */ {"accept-encoding", "gzip, deflate"},
-      /* 17: */ {"accept-language", ""},
-      /* 18: */ {"accept-ranges", ""},
-      /* 19: */ {"accept", ""},
-      /* 20: */ {"access-control-allow-origin", ""},
-      /* 21: */ {"age", ""},
-      /* 22: */ {"allow", ""},
-      /* 23: */ {"authorization", ""},
-      /* 24: */ {"cache-control", ""},
-      /* 25: */ {"content-disposition", ""},
-      /* 26: */ {"content-encoding", ""},
-      /* 27: */ {"content-language", ""},
-      /* 28: */ {"content-length", ""},
-      /* 29: */ {"content-location", ""},
-      /* 30: */ {"content-range", ""},
-      /* 31: */ {"content-type", ""},
-      /* 32: */ {"cookie", ""},
-      /* 33: */ {"date", ""},
-      /* 34: */ {"etag", ""},
-      /* 35: */ {"expect", ""},
-      /* 36: */ {"expires", ""},
-      /* 37: */ {"from", ""},
-      /* 38: */ {"host", ""},
-      /* 39: */ {"if-match", ""},
-      /* 40: */ {"if-modified-since", ""},
-      /* 41: */ {"if-none-match", ""},
-      /* 42: */ {"if-range", ""},
-      /* 43: */ {"if-unmodified-since", ""},
-      /* 44: */ {"last-modified", ""},
-      /* 45: */ {"link", ""},
-      /* 46: */ {"location", ""},
-      /* 47: */ {"max-forwards", ""},
-      /* 48: */ {"proxy-authenticate", ""},
-      /* 49: */ {"proxy-authorization", ""},
-      /* 50: */ {"range", ""},
-      /* 51: */ {"referer", ""},
-      /* 52: */ {"refresh", ""},
-      /* 53: */ {"retry-after", ""},
-      /* 54: */ {"server", ""},
-      /* 55: */ {"set-cookie", ""},
-      /* 56: */ {"strict-transport-security", ""},
-      /* 57: */ {"transfer-encoding", ""},
-      /* 58: */ {"user-agent", ""},
-      /* 59: */ {"vary", ""},
-      /* 60: */ {"via", ""},
-      /* 61: */ {"www-authenticate", ""}, };
+    /* 0: */ {NULL, NULL},
+    /* 1: */ {":authority", ""},
+    /* 2: */ {":method", "GET"},
+    /* 3: */ {":method", "POST"},
+    /* 4: */ {":path", "/"},
+    /* 5: */ {":path", "/index.html"},
+    /* 6: */ {":scheme", "http"},
+    /* 7: */ {":scheme", "https"},
+    /* 8: */ {":status", "200"},
+    /* 9: */ {":status", "204"},
+    /* 10: */ {":status", "206"},
+    /* 11: */ {":status", "304"},
+    /* 12: */ {":status", "400"},
+    /* 13: */ {":status", "404"},
+    /* 14: */ {":status", "500"},
+    /* 15: */ {"accept-charset", ""},
+    /* 16: */ {"accept-encoding", "gzip, deflate"},
+    /* 17: */ {"accept-language", ""},
+    /* 18: */ {"accept-ranges", ""},
+    /* 19: */ {"accept", ""},
+    /* 20: */ {"access-control-allow-origin", ""},
+    /* 21: */ {"age", ""},
+    /* 22: */ {"allow", ""},
+    /* 23: */ {"authorization", ""},
+    /* 24: */ {"cache-control", ""},
+    /* 25: */ {"content-disposition", ""},
+    /* 26: */ {"content-encoding", ""},
+    /* 27: */ {"content-language", ""},
+    /* 28: */ {"content-length", ""},
+    /* 29: */ {"content-location", ""},
+    /* 30: */ {"content-range", ""},
+    /* 31: */ {"content-type", ""},
+    /* 32: */ {"cookie", ""},
+    /* 33: */ {"date", ""},
+    /* 34: */ {"etag", ""},
+    /* 35: */ {"expect", ""},
+    /* 36: */ {"expires", ""},
+    /* 37: */ {"from", ""},
+    /* 38: */ {"host", ""},
+    /* 39: */ {"if-match", ""},
+    /* 40: */ {"if-modified-since", ""},
+    /* 41: */ {"if-none-match", ""},
+    /* 42: */ {"if-range", ""},
+    /* 43: */ {"if-unmodified-since", ""},
+    /* 44: */ {"last-modified", ""},
+    /* 45: */ {"link", ""},
+    /* 46: */ {"location", ""},
+    /* 47: */ {"max-forwards", ""},
+    /* 48: */ {"proxy-authenticate", ""},
+    /* 49: */ {"proxy-authorization", ""},
+    /* 50: */ {"range", ""},
+    /* 51: */ {"referer", ""},
+    /* 52: */ {"refresh", ""},
+    /* 53: */ {"retry-after", ""},
+    /* 54: */ {"server", ""},
+    /* 55: */ {"set-cookie", ""},
+    /* 56: */ {"strict-transport-security", ""},
+    /* 57: */ {"transfer-encoding", ""},
+    /* 58: */ {"user-agent", ""},
+    /* 59: */ {"vary", ""},
+    /* 60: */ {"via", ""},
+    /* 61: */ {"www-authenticate", ""},
+};
 
 void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
   size_t i;
@@ -121,10 +122,10 @@
 void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
   size_t i;
   for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
-    grpc_mdelem_unref(tbl->static_ents[i]);
+    GRPC_MDELEM_UNREF(tbl->static_ents[i]);
   }
   for (i = 0; i < tbl->num_ents; i++) {
-    grpc_mdelem_unref(
+    GRPC_MDELEM_UNREF(
         tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
   }
 }
@@ -154,7 +155,7 @@
                    GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
   tbl->first_ent = (tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT;
   tbl->num_ents--;
-  grpc_mdelem_unref(first_ent);
+  GRPC_MDELEM_UNREF(first_ent);
 }
 
 void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h
index d3bf41b..4f882e2 100644
--- a/src/core/transport/chttp2/hpack_table.h
+++ b/src/core/transport/chttp2/hpack_table.h
@@ -94,4 +94,4 @@
 grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
     const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H */
diff --git a/src/core/transport/chttp2/http2_errors.h b/src/core/transport/chttp2/http2_errors.h
index 4ab2ec0..a4f309e 100644
--- a/src/core/transport/chttp2/http2_errors.h
+++ b/src/core/transport/chttp2/http2_errors.h
@@ -53,4 +53,4 @@
   GRPC_CHTTP2__ERROR_DO_NOT_USE = -1
 } grpc_chttp2_error_code;
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H */
diff --git a/src/core/transport/chttp2/huffsyms.c b/src/core/transport/chttp2/huffsyms.c
index 0a926e7..6f5cf6a 100644
--- a/src/core/transport/chttp2/huffsyms.c
+++ b/src/core/transport/chttp2/huffsyms.c
@@ -37,260 +37,69 @@
    command:
    :%s/.*   \([0-9a-f]\+\)  \[ *\([0-9]\+\)\]/{0x\1, \2},/g */
 const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS] = {
-    {0x1ff8, 13},
-    {0x7fffd8, 23},
-    {0xfffffe2, 28},
-    {0xfffffe3, 28},
-    {0xfffffe4, 28},
-    {0xfffffe5, 28},
-    {0xfffffe6, 28},
-    {0xfffffe7, 28},
-    {0xfffffe8, 28},
-    {0xffffea, 24},
-    {0x3ffffffc, 30},
-    {0xfffffe9, 28},
-    {0xfffffea, 28},
-    {0x3ffffffd, 30},
-    {0xfffffeb, 28},
-    {0xfffffec, 28},
-    {0xfffffed, 28},
-    {0xfffffee, 28},
-    {0xfffffef, 28},
-    {0xffffff0, 28},
-    {0xffffff1, 28},
-    {0xffffff2, 28},
-    {0x3ffffffe, 30},
-    {0xffffff3, 28},
-    {0xffffff4, 28},
-    {0xffffff5, 28},
-    {0xffffff6, 28},
-    {0xffffff7, 28},
-    {0xffffff8, 28},
-    {0xffffff9, 28},
-    {0xffffffa, 28},
-    {0xffffffb, 28},
-    {0x14, 6},
-    {0x3f8, 10},
-    {0x3f9, 10},
-    {0xffa, 12},
-    {0x1ff9, 13},
-    {0x15, 6},
-    {0xf8, 8},
-    {0x7fa, 11},
-    {0x3fa, 10},
-    {0x3fb, 10},
-    {0xf9, 8},
-    {0x7fb, 11},
-    {0xfa, 8},
-    {0x16, 6},
-    {0x17, 6},
-    {0x18, 6},
-    {0x0, 5},
-    {0x1, 5},
-    {0x2, 5},
-    {0x19, 6},
-    {0x1a, 6},
-    {0x1b, 6},
-    {0x1c, 6},
-    {0x1d, 6},
-    {0x1e, 6},
-    {0x1f, 6},
-    {0x5c, 7},
-    {0xfb, 8},
-    {0x7ffc, 15},
-    {0x20, 6},
-    {0xffb, 12},
-    {0x3fc, 10},
-    {0x1ffa, 13},
-    {0x21, 6},
-    {0x5d, 7},
-    {0x5e, 7},
-    {0x5f, 7},
-    {0x60, 7},
-    {0x61, 7},
-    {0x62, 7},
-    {0x63, 7},
-    {0x64, 7},
-    {0x65, 7},
-    {0x66, 7},
-    {0x67, 7},
-    {0x68, 7},
-    {0x69, 7},
-    {0x6a, 7},
-    {0x6b, 7},
-    {0x6c, 7},
-    {0x6d, 7},
-    {0x6e, 7},
-    {0x6f, 7},
-    {0x70, 7},
-    {0x71, 7},
-    {0x72, 7},
-    {0xfc, 8},
-    {0x73, 7},
-    {0xfd, 8},
-    {0x1ffb, 13},
-    {0x7fff0, 19},
-    {0x1ffc, 13},
-    {0x3ffc, 14},
-    {0x22, 6},
-    {0x7ffd, 15},
-    {0x3, 5},
-    {0x23, 6},
-    {0x4, 5},
-    {0x24, 6},
-    {0x5, 5},
-    {0x25, 6},
-    {0x26, 6},
-    {0x27, 6},
-    {0x6, 5},
-    {0x74, 7},
-    {0x75, 7},
-    {0x28, 6},
-    {0x29, 6},
-    {0x2a, 6},
-    {0x7, 5},
-    {0x2b, 6},
-    {0x76, 7},
-    {0x2c, 6},
-    {0x8, 5},
-    {0x9, 5},
-    {0x2d, 6},
-    {0x77, 7},
-    {0x78, 7},
-    {0x79, 7},
-    {0x7a, 7},
-    {0x7b, 7},
-    {0x7ffe, 15},
-    {0x7fc, 11},
-    {0x3ffd, 14},
-    {0x1ffd, 13},
-    {0xffffffc, 28},
-    {0xfffe6, 20},
-    {0x3fffd2, 22},
-    {0xfffe7, 20},
-    {0xfffe8, 20},
-    {0x3fffd3, 22},
-    {0x3fffd4, 22},
-    {0x3fffd5, 22},
-    {0x7fffd9, 23},
-    {0x3fffd6, 22},
-    {0x7fffda, 23},
-    {0x7fffdb, 23},
-    {0x7fffdc, 23},
-    {0x7fffdd, 23},
-    {0x7fffde, 23},
-    {0xffffeb, 24},
-    {0x7fffdf, 23},
-    {0xffffec, 24},
-    {0xffffed, 24},
-    {0x3fffd7, 22},
-    {0x7fffe0, 23},
-    {0xffffee, 24},
-    {0x7fffe1, 23},
-    {0x7fffe2, 23},
-    {0x7fffe3, 23},
-    {0x7fffe4, 23},
-    {0x1fffdc, 21},
-    {0x3fffd8, 22},
-    {0x7fffe5, 23},
-    {0x3fffd9, 22},
-    {0x7fffe6, 23},
-    {0x7fffe7, 23},
-    {0xffffef, 24},
-    {0x3fffda, 22},
-    {0x1fffdd, 21},
-    {0xfffe9, 20},
-    {0x3fffdb, 22},
-    {0x3fffdc, 22},
-    {0x7fffe8, 23},
-    {0x7fffe9, 23},
-    {0x1fffde, 21},
-    {0x7fffea, 23},
-    {0x3fffdd, 22},
-    {0x3fffde, 22},
-    {0xfffff0, 24},
-    {0x1fffdf, 21},
-    {0x3fffdf, 22},
-    {0x7fffeb, 23},
-    {0x7fffec, 23},
-    {0x1fffe0, 21},
-    {0x1fffe1, 21},
-    {0x3fffe0, 22},
-    {0x1fffe2, 21},
-    {0x7fffed, 23},
-    {0x3fffe1, 22},
-    {0x7fffee, 23},
-    {0x7fffef, 23},
-    {0xfffea, 20},
-    {0x3fffe2, 22},
-    {0x3fffe3, 22},
-    {0x3fffe4, 22},
-    {0x7ffff0, 23},
-    {0x3fffe5, 22},
-    {0x3fffe6, 22},
-    {0x7ffff1, 23},
-    {0x3ffffe0, 26},
-    {0x3ffffe1, 26},
-    {0xfffeb, 20},
-    {0x7fff1, 19},
-    {0x3fffe7, 22},
-    {0x7ffff2, 23},
-    {0x3fffe8, 22},
-    {0x1ffffec, 25},
-    {0x3ffffe2, 26},
-    {0x3ffffe3, 26},
-    {0x3ffffe4, 26},
-    {0x7ffffde, 27},
-    {0x7ffffdf, 27},
-    {0x3ffffe5, 26},
-    {0xfffff1, 24},
-    {0x1ffffed, 25},
-    {0x7fff2, 19},
-    {0x1fffe3, 21},
-    {0x3ffffe6, 26},
-    {0x7ffffe0, 27},
-    {0x7ffffe1, 27},
-    {0x3ffffe7, 26},
-    {0x7ffffe2, 27},
-    {0xfffff2, 24},
-    {0x1fffe4, 21},
-    {0x1fffe5, 21},
-    {0x3ffffe8, 26},
-    {0x3ffffe9, 26},
-    {0xffffffd, 28},
-    {0x7ffffe3, 27},
-    {0x7ffffe4, 27},
-    {0x7ffffe5, 27},
-    {0xfffec, 20},
-    {0xfffff3, 24},
-    {0xfffed, 20},
-    {0x1fffe6, 21},
-    {0x3fffe9, 22},
-    {0x1fffe7, 21},
-    {0x1fffe8, 21},
-    {0x7ffff3, 23},
-    {0x3fffea, 22},
-    {0x3fffeb, 22},
-    {0x1ffffee, 25},
-    {0x1ffffef, 25},
-    {0xfffff4, 24},
-    {0xfffff5, 24},
-    {0x3ffffea, 26},
-    {0x7ffff4, 23},
-    {0x3ffffeb, 26},
-    {0x7ffffe6, 27},
-    {0x3ffffec, 26},
-    {0x3ffffed, 26},
-    {0x7ffffe7, 27},
-    {0x7ffffe8, 27},
-    {0x7ffffe9, 27},
-    {0x7ffffea, 27},
-    {0x7ffffeb, 27},
-    {0xffffffe, 28},
-    {0x7ffffec, 27},
-    {0x7ffffed, 27},
-    {0x7ffffee, 27},
-    {0x7ffffef, 27},
-    {0x7fffff0, 27},
-    {0x3ffffee, 26},
-    {0x3fffffff, 30}, };
+    {0x1ff8, 13},     {0x7fffd8, 23},   {0xfffffe2, 28},  {0xfffffe3, 28},
+    {0xfffffe4, 28},  {0xfffffe5, 28},  {0xfffffe6, 28},  {0xfffffe7, 28},
+    {0xfffffe8, 28},  {0xffffea, 24},   {0x3ffffffc, 30}, {0xfffffe9, 28},
+    {0xfffffea, 28},  {0x3ffffffd, 30}, {0xfffffeb, 28},  {0xfffffec, 28},
+    {0xfffffed, 28},  {0xfffffee, 28},  {0xfffffef, 28},  {0xffffff0, 28},
+    {0xffffff1, 28},  {0xffffff2, 28},  {0x3ffffffe, 30}, {0xffffff3, 28},
+    {0xffffff4, 28},  {0xffffff5, 28},  {0xffffff6, 28},  {0xffffff7, 28},
+    {0xffffff8, 28},  {0xffffff9, 28},  {0xffffffa, 28},  {0xffffffb, 28},
+    {0x14, 6},        {0x3f8, 10},      {0x3f9, 10},      {0xffa, 12},
+    {0x1ff9, 13},     {0x15, 6},        {0xf8, 8},        {0x7fa, 11},
+    {0x3fa, 10},      {0x3fb, 10},      {0xf9, 8},        {0x7fb, 11},
+    {0xfa, 8},        {0x16, 6},        {0x17, 6},        {0x18, 6},
+    {0x0, 5},         {0x1, 5},         {0x2, 5},         {0x19, 6},
+    {0x1a, 6},        {0x1b, 6},        {0x1c, 6},        {0x1d, 6},
+    {0x1e, 6},        {0x1f, 6},        {0x5c, 7},        {0xfb, 8},
+    {0x7ffc, 15},     {0x20, 6},        {0xffb, 12},      {0x3fc, 10},
+    {0x1ffa, 13},     {0x21, 6},        {0x5d, 7},        {0x5e, 7},
+    {0x5f, 7},        {0x60, 7},        {0x61, 7},        {0x62, 7},
+    {0x63, 7},        {0x64, 7},        {0x65, 7},        {0x66, 7},
+    {0x67, 7},        {0x68, 7},        {0x69, 7},        {0x6a, 7},
+    {0x6b, 7},        {0x6c, 7},        {0x6d, 7},        {0x6e, 7},
+    {0x6f, 7},        {0x70, 7},        {0x71, 7},        {0x72, 7},
+    {0xfc, 8},        {0x73, 7},        {0xfd, 8},        {0x1ffb, 13},
+    {0x7fff0, 19},    {0x1ffc, 13},     {0x3ffc, 14},     {0x22, 6},
+    {0x7ffd, 15},     {0x3, 5},         {0x23, 6},        {0x4, 5},
+    {0x24, 6},        {0x5, 5},         {0x25, 6},        {0x26, 6},
+    {0x27, 6},        {0x6, 5},         {0x74, 7},        {0x75, 7},
+    {0x28, 6},        {0x29, 6},        {0x2a, 6},        {0x7, 5},
+    {0x2b, 6},        {0x76, 7},        {0x2c, 6},        {0x8, 5},
+    {0x9, 5},         {0x2d, 6},        {0x77, 7},        {0x78, 7},
+    {0x79, 7},        {0x7a, 7},        {0x7b, 7},        {0x7ffe, 15},
+    {0x7fc, 11},      {0x3ffd, 14},     {0x1ffd, 13},     {0xffffffc, 28},
+    {0xfffe6, 20},    {0x3fffd2, 22},   {0xfffe7, 20},    {0xfffe8, 20},
+    {0x3fffd3, 22},   {0x3fffd4, 22},   {0x3fffd5, 22},   {0x7fffd9, 23},
+    {0x3fffd6, 22},   {0x7fffda, 23},   {0x7fffdb, 23},   {0x7fffdc, 23},
+    {0x7fffdd, 23},   {0x7fffde, 23},   {0xffffeb, 24},   {0x7fffdf, 23},
+    {0xffffec, 24},   {0xffffed, 24},   {0x3fffd7, 22},   {0x7fffe0, 23},
+    {0xffffee, 24},   {0x7fffe1, 23},   {0x7fffe2, 23},   {0x7fffe3, 23},
+    {0x7fffe4, 23},   {0x1fffdc, 21},   {0x3fffd8, 22},   {0x7fffe5, 23},
+    {0x3fffd9, 22},   {0x7fffe6, 23},   {0x7fffe7, 23},   {0xffffef, 24},
+    {0x3fffda, 22},   {0x1fffdd, 21},   {0xfffe9, 20},    {0x3fffdb, 22},
+    {0x3fffdc, 22},   {0x7fffe8, 23},   {0x7fffe9, 23},   {0x1fffde, 21},
+    {0x7fffea, 23},   {0x3fffdd, 22},   {0x3fffde, 22},   {0xfffff0, 24},
+    {0x1fffdf, 21},   {0x3fffdf, 22},   {0x7fffeb, 23},   {0x7fffec, 23},
+    {0x1fffe0, 21},   {0x1fffe1, 21},   {0x3fffe0, 22},   {0x1fffe2, 21},
+    {0x7fffed, 23},   {0x3fffe1, 22},   {0x7fffee, 23},   {0x7fffef, 23},
+    {0xfffea, 20},    {0x3fffe2, 22},   {0x3fffe3, 22},   {0x3fffe4, 22},
+    {0x7ffff0, 23},   {0x3fffe5, 22},   {0x3fffe6, 22},   {0x7ffff1, 23},
+    {0x3ffffe0, 26},  {0x3ffffe1, 26},  {0xfffeb, 20},    {0x7fff1, 19},
+    {0x3fffe7, 22},   {0x7ffff2, 23},   {0x3fffe8, 22},   {0x1ffffec, 25},
+    {0x3ffffe2, 26},  {0x3ffffe3, 26},  {0x3ffffe4, 26},  {0x7ffffde, 27},
+    {0x7ffffdf, 27},  {0x3ffffe5, 26},  {0xfffff1, 24},   {0x1ffffed, 25},
+    {0x7fff2, 19},    {0x1fffe3, 21},   {0x3ffffe6, 26},  {0x7ffffe0, 27},
+    {0x7ffffe1, 27},  {0x3ffffe7, 26},  {0x7ffffe2, 27},  {0xfffff2, 24},
+    {0x1fffe4, 21},   {0x1fffe5, 21},   {0x3ffffe8, 26},  {0x3ffffe9, 26},
+    {0xffffffd, 28},  {0x7ffffe3, 27},  {0x7ffffe4, 27},  {0x7ffffe5, 27},
+    {0xfffec, 20},    {0xfffff3, 24},   {0xfffed, 20},    {0x1fffe6, 21},
+    {0x3fffe9, 22},   {0x1fffe7, 21},   {0x1fffe8, 21},   {0x7ffff3, 23},
+    {0x3fffea, 22},   {0x3fffeb, 22},   {0x1ffffee, 25},  {0x1ffffef, 25},
+    {0xfffff4, 24},   {0xfffff5, 24},   {0x3ffffea, 26},  {0x7ffff4, 23},
+    {0x3ffffeb, 26},  {0x7ffffe6, 27},  {0x3ffffec, 26},  {0x3ffffed, 26},
+    {0x7ffffe7, 27},  {0x7ffffe8, 27},  {0x7ffffe9, 27},  {0x7ffffea, 27},
+    {0x7ffffeb, 27},  {0xffffffe, 28},  {0x7ffffec, 27},  {0x7ffffed, 27},
+    {0x7ffffee, 27},  {0x7ffffef, 27},  {0x7fffff0, 27},  {0x3ffffee, 26},
+    {0x3fffffff, 30},
+};
diff --git a/src/core/transport/chttp2/huffsyms.h b/src/core/transport/chttp2/huffsyms.h
index f9c1447..a3cdba8 100644
--- a/src/core/transport/chttp2/huffsyms.h
+++ b/src/core/transport/chttp2/huffsyms.h
@@ -45,4 +45,4 @@
 
 extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS];
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H */
diff --git a/src/core/transport/chttp2/incoming_metadata.c b/src/core/transport/chttp2/incoming_metadata.c
new file mode 100644
index 0000000..974b864
--- /dev/null
+++ b/src/core/transport/chttp2/incoming_metadata.c
@@ -0,0 +1,182 @@
+/*
+ *
+ * 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/transport/chttp2/incoming_metadata.h"
+
+#include <string.h>
+
+#include "src/core/transport/chttp2/internal.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+void grpc_chttp2_incoming_metadata_buffer_init(
+    grpc_chttp2_incoming_metadata_buffer *buffer) {
+  buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+}
+
+void grpc_chttp2_incoming_metadata_buffer_destroy(
+    grpc_chttp2_incoming_metadata_buffer *buffer) {
+  size_t i;
+  for (i = 0; i < buffer->count; i++) {
+    GRPC_MDELEM_UNREF(buffer->elems[i].md);
+  }
+  gpr_free(buffer->elems);
+}
+
+void grpc_chttp2_incoming_metadata_buffer_add(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) {
+  if (buffer->capacity == buffer->count) {
+    buffer->capacity = GPR_MAX(8, 2 * buffer->capacity);
+    buffer->elems =
+        gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity);
+  }
+  buffer->elems[buffer->count++].md = elem;
+}
+
+void grpc_chttp2_incoming_metadata_buffer_set_deadline(
+    grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) {
+  buffer->deadline = deadline;
+}
+
+void grpc_chttp2_incoming_metadata_live_op_buffer_end(
+    grpc_chttp2_incoming_metadata_live_op_buffer *buffer) {
+  gpr_free(buffer->elems);
+  buffer->elems = NULL;
+}
+
+void grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb) {
+  grpc_metadata_batch b;
+
+  b.list.head = NULL;
+  /* Store away the last element of the list, so that in patch_metadata_ops
+     we can reconstitute the list.
+     We can't do list building here as later incoming metadata may reallocate
+     the underlying array. */
+  b.list.tail = (void *)(gpr_intptr)buffer->count;
+  b.garbage.head = b.garbage.tail = NULL;
+  b.deadline = buffer->deadline;
+  buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+
+  grpc_sopb_add_metadata(sopb, b);
+}
+
+void grpc_chttp2_incoming_metadata_buffer_swap(
+    grpc_chttp2_incoming_metadata_buffer *a,
+    grpc_chttp2_incoming_metadata_buffer *b) {
+  GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, *a, *b);
+}
+
+void grpc_incoming_metadata_buffer_move_to_referencing_sopb(
+    grpc_chttp2_incoming_metadata_buffer *src,
+    grpc_chttp2_incoming_metadata_buffer *dst, grpc_stream_op_buffer *sopb) {
+  size_t delta;
+  size_t i;
+  dst->deadline = gpr_time_min(src->deadline, dst->deadline);
+
+  if (src->count == 0) {
+    return;
+  }
+  if (dst->count == 0) {
+    grpc_chttp2_incoming_metadata_buffer_swap(src, dst);
+    return;
+  }
+  delta = dst->count;
+  if (dst->capacity < src->count + dst->count) {
+    dst->capacity = GPR_MAX(dst->capacity * 2, src->count + dst->count);
+    dst->elems = gpr_realloc(dst->elems, dst->capacity * sizeof(*dst->elems));
+  }
+  memcpy(dst->elems + dst->count, src->elems, src->count * sizeof(*src->elems));
+  dst->count += src->count;
+  for (i = 0; i < sopb->nops; i++) {
+    if (sopb->ops[i].type != GRPC_OP_METADATA) continue;
+    sopb->ops[i].data.metadata.list.tail =
+        (void *)(delta + (gpr_intptr)sopb->ops[i].data.metadata.list.tail);
+  }
+  src->count = 0;
+}
+
+void grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb,
+    grpc_chttp2_incoming_metadata_live_op_buffer *live_op_buffer) {
+  grpc_stream_op *ops = sopb->ops;
+  size_t nops = sopb->nops;
+  size_t i;
+  size_t j;
+  size_t mdidx = 0;
+  size_t last_mdidx;
+  int found_metadata = 0;
+
+  /* rework the array of metadata into a linked list, making use
+     of the breadcrumbs we left in metadata batches during
+     add_metadata_batch */
+  for (i = 0; i < nops; i++) {
+    grpc_stream_op *op = &ops[i];
+    if (op->type != GRPC_OP_METADATA) continue;
+    found_metadata = 1;
+    /* we left a breadcrumb indicating where the end of this list is,
+       and since we add sequentially, we know from the end of the last
+       segment where this segment begins */
+    last_mdidx = (size_t)(gpr_intptr)(op->data.metadata.list.tail);
+    GPR_ASSERT(last_mdidx > mdidx);
+    GPR_ASSERT(last_mdidx <= buffer->count);
+    /* turn the array into a doubly linked list */
+    op->data.metadata.list.head = &buffer->elems[mdidx];
+    op->data.metadata.list.tail = &buffer->elems[last_mdidx - 1];
+    for (j = mdidx + 1; j < last_mdidx; j++) {
+      buffer->elems[j].prev = &buffer->elems[j - 1];
+      buffer->elems[j - 1].next = &buffer->elems[j];
+    }
+    buffer->elems[mdidx].prev = NULL;
+    buffer->elems[last_mdidx - 1].next = NULL;
+    /* track where we're up to */
+    mdidx = last_mdidx;
+  }
+  if (found_metadata) {
+    live_op_buffer->elems = buffer->elems;
+    if (mdidx != buffer->count) {
+      /* we have a partially read metadata batch still in incoming_metadata */
+      size_t new_count = buffer->count - mdidx;
+      size_t copy_bytes = sizeof(*buffer->elems) * new_count;
+      GPR_ASSERT(mdidx < buffer->count);
+      buffer->elems = gpr_malloc(copy_bytes);
+      memcpy(live_op_buffer->elems + mdidx, buffer->elems, copy_bytes);
+      buffer->count = buffer->capacity = new_count;
+    } else {
+      buffer->elems = NULL;
+      buffer->count = 0;
+      buffer->capacity = 0;
+    }
+  }
+}
diff --git a/src/core/transport/chttp2/incoming_metadata.h b/src/core/transport/chttp2/incoming_metadata.h
new file mode 100644
index 0000000..2f1de41
--- /dev/null
+++ b/src/core/transport/chttp2/incoming_metadata.h
@@ -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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H
+#define GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H
+
+#include "src/core/transport/transport.h"
+
+typedef struct {
+  grpc_linked_mdelem *elems;
+  size_t count;
+  size_t capacity;
+  gpr_timespec deadline;
+} grpc_chttp2_incoming_metadata_buffer;
+
+typedef struct {
+  grpc_linked_mdelem *elems;
+} grpc_chttp2_incoming_metadata_live_op_buffer;
+
+/** assumes everything initially zeroed */
+void grpc_chttp2_incoming_metadata_buffer_init(
+    grpc_chttp2_incoming_metadata_buffer *buffer);
+void grpc_chttp2_incoming_metadata_buffer_destroy(
+    grpc_chttp2_incoming_metadata_buffer *buffer);
+void grpc_chttp2_incoming_metadata_buffer_reset(
+    grpc_chttp2_incoming_metadata_buffer *buffer);
+
+void grpc_chttp2_incoming_metadata_buffer_add(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem);
+void grpc_chttp2_incoming_metadata_buffer_set_deadline(
+    grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline);
+
+/** extend sopb with a metadata batch; this must be post-processed by
+    grpc_chttp2_incoming_metadata_buffer_postprocess_sopb before being handed
+    out of the transport */
+void grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb);
+
+void grpc_incoming_metadata_buffer_move_to_referencing_sopb(
+    grpc_chttp2_incoming_metadata_buffer *src,
+    grpc_chttp2_incoming_metadata_buffer *dst, grpc_stream_op_buffer *sopb);
+
+void grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_stream_op_buffer *sopb,
+    grpc_chttp2_incoming_metadata_live_op_buffer *live_op_buffer);
+
+void grpc_chttp2_incoming_metadata_live_op_buffer_end(
+    grpc_chttp2_incoming_metadata_live_op_buffer *live_op_buffer);
+
+#endif /* GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H */
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
new file mode 100644
index 0000000..e5e6f44
--- /dev/null
+++ b/src/core/transport/chttp2/internal.h
@@ -0,0 +1,624 @@
+/*
+ *
+ * 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_CHTTP2_INTERNAL_H
+#define GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H
+
+#include "src/core/iomgr/endpoint.h"
+#include "src/core/transport/chttp2/frame.h"
+#include "src/core/transport/chttp2/frame_data.h"
+#include "src/core/transport/chttp2/frame_goaway.h"
+#include "src/core/transport/chttp2/frame_ping.h"
+#include "src/core/transport/chttp2/frame_rst_stream.h"
+#include "src/core/transport/chttp2/frame_settings.h"
+#include "src/core/transport/chttp2/frame_window_update.h"
+#include "src/core/transport/chttp2/hpack_parser.h"
+#include "src/core/transport/chttp2/incoming_metadata.h"
+#include "src/core/transport/chttp2/stream_encoder.h"
+#include "src/core/transport/chttp2/stream_map.h"
+#include "src/core/transport/connectivity_state.h"
+#include "src/core/transport/transport_impl.h"
+
+typedef struct grpc_chttp2_transport grpc_chttp2_transport;
+typedef struct grpc_chttp2_stream grpc_chttp2_stream;
+
+/* streams are kept in various linked lists depending on what things need to
+   happen to them... this enum labels each list */
+typedef enum {
+  GRPC_CHTTP2_LIST_ALL_STREAMS,
+  GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED,
+  GRPC_CHTTP2_LIST_WRITABLE,
+  GRPC_CHTTP2_LIST_WRITING,
+  GRPC_CHTTP2_LIST_WRITTEN,
+  GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE,
+  GRPC_CHTTP2_LIST_PARSING_SEEN,
+  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
+  GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING,
+  GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED,
+  /** streams that are waiting to start because there are too many concurrent
+      streams on the connection */
+  GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY,
+  STREAM_LIST_COUNT /* must be last */
+} grpc_chttp2_stream_list_id;
+
+/* deframer state for the overall http2 stream of bytes */
+typedef enum {
+  /* prefix: one entry per http2 connection prefix byte */
+  GRPC_DTS_CLIENT_PREFIX_0 = 0,
+  GRPC_DTS_CLIENT_PREFIX_1,
+  GRPC_DTS_CLIENT_PREFIX_2,
+  GRPC_DTS_CLIENT_PREFIX_3,
+  GRPC_DTS_CLIENT_PREFIX_4,
+  GRPC_DTS_CLIENT_PREFIX_5,
+  GRPC_DTS_CLIENT_PREFIX_6,
+  GRPC_DTS_CLIENT_PREFIX_7,
+  GRPC_DTS_CLIENT_PREFIX_8,
+  GRPC_DTS_CLIENT_PREFIX_9,
+  GRPC_DTS_CLIENT_PREFIX_10,
+  GRPC_DTS_CLIENT_PREFIX_11,
+  GRPC_DTS_CLIENT_PREFIX_12,
+  GRPC_DTS_CLIENT_PREFIX_13,
+  GRPC_DTS_CLIENT_PREFIX_14,
+  GRPC_DTS_CLIENT_PREFIX_15,
+  GRPC_DTS_CLIENT_PREFIX_16,
+  GRPC_DTS_CLIENT_PREFIX_17,
+  GRPC_DTS_CLIENT_PREFIX_18,
+  GRPC_DTS_CLIENT_PREFIX_19,
+  GRPC_DTS_CLIENT_PREFIX_20,
+  GRPC_DTS_CLIENT_PREFIX_21,
+  GRPC_DTS_CLIENT_PREFIX_22,
+  GRPC_DTS_CLIENT_PREFIX_23,
+  /* frame header byte 0... */
+  /* must follow from the prefix states */
+  GRPC_DTS_FH_0,
+  GRPC_DTS_FH_1,
+  GRPC_DTS_FH_2,
+  GRPC_DTS_FH_3,
+  GRPC_DTS_FH_4,
+  GRPC_DTS_FH_5,
+  GRPC_DTS_FH_6,
+  GRPC_DTS_FH_7,
+  /* ... frame header byte 8 */
+  GRPC_DTS_FH_8,
+  /* inside a http2 frame */
+  GRPC_DTS_FRAME
+} grpc_chttp2_deframe_transport_state;
+
+typedef enum {
+  GRPC_WRITE_STATE_OPEN,
+  GRPC_WRITE_STATE_QUEUED_CLOSE,
+  GRPC_WRITE_STATE_SENT_CLOSE
+} grpc_chttp2_write_state;
+
+typedef enum {
+  GRPC_DONT_SEND_CLOSED = 0,
+  GRPC_SEND_CLOSED,
+  GRPC_SEND_CLOSED_WITH_RST_STREAM
+} grpc_chttp2_send_closed;
+
+typedef struct {
+  grpc_chttp2_stream *head;
+  grpc_chttp2_stream *tail;
+} grpc_chttp2_stream_list;
+
+typedef struct {
+  grpc_chttp2_stream *next;
+  grpc_chttp2_stream *prev;
+} grpc_chttp2_stream_link;
+
+/* We keep several sets of connection wide parameters */
+typedef enum {
+  /* The settings our peer has asked for (and we have acked) */
+  GRPC_PEER_SETTINGS = 0,
+  /* The settings we'd like to have */
+  GRPC_LOCAL_SETTINGS,
+  /* The settings we've published to our peer */
+  GRPC_SENT_SETTINGS,
+  /* The settings the peer has acked */
+  GRPC_ACKED_SETTINGS,
+  GRPC_NUM_SETTING_SETS
+} grpc_chttp2_setting_set;
+
+/* Outstanding ping request data */
+typedef struct grpc_chttp2_outstanding_ping {
+  gpr_uint8 id[8];
+  grpc_iomgr_closure *on_recv;
+  struct grpc_chttp2_outstanding_ping *next;
+  struct grpc_chttp2_outstanding_ping *prev;
+} grpc_chttp2_outstanding_ping;
+
+typedef struct {
+  /** data to write next write */
+  gpr_slice_buffer qbuf;
+  /** queued callbacks */
+  grpc_iomgr_closure *pending_closures_head;
+  grpc_iomgr_closure *pending_closures_tail;
+
+  /** window available for us to send to peer */
+  gpr_uint32 outgoing_window;
+  /** window available for peer to send to us - updated after parse */
+  gpr_uint32 incoming_window;
+  /** how much window would we like to have for incoming_window */
+  gpr_uint32 connection_window_target;
+
+  /** have we seen a goaway */
+  gpr_uint8 seen_goaway;
+  /** have we sent a goaway */
+  gpr_uint8 sent_goaway;
+
+  /** is this transport a client? */
+  gpr_uint8 is_client;
+  /** are the local settings dirty and need to be sent? */
+  gpr_uint8 dirtied_local_settings;
+  /** have local settings been sent? */
+  gpr_uint8 sent_local_settings;
+  /** bitmask of setting indexes to send out */
+  gpr_uint32 force_send_settings;
+  /** settings values */
+  gpr_uint32 settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS];
+
+  /** what is the next stream id to be allocated by this peer?
+      copied to next_stream_id in parsing when parsing commences */
+  gpr_uint32 next_stream_id;
+
+  /** last received stream id */
+  gpr_uint32 last_incoming_stream_id;
+
+  /** pings awaiting responses */
+  grpc_chttp2_outstanding_ping pings;
+  /** next payload for an outgoing ping */
+  gpr_uint64 ping_counter;
+
+  /** concurrent stream count: updated when not parsing,
+      so this is a strict over-estimation on the client */
+  gpr_uint32 concurrent_stream_count;
+} grpc_chttp2_transport_global;
+
+typedef struct {
+  /** data to write now */
+  gpr_slice_buffer outbuf;
+  /** hpack encoding */
+  grpc_chttp2_hpack_compressor hpack_compressor;
+  /** is this a client? */
+  gpr_uint8 is_client;
+} grpc_chttp2_transport_writing;
+
+struct grpc_chttp2_transport_parsing {
+  /** is this transport a client? (boolean) */
+  gpr_uint8 is_client;
+
+  /** were settings updated? */
+  gpr_uint8 settings_updated;
+  /** was a settings ack received? */
+  gpr_uint8 settings_ack_received;
+  /** was a goaway frame received? */
+  gpr_uint8 goaway_received;
+
+  /** initial window change */
+  gpr_int64 initial_window_update;
+
+  /** data to write later - after parsing */
+  gpr_slice_buffer qbuf;
+  /* metadata object cache */
+  grpc_mdstr *str_grpc_timeout;
+  /** parser for headers */
+  grpc_chttp2_hpack_parser hpack_parser;
+  /** simple one shot parsers */
+  union {
+    grpc_chttp2_window_update_parser window_update;
+    grpc_chttp2_settings_parser settings;
+    grpc_chttp2_ping_parser ping;
+    grpc_chttp2_rst_stream_parser rst_stream;
+  } simple;
+  /** parser for goaway frames */
+  grpc_chttp2_goaway_parser goaway_parser;
+
+  /** window available for peer to send to us */
+  gpr_uint32 incoming_window;
+  gpr_uint32 incoming_window_delta;
+
+  /** next stream id available at the time of beginning parsing */
+  gpr_uint32 next_stream_id;
+  gpr_uint32 last_incoming_stream_id;
+
+  /* deframing */
+  grpc_chttp2_deframe_transport_state deframe_state;
+  gpr_uint8 incoming_frame_type;
+  gpr_uint8 incoming_frame_flags;
+  gpr_uint8 header_eof;
+  gpr_uint32 expect_continuation_stream_id;
+  gpr_uint32 incoming_frame_size;
+  gpr_uint32 incoming_stream_id;
+
+  /* active parser */
+  void *parser_data;
+  grpc_chttp2_stream_parsing *incoming_stream;
+  grpc_chttp2_parse_error (*parser)(
+      void *parser_user_data, grpc_chttp2_transport_parsing *transport_parsing,
+      grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+  /* received settings */
+  gpr_uint32 settings[GRPC_CHTTP2_NUM_SETTINGS];
+
+  /* goaway data */
+  grpc_status_code goaway_error;
+  gpr_uint32 goaway_last_stream_index;
+  gpr_slice goaway_text;
+
+  gpr_uint64 outgoing_window_update;
+
+  /** pings awaiting responses */
+  grpc_chttp2_outstanding_ping pings;
+};
+
+struct grpc_chttp2_transport {
+  grpc_transport base; /* must be first */
+  grpc_endpoint *ep;
+  grpc_mdctx *metadata_context;
+  gpr_refcount refs;
+
+  gpr_mu mu;
+
+  /** is the transport destroying itself? */
+  gpr_uint8 destroying;
+  /** has the upper layer closed the transport? */
+  gpr_uint8 closed;
+
+  /** is a thread currently writing */
+  gpr_uint8 writing_active;
+  /** is a thread currently parsing */
+  gpr_uint8 parsing_active;
+
+  /** is there a read request to the endpoint outstanding? */
+  gpr_uint8 endpoint_reading;
+
+  /** various lists of streams */
+  grpc_chttp2_stream_list lists[STREAM_LIST_COUNT];
+
+  /** global state for reading/writing */
+  grpc_chttp2_transport_global global;
+  /** state only accessible by the chain of execution that
+      set writing_active=1 */
+  grpc_chttp2_transport_writing writing;
+  /** state only accessible by the chain of execution that
+      set parsing_active=1 */
+  grpc_chttp2_transport_parsing parsing;
+
+  /** maps stream id to grpc_chttp2_stream objects;
+      owned by the parsing thread when parsing */
+  grpc_chttp2_stream_map parsing_stream_map;
+
+  /** streams created by the client (possibly during parsing);
+      merged with parsing_stream_map during unlock when no
+      parsing is occurring */
+  grpc_chttp2_stream_map new_stream_map;
+
+  /** closure to execute writing */
+  grpc_iomgr_closure writing_action;
+  /** closure to start reading from the endpoint */
+  grpc_iomgr_closure reading_action;
+
+  /** address to place a newly accepted stream - set and unset by
+      grpc_chttp2_parsing_accept_stream; used by init_stream to
+      publish the accepted server stream */
+  grpc_chttp2_stream **accepting_stream;
+
+  struct {
+    /* accept stream callback */
+    void (*accept_stream)(void *user_data, grpc_transport *transport,
+                          const void *server_data);
+    void *accept_stream_user_data;
+
+    /** connectivity tracking */
+    grpc_connectivity_state_tracker state_tracker;
+  } channel_callback;
+};
+
+typedef struct {
+  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
+  gpr_uint32 id;
+
+  grpc_iomgr_closure *send_done_closure;
+  grpc_iomgr_closure *recv_done_closure;
+
+  /** window available for us to send to peer */
+  gpr_int64 outgoing_window;
+  /** The number of bytes the upper layers have offered to receive.
+      As the upper layer offers more bytes, this value increases.
+      As bytes are read, this value decreases. */
+  gpr_uint32 max_recv_bytes;
+  /** The number of bytes the upper layer has offered to read but we have
+      not yet announced to HTTP2 flow control.
+      As the upper layers offer to read more bytes, this value increases.
+      As we advertise incoming flow control window, this value decreases. */
+  gpr_uint32 unannounced_incoming_window;
+  /** The number of bytes of HTTP2 flow control we have advertised.
+      As we advertise incoming flow control window, this value increases.
+      As bytes are read, this value decreases.
+      Updated after parse. */
+  gpr_uint32 incoming_window;
+  /** stream ops the transport user would like to send */
+  grpc_stream_op_buffer *outgoing_sopb;
+  /** when the application requests writes be closed, the write_closed is
+      'queued'; when the close is flow controlled into the send path, we are
+      'sending' it; when the write has been performed it is 'sent' */
+  grpc_chttp2_write_state write_state;
+  /** is this stream closed (boolean) */
+  gpr_uint8 read_closed;
+  /** has this stream been cancelled? (boolean) */
+  gpr_uint8 cancelled;
+  grpc_status_code cancelled_status;
+  /** have we told the upper layer that this stream is cancelled? */
+  gpr_uint8 published_cancelled;
+  /** is this stream in the stream map? (boolean) */
+  gpr_uint8 in_stream_map;
+
+  /** stream state already published to the upper layer */
+  grpc_stream_state published_state;
+  /** address to publish next stream state to */
+  grpc_stream_state *publish_state;
+  /** pointer to sop buffer to fill in with new stream ops */
+  grpc_stream_op_buffer *publish_sopb;
+  grpc_stream_op_buffer incoming_sopb;
+
+  /** incoming metadata */
+  grpc_chttp2_incoming_metadata_buffer incoming_metadata;
+  grpc_chttp2_incoming_metadata_live_op_buffer outstanding_metadata;
+} grpc_chttp2_stream_global;
+
+typedef struct {
+  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
+  gpr_uint32 id;
+  /** sops that have passed flow control to be written */
+  grpc_stream_op_buffer sopb;
+  /** how strongly should we indicate closure with the next write */
+  grpc_chttp2_send_closed send_closed;
+  /** how much window should we announce? */
+  gpr_uint32 announce_window;
+} grpc_chttp2_stream_writing;
+
+struct grpc_chttp2_stream_parsing {
+  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
+  gpr_uint32 id;
+  /** has this stream received a close */
+  gpr_uint8 received_close;
+  /** saw a rst_stream */
+  gpr_uint8 saw_rst_stream;
+  /** incoming_window has been reduced by this much during parsing */
+  gpr_uint32 incoming_window_delta;
+  /** window available for peer to send to us */
+  gpr_uint32 incoming_window;
+  /** parsing state for data frames */
+  grpc_chttp2_data_parser data_parser;
+  /** reason give to rst_stream */
+  gpr_uint32 rst_stream_reason;
+  /* amount of window given */
+  gpr_uint64 outgoing_window_update;
+
+  /** incoming metadata */
+  grpc_chttp2_incoming_metadata_buffer incoming_metadata;
+};
+
+struct grpc_chttp2_stream {
+  grpc_chttp2_stream_global global;
+  grpc_chttp2_stream_writing writing;
+  grpc_chttp2_stream_parsing parsing;
+
+  grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
+  gpr_uint8 included[STREAM_LIST_COUNT];
+};
+
+/** Transport writing call flow:
+    chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes
+   are required;
+    if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the
+   writes.
+    Once writes have been completed (meaning another write could potentially be
+   started),
+    grpc_chttp2_terminate_writing is called. This will call
+   grpc_chttp2_cleanup_writing, at which
+    point the write phase is complete. */
+
+/** Someone is unlocking the transport mutex: check to see if writes
+    are required, and schedule them if so */
+int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global,
+                                       grpc_chttp2_transport_writing *writing);
+void grpc_chttp2_perform_writes(
+    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint);
+void grpc_chttp2_terminate_writing(
+    grpc_chttp2_transport_writing *transport_writing, int success);
+void grpc_chttp2_cleanup_writing(grpc_chttp2_transport_global *global,
+                                 grpc_chttp2_transport_writing *writing);
+
+void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global,
+                                 grpc_chttp2_transport_parsing *parsing);
+/** Process one slice of incoming data; return 1 if the connection is still
+    viable after reading, or 0 if the connection should be torn down */
+int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
+                             gpr_slice slice);
+void grpc_chttp2_publish_reads(grpc_chttp2_transport_global *global,
+                               grpc_chttp2_transport_parsing *parsing);
+
+/** Get a writable stream
+    returns non-zero if there was a stream available */
+void grpc_chttp2_list_add_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_writing **stream_writing);
+
+void grpc_chttp2_list_add_incoming_window_updated(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_incoming_window_updated(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_parsing **stream_parsing);
+void grpc_chttp2_list_remove_incoming_window_updated(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+
+void grpc_chttp2_list_add_writing_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing);
+int grpc_chttp2_list_have_writing_streams(
+    grpc_chttp2_transport_writing *transport_writing);
+int grpc_chttp2_list_pop_writing_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing **stream_writing);
+
+void grpc_chttp2_list_add_written_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing);
+int grpc_chttp2_list_pop_written_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_writing **stream_writing);
+
+void grpc_chttp2_list_add_writable_window_update_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_writable_window_update_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_writing **stream_writing);
+void grpc_chttp2_list_remove_writable_window_update_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+
+void grpc_chttp2_list_add_parsing_seen_stream(
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing);
+int grpc_chttp2_list_pop_parsing_seen_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_parsing **stream_parsing);
+
+void grpc_chttp2_list_add_waiting_for_concurrency(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_waiting_for_concurrency(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+
+void grpc_chttp2_list_add_closed_waiting_for_parsing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_closed_waiting_for_parsing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+
+void grpc_chttp2_list_add_cancelled_waiting_for_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_cancelled_waiting_for_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+
+void grpc_chttp2_list_add_read_write_state_changed(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_read_write_state_changed(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+
+/** schedule a closure to run without the transport lock taken */
+void grpc_chttp2_schedule_closure(
+    grpc_chttp2_transport_global *transport_global, grpc_iomgr_closure *closure,
+    int success);
+
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
+    grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id);
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
+    grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id);
+
+void grpc_chttp2_add_incoming_goaway(
+    grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error,
+    gpr_slice goaway_text);
+
+void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
+                                 grpc_chttp2_stream *s);
+/* returns 1 if this is the last stream, 0 otherwise */
+int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t,
+                                  grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT;
+int grpc_chttp2_has_streams(grpc_chttp2_transport *t);
+void grpc_chttp2_for_all_streams(
+    grpc_chttp2_transport_global *transport_global, void *user_data,
+    void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data,
+               grpc_chttp2_stream_global *stream_global));
+
+void grpc_chttp2_parsing_become_skip_parser(
+    grpc_chttp2_transport_parsing *transport_parsing);
+
+#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
+  (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)
+
+extern int grpc_http_trace;
+extern int grpc_flowctl_trace;
+
+#define GRPC_CHTTP2_IF_TRACING(stmt) \
+  if (!(grpc_http_trace))            \
+    ;                                \
+  else                               \
+  stmt
+
+#define GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(reason, transport, context, var,      \
+                                         delta)                                \
+  if (!(grpc_flowctl_trace)) {                                                 \
+  } else {                                                                     \
+    grpc_chttp2_flowctl_trace(__FILE__, __LINE__, reason, #context, #var,      \
+                              transport->is_client, context->id, context->var, \
+                              delta);                                          \
+  }
+
+#define GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(reason, context, var, delta)   \
+  if (!(grpc_flowctl_trace)) {                                             \
+  } else {                                                                 \
+    grpc_chttp2_flowctl_trace(__FILE__, __LINE__, reason, #context, #var,  \
+                              context->is_client, 0, context->var, delta); \
+  }
+
+void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason,
+                               const char *context, const char *var,
+                               int is_client, gpr_uint32 stream_id,
+                               gpr_int64 current_value, gpr_int64 delta);
+
+#endif
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
new file mode 100644
index 0000000..aa32f2e
--- /dev/null
+++ b/src/core/transport/chttp2/parsing.c
@@ -0,0 +1,818 @@
+/*
+ *
+ * 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/transport/chttp2/internal.h"
+
+#include <string.h>
+
+#include "src/core/transport/chttp2/http2_errors.h"
+#include "src/core/transport/chttp2/status_conversion.h"
+#include "src/core/transport/chttp2/timeout_encoding.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing);
+static int init_header_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing, int is_continuation);
+static int init_data_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing);
+static int init_rst_stream_parser(
+    grpc_chttp2_transport_parsing *transport_parsing);
+static int init_settings_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing);
+static int init_window_update_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing);
+static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing);
+static int init_goaway_parser(grpc_chttp2_transport_parsing *transport_parsing);
+static int init_skip_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing, int is_header);
+
+static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
+                             gpr_slice slice, int is_last);
+
+void grpc_chttp2_prepare_to_read(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  grpc_chttp2_stream_global *stream_global;
+  grpc_chttp2_stream_parsing *stream_parsing;
+
+  transport_parsing->next_stream_id = transport_global->next_stream_id;
+
+  /* update the parsing view of incoming window */
+  if (transport_parsing->incoming_window != transport_global->incoming_window) {
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+        "parse", transport_parsing, incoming_window,
+        (gpr_int64)transport_global->incoming_window -
+            (gpr_int64)transport_parsing->incoming_window);
+    transport_parsing->incoming_window = transport_global->incoming_window;
+  }
+  while (grpc_chttp2_list_pop_incoming_window_updated(
+      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
+    stream_parsing->id = stream_global->id;
+    if (stream_parsing->incoming_window != stream_global->incoming_window) {
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+          "parse", transport_parsing, stream_parsing, incoming_window,
+          (gpr_int64)stream_global->incoming_window -
+              (gpr_int64)stream_parsing->incoming_window);
+      stream_parsing->incoming_window = stream_global->incoming_window;
+    }
+  }
+}
+
+void grpc_chttp2_publish_reads(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  grpc_chttp2_stream_global *stream_global;
+  grpc_chttp2_stream_parsing *stream_parsing;
+
+  /* transport_parsing->last_incoming_stream_id is used as
+     last-grpc_chttp2_stream-id when
+     sending GOAWAY frame.
+     https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
+     says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream
+     ID.  So,
+     since we don't have server pushed streams, client should send
+     GOAWAY last-grpc_chttp2_stream-id=0 in this case. */
+  if (!transport_parsing->is_client) {
+    transport_global->last_incoming_stream_id =
+        transport_parsing->incoming_stream_id;
+  }
+
+  /* copy parsing qbuf to global qbuf */
+  gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf);
+
+  /* update global settings */
+  if (transport_parsing->settings_updated) {
+    memcpy(transport_global->settings[GRPC_PEER_SETTINGS],
+           transport_parsing->settings, sizeof(transport_parsing->settings));
+    transport_parsing->settings_updated = 0;
+  }
+
+  /* update settings based on ack if received */
+  if (transport_parsing->settings_ack_received) {
+    memcpy(transport_global->settings[GRPC_ACKED_SETTINGS],
+           transport_global->settings[GRPC_SENT_SETTINGS],
+           GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
+    transport_parsing->settings_ack_received = 0;
+  }
+
+  /* move goaway to the global state if we received one (it will be
+     published later */
+  if (transport_parsing->goaway_received) {
+    grpc_chttp2_add_incoming_goaway(transport_global,
+                                    transport_parsing->goaway_error,
+                                    transport_parsing->goaway_text);
+    transport_parsing->goaway_text = gpr_empty_slice();
+    transport_parsing->goaway_received = 0;
+  }
+
+  /* propagate flow control tokens to global state */
+  if (transport_parsing->outgoing_window_update) {
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+        "parsed", transport_global, outgoing_window,
+        transport_parsing->outgoing_window_update);
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+        "parsed", transport_parsing, outgoing_window_update,
+        -(gpr_int64)transport_parsing->outgoing_window_update);
+    transport_global->outgoing_window +=
+        transport_parsing->outgoing_window_update;
+    transport_parsing->outgoing_window_update = 0;
+  }
+
+  if (transport_parsing->incoming_window_delta) {
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+        "parsed", transport_global, incoming_window,
+        -(gpr_int64)transport_parsing->incoming_window_delta);
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+        "parsed", transport_parsing, incoming_window_delta,
+        -(gpr_int64)transport_parsing->incoming_window_delta);
+    transport_global->incoming_window -=
+        transport_parsing->incoming_window_delta;
+    transport_parsing->incoming_window_delta = 0;
+  }
+
+  /* for each stream that saw an update, fixup global state */
+  while (grpc_chttp2_list_pop_parsing_seen_stream(
+      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
+    /* update incoming flow control window */
+    if (stream_parsing->incoming_window_delta) {
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+          "parsed", transport_parsing, stream_global, incoming_window,
+          -(gpr_int64)stream_parsing->incoming_window_delta);
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+          "parsed", transport_parsing, stream_parsing, incoming_window_delta,
+          -(gpr_int64)stream_parsing->incoming_window_delta);
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+          "parsed", transport_parsing, stream_global, max_recv_bytes,
+          -(gpr_int64)stream_parsing->incoming_window_delta);
+      stream_global->incoming_window -= stream_parsing->incoming_window_delta;
+      GPR_ASSERT(stream_global->max_recv_bytes >= 
+          stream_parsing->incoming_window_delta);
+      stream_global->max_recv_bytes -= 
+          stream_parsing->incoming_window_delta;
+      stream_parsing->incoming_window_delta = 0;
+      grpc_chttp2_list_add_writable_window_update_stream(transport_global,
+                                                         stream_global);
+    }
+
+    /* update outgoing flow control window */
+    if (stream_parsing->outgoing_window_update) {
+      int was_zero = stream_global->outgoing_window <= 0;
+      int is_zero;
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("parsed", transport_parsing,
+                                       stream_global, outgoing_window,
+                                       stream_parsing->outgoing_window_update);
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+          "parsed", transport_parsing, stream_parsing, outgoing_window_update,
+          -(gpr_int64)stream_parsing->outgoing_window_update);
+      stream_global->outgoing_window += stream_parsing->outgoing_window_update;
+      stream_parsing->outgoing_window_update = 0;
+      is_zero = stream_global->outgoing_window <= 0;
+      if (was_zero && !is_zero) {
+        grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
+      }
+    }
+
+    /* updating closed status */
+    if (stream_parsing->received_close) {
+      stream_global->read_closed = 1;
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+    }
+    if (stream_parsing->saw_rst_stream) {
+      stream_global->cancelled = 1;
+      stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(
+          stream_parsing->rst_stream_reason);
+      if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) {
+        stream_global->published_cancelled = 1;
+      }
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+    }
+
+    /* publish incoming stream ops */
+    if (stream_parsing->data_parser.incoming_sopb.nops > 0) {
+      grpc_incoming_metadata_buffer_move_to_referencing_sopb(
+          &stream_parsing->incoming_metadata, &stream_global->incoming_metadata,
+          &stream_parsing->data_parser.incoming_sopb);
+      grpc_sopb_move_to(&stream_parsing->data_parser.incoming_sopb,
+                        &stream_global->incoming_sopb);
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+    }
+  }
+}
+
+int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
+                             gpr_slice slice) {
+  gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
+  gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
+  gpr_uint8 *cur = beg;
+
+  if (cur == end) return 1;
+
+  switch (transport_parsing->deframe_state) {
+    case GRPC_DTS_CLIENT_PREFIX_0:
+    case GRPC_DTS_CLIENT_PREFIX_1:
+    case GRPC_DTS_CLIENT_PREFIX_2:
+    case GRPC_DTS_CLIENT_PREFIX_3:
+    case GRPC_DTS_CLIENT_PREFIX_4:
+    case GRPC_DTS_CLIENT_PREFIX_5:
+    case GRPC_DTS_CLIENT_PREFIX_6:
+    case GRPC_DTS_CLIENT_PREFIX_7:
+    case GRPC_DTS_CLIENT_PREFIX_8:
+    case GRPC_DTS_CLIENT_PREFIX_9:
+    case GRPC_DTS_CLIENT_PREFIX_10:
+    case GRPC_DTS_CLIENT_PREFIX_11:
+    case GRPC_DTS_CLIENT_PREFIX_12:
+    case GRPC_DTS_CLIENT_PREFIX_13:
+    case GRPC_DTS_CLIENT_PREFIX_14:
+    case GRPC_DTS_CLIENT_PREFIX_15:
+    case GRPC_DTS_CLIENT_PREFIX_16:
+    case GRPC_DTS_CLIENT_PREFIX_17:
+    case GRPC_DTS_CLIENT_PREFIX_18:
+    case GRPC_DTS_CLIENT_PREFIX_19:
+    case GRPC_DTS_CLIENT_PREFIX_20:
+    case GRPC_DTS_CLIENT_PREFIX_21:
+    case GRPC_DTS_CLIENT_PREFIX_22:
+    case GRPC_DTS_CLIENT_PREFIX_23:
+      while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
+        if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
+                                                          ->deframe_state]) {
+          gpr_log(GPR_INFO,
+                  "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
+                  "at byte %d",
+                  GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
+                                                        ->deframe_state],
+                  (int)(gpr_uint8)GRPC_CHTTP2_CLIENT_CONNECT_STRING
+                      [transport_parsing->deframe_state],
+                  *cur, (int)*cur, transport_parsing->deframe_state);
+          return 0;
+        }
+        ++cur;
+        ++transport_parsing->deframe_state;
+      }
+      if (cur == end) {
+        return 1;
+      }
+    /* fallthrough */
+    dts_fh_0:
+    case GRPC_DTS_FH_0:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_frame_size = ((gpr_uint32)*cur) << 16;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_1;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_1:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_2;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_2:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_frame_size |= *cur;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_3;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_3:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_frame_type = *cur;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_4;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_4:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_frame_flags = *cur;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_5;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_5:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_stream_id = (((gpr_uint32)*cur) & 0x7f) << 24;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_6;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_6:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_7;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_7:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
+      if (++cur == end) {
+        transport_parsing->deframe_state = GRPC_DTS_FH_8;
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FH_8:
+      GPR_ASSERT(cur < end);
+      transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur);
+      transport_parsing->deframe_state = GRPC_DTS_FRAME;
+      if (!init_frame_parser(transport_parsing)) {
+        return 0;
+      }
+      if (transport_parsing->incoming_stream_id) {
+        transport_parsing->last_incoming_stream_id =
+            transport_parsing->incoming_stream_id;
+      }
+      if (transport_parsing->incoming_frame_size == 0) {
+        if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1)) {
+          return 0;
+        }
+        transport_parsing->incoming_stream = NULL;
+        if (++cur == end) {
+          transport_parsing->deframe_state = GRPC_DTS_FH_0;
+          return 1;
+        }
+        goto dts_fh_0; /* loop */
+      }
+      if (++cur == end) {
+        return 1;
+      }
+    /* fallthrough */
+    case GRPC_DTS_FRAME:
+      GPR_ASSERT(cur < end);
+      if ((gpr_uint32)(end - cur) == transport_parsing->incoming_frame_size) {
+        if (!parse_frame_slice(
+                transport_parsing,
+                gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) {
+          return 0;
+        }
+        transport_parsing->deframe_state = GRPC_DTS_FH_0;
+        transport_parsing->incoming_stream = NULL;
+        return 1;
+      } else if ((gpr_uint32)(end - cur) >
+                 transport_parsing->incoming_frame_size) {
+        if (!parse_frame_slice(
+                transport_parsing,
+                gpr_slice_sub_no_ref(
+                    slice, cur - beg,
+                    cur + transport_parsing->incoming_frame_size - beg),
+                1)) {
+          return 0;
+        }
+        cur += transport_parsing->incoming_frame_size;
+        transport_parsing->incoming_stream = NULL;
+        goto dts_fh_0; /* loop */
+      } else {
+        if (!parse_frame_slice(
+                transport_parsing,
+                gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) {
+          return 0;
+        }
+        transport_parsing->incoming_frame_size -= (end - cur);
+        return 1;
+      }
+      gpr_log(GPR_ERROR, "should never reach here");
+      abort();
+  }
+
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+
+  return 0;
+}
+
+static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) {
+  if (transport_parsing->expect_continuation_stream_id != 0) {
+    if (transport_parsing->incoming_frame_type !=
+        GRPC_CHTTP2_FRAME_CONTINUATION) {
+      gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x",
+              transport_parsing->incoming_frame_type);
+      return 0;
+    }
+    if (transport_parsing->expect_continuation_stream_id !=
+        transport_parsing->incoming_stream_id) {
+      gpr_log(GPR_ERROR,
+              "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
+              "grpc_chttp2_stream %08x",
+              transport_parsing->expect_continuation_stream_id,
+              transport_parsing->incoming_stream_id);
+      return 0;
+    }
+    return init_header_frame_parser(transport_parsing, 1);
+  }
+  switch (transport_parsing->incoming_frame_type) {
+    case GRPC_CHTTP2_FRAME_DATA:
+      return init_data_frame_parser(transport_parsing);
+    case GRPC_CHTTP2_FRAME_HEADER:
+      return init_header_frame_parser(transport_parsing, 0);
+    case GRPC_CHTTP2_FRAME_CONTINUATION:
+      gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame");
+      return 0;
+    case GRPC_CHTTP2_FRAME_RST_STREAM:
+      return init_rst_stream_parser(transport_parsing);
+    case GRPC_CHTTP2_FRAME_SETTINGS:
+      return init_settings_frame_parser(transport_parsing);
+    case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
+      return init_window_update_frame_parser(transport_parsing);
+    case GRPC_CHTTP2_FRAME_PING:
+      return init_ping_parser(transport_parsing);
+    case GRPC_CHTTP2_FRAME_GOAWAY:
+      return init_goaway_parser(transport_parsing);
+    default:
+      gpr_log(GPR_ERROR, "Unknown frame type %02x",
+              transport_parsing->incoming_frame_type);
+      return init_skip_frame_parser(transport_parsing, 0);
+  }
+}
+
+static grpc_chttp2_parse_error skip_parser(
+    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
+
+static int init_skip_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing, int is_header) {
+  if (is_header) {
+    int is_eoh = transport_parsing->expect_continuation_stream_id != 0;
+    transport_parsing->parser = grpc_chttp2_header_parser_parse;
+    transport_parsing->parser_data = &transport_parsing->hpack_parser;
+    transport_parsing->hpack_parser.on_header = skip_header;
+    transport_parsing->hpack_parser.on_header_user_data = NULL;
+    transport_parsing->hpack_parser.is_boundary = is_eoh;
+    transport_parsing->hpack_parser.is_eof =
+        is_eoh ? transport_parsing->header_eof : 0;
+  } else {
+    transport_parsing->parser = skip_parser;
+  }
+  return 1;
+}
+
+void grpc_chttp2_parsing_become_skip_parser(
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  init_skip_frame_parser(
+      transport_parsing,
+      transport_parsing->parser == grpc_chttp2_header_parser_parse);
+}
+
+static grpc_chttp2_parse_error update_incoming_window(
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing) {
+  if (transport_parsing->incoming_frame_size >
+      transport_parsing->incoming_window) {
+    gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
+            transport_parsing->incoming_frame_size,
+            transport_parsing->incoming_window);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+
+  if (transport_parsing->incoming_frame_size >
+      stream_parsing->incoming_window) {
+    gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
+            transport_parsing->incoming_frame_size,
+            stream_parsing->incoming_window);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+
+  GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+      "data", transport_parsing, incoming_window,
+      -(gpr_int64)transport_parsing->incoming_frame_size);
+  GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("data", transport_parsing,
+                                      incoming_window_delta,
+                                      transport_parsing->incoming_frame_size);
+  GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+      "data", transport_parsing, stream_parsing, incoming_window,
+      -(gpr_int64)transport_parsing->incoming_frame_size);
+  GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("data", transport_parsing, stream_parsing,
+                                   incoming_window_delta,
+                                   transport_parsing->incoming_frame_size);
+
+  transport_parsing->incoming_window -= transport_parsing->incoming_frame_size;
+  transport_parsing->incoming_window_delta +=
+      transport_parsing->incoming_frame_size;
+  stream_parsing->incoming_window -= transport_parsing->incoming_frame_size;
+  stream_parsing->incoming_window_delta +=
+      transport_parsing->incoming_frame_size;
+  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+static int init_data_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  grpc_chttp2_stream_parsing *stream_parsing =
+      grpc_chttp2_parsing_lookup_stream(transport_parsing,
+                                        transport_parsing->incoming_stream_id);
+  grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK;
+  if (!stream_parsing || stream_parsing->received_close)
+    return init_skip_frame_parser(transport_parsing, 0);
+  if (err == GRPC_CHTTP2_PARSE_OK) {
+    err = update_incoming_window(transport_parsing, stream_parsing);
+  }
+  if (err == GRPC_CHTTP2_PARSE_OK) {
+    err = grpc_chttp2_data_parser_begin_frame(
+        &stream_parsing->data_parser, transport_parsing->incoming_frame_flags);
+  }
+  switch (err) {
+    case GRPC_CHTTP2_PARSE_OK:
+      transport_parsing->incoming_stream = stream_parsing;
+      transport_parsing->parser = grpc_chttp2_data_parser_parse;
+      transport_parsing->parser_data = &stream_parsing->data_parser;
+      return 1;
+    case GRPC_CHTTP2_STREAM_ERROR:
+      stream_parsing->received_close = 1;
+      stream_parsing->saw_rst_stream = 1;
+      stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
+      gpr_slice_buffer_add(
+          &transport_parsing->qbuf,
+          grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
+                                        GRPC_CHTTP2_PROTOCOL_ERROR));
+      return init_skip_frame_parser(transport_parsing, 0);
+    case GRPC_CHTTP2_CONNECTION_ERROR:
+      return 0;
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+  return 0;
+}
+
+static void free_timeout(void *p) { gpr_free(p); }
+
+static void on_header(void *tp, grpc_mdelem *md) {
+  grpc_chttp2_transport_parsing *transport_parsing = tp;
+  grpc_chttp2_stream_parsing *stream_parsing =
+      transport_parsing->incoming_stream;
+
+  GPR_ASSERT(stream_parsing);
+
+  GRPC_CHTTP2_IF_TRACING(gpr_log(
+      GPR_INFO, "HTTP:%d:HDR: %s: %s", stream_parsing->id,
+      transport_parsing->is_client ? "CLI" : "SVR",
+      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
+
+  if (md->key == transport_parsing->str_grpc_timeout) {
+    gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
+    if (!cached_timeout) {
+      /* not already parsed: parse it now, and store the result away */
+      cached_timeout = gpr_malloc(sizeof(gpr_timespec));
+      if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
+                                      cached_timeout)) {
+        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
+                grpc_mdstr_as_c_string(md->value));
+        *cached_timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
+      }
+      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+    }
+    grpc_chttp2_incoming_metadata_buffer_set_deadline(
+        &stream_parsing->incoming_metadata,
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), *cached_timeout));
+    GRPC_MDELEM_UNREF(md);
+  } else {
+    grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata,
+                                             md);
+  }
+
+  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
+}
+
+static int init_header_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing, int is_continuation) {
+  int is_eoh = (transport_parsing->incoming_frame_flags &
+                GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
+  int via_accept = 0;
+  grpc_chttp2_stream_parsing *stream_parsing;
+
+  if (is_eoh) {
+    transport_parsing->expect_continuation_stream_id = 0;
+  } else {
+    transport_parsing->expect_continuation_stream_id =
+        transport_parsing->incoming_stream_id;
+  }
+
+  if (!is_continuation) {
+    transport_parsing->header_eof = (transport_parsing->incoming_frame_flags &
+                                     GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
+  }
+
+  /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
+  stream_parsing = grpc_chttp2_parsing_lookup_stream(
+      transport_parsing, transport_parsing->incoming_stream_id);
+  if (stream_parsing == NULL) {
+    if (is_continuation) {
+      gpr_log(GPR_ERROR,
+              "grpc_chttp2_stream disbanded before CONTINUATION received");
+      return init_skip_frame_parser(transport_parsing, 1);
+    }
+    if (transport_parsing->is_client) {
+      if ((transport_parsing->incoming_stream_id & 1) &&
+          transport_parsing->incoming_stream_id <
+              transport_parsing->next_stream_id) {
+        /* this is an old (probably cancelled) grpc_chttp2_stream */
+      } else {
+        gpr_log(GPR_ERROR,
+                "ignoring new grpc_chttp2_stream creation on client");
+      }
+      return init_skip_frame_parser(transport_parsing, 1);
+    } else if (transport_parsing->last_incoming_stream_id >
+               transport_parsing->incoming_stream_id) {
+      gpr_log(GPR_ERROR,
+              "ignoring out of order new grpc_chttp2_stream request on server; "
+              "last grpc_chttp2_stream "
+              "id=%d, new grpc_chttp2_stream id=%d",
+              transport_parsing->last_incoming_stream_id,
+              transport_parsing->incoming_stream_id);
+      return init_skip_frame_parser(transport_parsing, 1);
+    } else if ((transport_parsing->incoming_stream_id & 1) == 0) {
+      gpr_log(GPR_ERROR,
+              "ignoring grpc_chttp2_stream with non-client generated index %d",
+              transport_parsing->incoming_stream_id);
+      return init_skip_frame_parser(transport_parsing, 1);
+    }
+    stream_parsing = transport_parsing->incoming_stream =
+        grpc_chttp2_parsing_accept_stream(
+            transport_parsing, transport_parsing->incoming_stream_id);
+    if (stream_parsing == NULL) {
+      gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted");
+      return init_skip_frame_parser(transport_parsing, 1);
+    }
+    via_accept = 1;
+  } else {
+    transport_parsing->incoming_stream = stream_parsing;
+  }
+  GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1));
+  if (stream_parsing->received_close) {
+    gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header");
+    transport_parsing->incoming_stream = NULL;
+    return init_skip_frame_parser(transport_parsing, 1);
+  }
+  transport_parsing->parser = grpc_chttp2_header_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->hpack_parser;
+  transport_parsing->hpack_parser.on_header = on_header;
+  transport_parsing->hpack_parser.on_header_user_data = transport_parsing;
+  transport_parsing->hpack_parser.is_boundary = is_eoh;
+  transport_parsing->hpack_parser.is_eof =
+      is_eoh ? transport_parsing->header_eof : 0;
+  if (!is_continuation && (transport_parsing->incoming_frame_flags &
+                           GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
+    grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser);
+  }
+  return 1;
+}
+
+static int init_window_update_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame(
+                                       &transport_parsing->simple.window_update,
+                                       transport_parsing->incoming_frame_size,
+                                       transport_parsing->incoming_frame_flags);
+  if (transport_parsing->incoming_stream_id) {
+    transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
+        transport_parsing, transport_parsing->incoming_stream_id);
+  }
+  transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->simple.window_update;
+  return ok;
+}
+
+static int init_ping_parser(grpc_chttp2_transport_parsing *transport_parsing) {
+  int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame(
+                                       &transport_parsing->simple.ping,
+                                       transport_parsing->incoming_frame_size,
+                                       transport_parsing->incoming_frame_flags);
+  transport_parsing->parser = grpc_chttp2_ping_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->simple.ping;
+  return ok;
+}
+
+static int init_rst_stream_parser(
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame(
+                                       &transport_parsing->simple.rst_stream,
+                                       transport_parsing->incoming_frame_size,
+                                       transport_parsing->incoming_frame_flags);
+  transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
+      transport_parsing, transport_parsing->incoming_stream_id);
+  if (!transport_parsing->incoming_stream) {
+    return init_skip_frame_parser(transport_parsing, 0);
+  }
+  transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
+  return ok;
+}
+
+static int init_goaway_parser(
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame(
+                                       &transport_parsing->goaway_parser,
+                                       transport_parsing->incoming_frame_size,
+                                       transport_parsing->incoming_frame_flags);
+  transport_parsing->parser = grpc_chttp2_goaway_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->goaway_parser;
+  return ok;
+}
+
+static int init_settings_frame_parser(
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  int ok;
+
+  if (transport_parsing->incoming_stream_id != 0) {
+    gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d",
+            transport_parsing->incoming_stream_id);
+    return 0;
+  }
+
+  ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame(
+                                   &transport_parsing->simple.settings,
+                                   transport_parsing->incoming_frame_size,
+                                   transport_parsing->incoming_frame_flags,
+                                   transport_parsing->settings);
+  if (!ok) {
+    return 0;
+  }
+  if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
+    transport_parsing->settings_ack_received = 1;
+  }
+  transport_parsing->parser = grpc_chttp2_settings_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->simple.settings;
+  return ok;
+}
+
+/*
+static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
+  return window + window_update < MAX_WINDOW;
+}
+*/
+
+static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
+                             gpr_slice slice, int is_last) {
+  grpc_chttp2_stream_parsing *stream_parsing =
+      transport_parsing->incoming_stream;
+  switch (transport_parsing->parser(transport_parsing->parser_data,
+                                    transport_parsing, stream_parsing, slice,
+                                    is_last)) {
+    case GRPC_CHTTP2_PARSE_OK:
+      if (stream_parsing) {
+        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                                 stream_parsing);
+      }
+      return 1;
+    case GRPC_CHTTP2_STREAM_ERROR:
+      grpc_chttp2_parsing_become_skip_parser(transport_parsing);
+      if (stream_parsing) {
+        stream_parsing->saw_rst_stream = 1;
+        stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
+        gpr_slice_buffer_add(
+            &transport_parsing->qbuf,
+            grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
+                                          GRPC_CHTTP2_PROTOCOL_ERROR));
+      }
+      return 1;
+    case GRPC_CHTTP2_CONNECTION_ERROR:
+      return 0;
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+  return 0;
+}
diff --git a/src/core/transport/chttp2/status_conversion.h b/src/core/transport/chttp2/status_conversion.h
index cf06c35..0ec5b56 100644
--- a/src/core/transport/chttp2/status_conversion.h
+++ b/src/core/transport/chttp2/status_conversion.h
@@ -47,4 +47,4 @@
 grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status);
 int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H */
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index cf78ac5..d30059a 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -247,19 +247,19 @@
   } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) {
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) {
-    c->entries_keys[HASH_FRAGMENT_2(key_hash)] = grpc_mdstr_ref(elem->key);
+    c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
     c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
   } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) {
-    c->entries_keys[HASH_FRAGMENT_3(key_hash)] = grpc_mdstr_ref(elem->key);
+    c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
              c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
-    grpc_mdstr_unref(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
-    c->entries_keys[HASH_FRAGMENT_2(key_hash)] = grpc_mdstr_ref(elem->key);
+    GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
+    c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
     c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
   } else {
-    grpc_mdstr_unref(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
-    c->entries_keys[HASH_FRAGMENT_3(key_hash)] = grpc_mdstr_ref(elem->key);
+    GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
+    c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   }
 
@@ -437,12 +437,13 @@
                          framer_state *st) {
   char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
   grpc_mdelem *mdelem;
-  grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
+  grpc_chttp2_encode_timeout(
+      gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME)), timeout_str);
   mdelem = grpc_mdelem_from_metadata_strings(
-      c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
+      c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str),
       grpc_mdstr_from_string(c->mdctx, timeout_str));
   mdelem = hpack_enc(c, mdelem, st);
-  if (mdelem) grpc_mdelem_unref(mdelem);
+  if (mdelem) GRPC_MDELEM_UNREF(mdelem);
 }
 
 gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
@@ -461,10 +462,10 @@
 void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
   int i;
   for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
-    if (c->entries_keys[i]) grpc_mdstr_unref(c->entries_keys[i]);
-    if (c->entries_elems[i]) grpc_mdelem_unref(c->entries_elems[i]);
+    if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]);
+    if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]);
   }
-  grpc_mdstr_unref(c->timeout_key_str);
+  GRPC_MDSTR_UNREF(c->timeout_key_str);
 }
 
 gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
@@ -476,6 +477,7 @@
   gpr_uint32 flow_controlled_bytes_taken = 0;
   gpr_uint32 curop = 0;
   gpr_uint8 *p;
+  int compressed_flag_set = 0;
 
   while (curop < *inops_count) {
     GPR_ASSERT(flow_controlled_bytes_taken <= max_flow_controlled_bytes);
@@ -495,9 +497,12 @@
       case GRPC_OP_BEGIN_MESSAGE:
         /* begin op: for now we just convert the op to a slice and fall
            through - this lets us reuse the slice framing code below */
+        compressed_flag_set =
+            (op->data.begin_message.flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
         slice = gpr_slice_malloc(5);
+
         p = GPR_SLICE_START_PTR(slice);
-        p[0] = 0;
+        p[0] = compressed_flag_set;
         p[1] = op->data.begin_message.length >> 24;
         p[2] = op->data.begin_message.length >> 16;
         p[3] = op->data.begin_message.length >> 8;
@@ -584,7 +589,8 @@
           l->md = hpack_enc(compressor, l->md, &st);
           need_unref |= l->md != NULL;
         }
-        if (gpr_time_cmp(op->data.metadata.deadline, gpr_inf_future) != 0) {
+        if (gpr_time_cmp(op->data.metadata.deadline,
+                         gpr_inf_future(GPR_CLOCK_REALTIME)) != 0) {
           deadline_enc(compressor, op->data.metadata.deadline, &st);
         }
         curop++;
@@ -620,10 +626,10 @@
       op = &ops[unref_op];
       if (op->type != GRPC_OP_METADATA) continue;
       for (l = op->data.metadata.list.head; l; l = l->next) {
-        if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+        if (l->md) GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md);
       }
       for (l = op->data.metadata.garbage.head; l; l = l->next) {
-        grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+        GRPC_MDCTX_LOCKED_MDELEM_UNREF(mdctx, l->md);
       }
     }
     grpc_mdctx_unlock(mdctx);
diff --git a/src/core/transport/chttp2/stream_encoder.h b/src/core/transport/chttp2/stream_encoder.h
index 50c58ad..db52f2a 100644
--- a/src/core/transport/chttp2/stream_encoder.h
+++ b/src/core/transport/chttp2/stream_encoder.h
@@ -90,4 +90,4 @@
                         grpc_chttp2_hpack_compressor *compressor,
                         gpr_slice_buffer *output);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_ENCODER_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_ENCODER_H */
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
new file mode 100644
index 0000000..590f6ab
--- /dev/null
+++ b/src/core/transport/chttp2/stream_lists.c
@@ -0,0 +1,382 @@
+/*
+ *
+ * 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/transport/chttp2/internal.h"
+
+#include <grpc/support/log.h>
+
+#define TRANSPORT_FROM_GLOBAL(tg)                                         \
+  ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \
+                                                   global)))
+
+#define STREAM_FROM_GLOBAL(sg) \
+  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
+
+#define TRANSPORT_FROM_WRITING(tw)                                        \
+  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
+                                                   writing)))
+
+#define STREAM_FROM_WRITING(sw) \
+  ((grpc_chttp2_stream *)((char *)(sw)-offsetof(grpc_chttp2_stream, writing)))
+
+#define TRANSPORT_FROM_PARSING(tp)                                        \
+  ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
+                                                   parsing)))
+
+#define STREAM_FROM_PARSING(sp) \
+  ((grpc_chttp2_stream *)((char *)(sp)-offsetof(grpc_chttp2_stream, parsing)))
+
+/* core list management */
+
+static int stream_list_empty(grpc_chttp2_transport *t,
+                             grpc_chttp2_stream_list_id id) {
+  return t->lists[id].head == NULL;
+}
+
+static int stream_list_pop(grpc_chttp2_transport *t,
+                           grpc_chttp2_stream **stream,
+                           grpc_chttp2_stream_list_id id) {
+  grpc_chttp2_stream *s = t->lists[id].head;
+  if (s) {
+    grpc_chttp2_stream *new_head = s->links[id].next;
+    GPR_ASSERT(s->included[id]);
+    if (new_head) {
+      t->lists[id].head = new_head;
+      new_head->links[id].prev = NULL;
+    } else {
+      t->lists[id].head = NULL;
+      t->lists[id].tail = NULL;
+    }
+    s->included[id] = 0;
+  }
+  *stream = s;
+  return s != 0;
+}
+
+static void stream_list_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                               grpc_chttp2_stream_list_id id) {
+  GPR_ASSERT(s->included[id]);
+  s->included[id] = 0;
+  if (s->links[id].prev) {
+    s->links[id].prev->links[id].next = s->links[id].next;
+  } else {
+    GPR_ASSERT(t->lists[id].head == s);
+    t->lists[id].head = s->links[id].next;
+  }
+  if (s->links[id].next) {
+    s->links[id].next->links[id].prev = s->links[id].prev;
+  } else {
+    t->lists[id].tail = s->links[id].prev;
+  }
+}
+
+static void stream_list_maybe_remove(grpc_chttp2_transport *t,
+                                     grpc_chttp2_stream *s,
+                                     grpc_chttp2_stream_list_id id) {
+  if (s->included[id]) {
+    stream_list_remove(t, s, id);
+  }
+}
+
+static void stream_list_add_tail(grpc_chttp2_transport *t,
+                                 grpc_chttp2_stream *s,
+                                 grpc_chttp2_stream_list_id id) {
+  grpc_chttp2_stream *old_tail;
+  GPR_ASSERT(!s->included[id]);
+  old_tail = t->lists[id].tail;
+  s->links[id].next = NULL;
+  s->links[id].prev = old_tail;
+  if (old_tail) {
+    old_tail->links[id].next = s;
+  } else {
+    s->links[id].prev = NULL;
+    t->lists[id].head = s;
+  }
+  t->lists[id].tail = s;
+  s->included[id] = 1;
+}
+
+static void stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                            grpc_chttp2_stream_list_id id) {
+  if (s->included[id]) {
+    return;
+  }
+  stream_list_add_tail(t, s, id);
+}
+
+/* wrappers for specializations */
+
+void grpc_chttp2_list_add_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  GPR_ASSERT(stream_global->id != 0);
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE);
+}
+
+int grpc_chttp2_list_pop_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_writing **stream_writing) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_WRITABLE);
+  *stream_global = &stream->global;
+  *stream_writing = &stream->writing;
+  return r;
+}
+
+void grpc_chttp2_list_add_writing_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing) {
+  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
+                  STREAM_FROM_WRITING(stream_writing),
+                  GRPC_CHTTP2_LIST_WRITING);
+}
+
+int grpc_chttp2_list_have_writing_streams(
+    grpc_chttp2_transport_writing *transport_writing) {
+  return !stream_list_empty(TRANSPORT_FROM_WRITING(transport_writing),
+                            GRPC_CHTTP2_LIST_WRITING);
+}
+
+int grpc_chttp2_list_pop_writing_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing **stream_writing) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream,
+                          GRPC_CHTTP2_LIST_WRITING);
+  *stream_writing = &stream->writing;
+  return r;
+}
+
+void grpc_chttp2_list_add_written_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing) {
+  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
+                  STREAM_FROM_WRITING(stream_writing),
+                  GRPC_CHTTP2_LIST_WRITTEN);
+}
+
+int grpc_chttp2_list_pop_written_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_writing **stream_writing) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream,
+                          GRPC_CHTTP2_LIST_WRITTEN);
+  *stream_global = &stream->global;
+  *stream_writing = &stream->writing;
+  return r;
+}
+
+void grpc_chttp2_list_add_writable_window_update_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  GPR_ASSERT(stream_global->id != 0);
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global),
+                  GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE);
+}
+
+int grpc_chttp2_list_pop_writable_window_update_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_writing **stream_writing) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE);
+  *stream_global = &stream->global;
+  *stream_writing = &stream->writing;
+  return r;
+}
+
+void grpc_chttp2_list_remove_writable_window_update_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
+                           STREAM_FROM_GLOBAL(stream_global),
+                           GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE);
+}
+
+void grpc_chttp2_list_add_parsing_seen_stream(
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing) {
+  stream_list_add(TRANSPORT_FROM_PARSING(transport_parsing),
+                  STREAM_FROM_PARSING(stream_parsing),
+                  GRPC_CHTTP2_LIST_PARSING_SEEN);
+}
+
+int grpc_chttp2_list_pop_parsing_seen_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_parsing **stream_parsing) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream,
+                          GRPC_CHTTP2_LIST_PARSING_SEEN);
+  *stream_global = &stream->global;
+  *stream_parsing = &stream->parsing;
+  return r;
+}
+
+void grpc_chttp2_list_add_waiting_for_concurrency(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global),
+                  GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
+}
+
+int grpc_chttp2_list_pop_waiting_for_concurrency(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
+  *stream_global = &stream->global;
+  return r;
+}
+
+void grpc_chttp2_list_add_closed_waiting_for_parsing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global),
+                  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING);
+}
+
+int grpc_chttp2_list_pop_closed_waiting_for_parsing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING);
+  *stream_global = &stream->global;
+  return r;
+}
+
+void grpc_chttp2_list_add_cancelled_waiting_for_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global),
+                  GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING);
+}
+
+int grpc_chttp2_list_pop_cancelled_waiting_for_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING);
+  *stream_global = &stream->global;
+  return r;
+}
+
+void grpc_chttp2_list_add_incoming_window_updated(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global),
+                  GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED);
+}
+
+int grpc_chttp2_list_pop_incoming_window_updated(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_global **stream_global,
+    grpc_chttp2_stream_parsing **stream_parsing) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED);
+  *stream_global = &stream->global;
+  *stream_parsing = &stream->parsing;
+  return r;
+}
+
+void grpc_chttp2_list_remove_incoming_window_updated(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
+                           STREAM_FROM_GLOBAL(stream_global),
+                           GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED);
+}
+
+void grpc_chttp2_list_add_read_write_state_changed(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+                  STREAM_FROM_GLOBAL(stream_global),
+                  GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED);
+}
+
+int grpc_chttp2_list_pop_read_write_state_changed(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global) {
+  grpc_chttp2_stream *stream;
+  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+                          GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED);
+  *stream_global = &stream->global;
+  return r;
+}
+
+void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
+                                 grpc_chttp2_stream *s) {
+  stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS);
+}
+
+int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t,
+                                   grpc_chttp2_stream *s) {
+  stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS);
+  return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS);
+}
+
+int grpc_chttp2_has_streams(grpc_chttp2_transport *t) {
+  return !stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS);
+}
+
+void grpc_chttp2_for_all_streams(
+    grpc_chttp2_transport_global *transport_global, void *user_data,
+    void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data,
+               grpc_chttp2_stream_global *stream_global)) {
+  grpc_chttp2_stream *s;
+  grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global);
+  for (s = t->lists[GRPC_CHTTP2_LIST_ALL_STREAMS].head; s != NULL;
+       s = s->links[GRPC_CHTTP2_LIST_ALL_STREAMS].next) {
+    cb(transport_global, user_data, &s->global);
+  }
+}
diff --git a/src/core/transport/chttp2/stream_map.c b/src/core/transport/chttp2/stream_map.c
index 580e32c..0ec2f27 100644
--- a/src/core/transport/chttp2/stream_map.c
+++ b/src/core/transport/chttp2/stream_map.c
@@ -32,8 +32,12 @@
  */
 
 #include "src/core/transport/chttp2/stream_map.h"
+
+#include <string.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 
 void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map,
                                  size_t initial_capacity) {
@@ -92,6 +96,41 @@
   map->count = count + 1;
 }
 
+void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src,
+                                      grpc_chttp2_stream_map *dst) {
+  /* if src is empty we dont need to do anything */
+  if (src->count == src->free) {
+    return;
+  }
+  /* if dst is empty we simply need to swap */
+  if (dst->count == dst->free) {
+    GPR_SWAP(grpc_chttp2_stream_map, *src, *dst);
+    return;
+  }
+  /* the first element of src must be greater than the last of dst...
+   * however the maps may need compacting for this property to hold */
+  if (src->keys[0] <= dst->keys[dst->count - 1]) {
+    src->count = compact(src->keys, src->values, src->count);
+    src->free = 0;
+    dst->count = compact(dst->keys, dst->values, dst->count);
+    dst->free = 0;
+  }
+  GPR_ASSERT(src->keys[0] > dst->keys[dst->count - 1]);
+  /* if dst doesn't have capacity, resize */
+  if (dst->count + src->count > dst->capacity) {
+    dst->capacity = GPR_MAX(dst->capacity * 3 / 2, dst->count + src->count);
+    dst->keys = gpr_realloc(dst->keys, dst->capacity * sizeof(gpr_uint32));
+    dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *));
+  }
+  memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(gpr_uint32));
+  memcpy(dst->values + dst->count, src->values,
+         src->count * sizeof(void*));
+  dst->count += src->count;
+  dst->free += src->free;
+  src->count = 0;
+  src->free = 0;
+}
+
 static void **find(grpc_chttp2_stream_map *map, gpr_uint32 key) {
   size_t min_idx = 0;
   size_t max_idx = map->count;
@@ -127,6 +166,11 @@
     out = *pvalue;
     *pvalue = NULL;
     map->free += (out != NULL);
+    /* recognize complete emptyness and ensure we can skip
+     * defragmentation later */
+    if (map->free == map->count) {
+      map->free = map->count = 0;
+    }
   }
   return out;
 }
diff --git a/src/core/transport/chttp2/stream_map.h b/src/core/transport/chttp2/stream_map.h
index d338d2f..71b0582 100644
--- a/src/core/transport/chttp2/stream_map.h
+++ b/src/core/transport/chttp2/stream_map.h
@@ -66,6 +66,10 @@
 void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map,
                                     gpr_uint32 key);
 
+/* Move all elements of src into dst */
+void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src,
+                                      grpc_chttp2_stream_map *dst);
+
 /* Return an existing key, or NULL if it does not exist */
 void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, gpr_uint32 key);
 
@@ -78,4 +82,4 @@
                                                void *value),
                                      void *user_data);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H */
diff --git a/src/core/transport/chttp2/timeout_encoding.c b/src/core/transport/chttp2/timeout_encoding.c
index 33915c4..1dd768a 100644
--- a/src/core/transport/chttp2/timeout_encoding.c
+++ b/src/core/transport/chttp2/timeout_encoding.c
@@ -147,7 +147,7 @@
     gpr_uint32 xp = x * 10 + *p - '0';
     have_digit = 1;
     if (xp < x) {
-      *timeout = gpr_inf_future;
+      *timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
       return 1;
     }
     x = xp;
@@ -159,22 +159,22 @@
   /* decode unit specifier */
   switch (*p) {
     case 'n':
-      *timeout = gpr_time_from_nanos(x);
+      *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
       break;
     case 'u':
-      *timeout = gpr_time_from_micros(x);
+      *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
       break;
     case 'm':
-      *timeout = gpr_time_from_millis(x);
+      *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
       break;
     case 'S':
-      *timeout = gpr_time_from_seconds(x);
+      *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
       break;
     case 'M':
-      *timeout = gpr_time_from_minutes(x);
+      *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
       break;
     case 'H':
-      *timeout = gpr_time_from_hours(x);
+      *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
       break;
     default:
       return 0;
diff --git a/src/core/transport/chttp2/timeout_encoding.h b/src/core/transport/chttp2/timeout_encoding.h
index e6664c6..9d8756e 100644
--- a/src/core/transport/chttp2/timeout_encoding.h
+++ b/src/core/transport/chttp2/timeout_encoding.h
@@ -44,4 +44,4 @@
 void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
 int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H */
diff --git a/src/core/transport/chttp2/varint.h b/src/core/transport/chttp2/varint.h
index ee04ed7..0a6fb55 100644
--- a/src/core/transport/chttp2/varint.h
+++ b/src/core/transport/chttp2/varint.h
@@ -56,19 +56,18 @@
   ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)   \
        ? 1                                        \
        : grpc_chttp2_hpack_varint_length(         \
-             (n) - GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)))
+             (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)))
 
-#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length) \
-  do {                                                                      \
-    gpr_uint8* tgt = target;                                                \
-    if ((length) == 1) {                                                    \
-      (tgt)[0] = (prefix_or) | (n);                                         \
-    } else {                                                                \
-      (tgt)[0] = (prefix_or) | GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits);      \
-      grpc_chttp2_hpack_write_varint_tail(                                  \
-          (n) - GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1,          \
-          (length) - 1);                                                    \
-    }                                                                       \
+#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length)   \
+  do {                                                                        \
+    gpr_uint8* tgt = target;                                                  \
+    if ((length) == 1) {                                                      \
+      (tgt)[0] = (prefix_or) | (n);                                           \
+    } else {                                                                  \
+      (tgt)[0] = (prefix_or) | GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits);        \
+      grpc_chttp2_hpack_write_varint_tail(                                    \
+          (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1, (length)-1); \
+    }                                                                         \
   } while (0)
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_VARINT_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_VARINT_H */
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
new file mode 100644
index 0000000..d8ec117
--- /dev/null
+++ b/src/core/transport/chttp2/writing.c
@@ -0,0 +1,225 @@
+/*
+ *
+ * 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/transport/chttp2/internal.h"
+#include "src/core/transport/chttp2/http2_errors.h"
+
+#include <grpc/support/log.h>
+
+static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing);
+static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status);
+
+int grpc_chttp2_unlocking_check_writes(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing) {
+  grpc_chttp2_stream_global *stream_global;
+  grpc_chttp2_stream_writing *stream_writing;
+  gpr_uint32 window_delta;
+
+  /* simple writes are queued to qbuf, and flushed here */
+  gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
+  GPR_ASSERT(transport_global->qbuf.count == 0);
+
+  if (transport_global->dirtied_local_settings &&
+      !transport_global->sent_local_settings) {
+    gpr_slice_buffer_add(
+        &transport_writing->outbuf,
+        grpc_chttp2_settings_create(
+            transport_global->settings[GRPC_SENT_SETTINGS],
+            transport_global->settings[GRPC_LOCAL_SETTINGS],
+            transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
+    transport_global->force_send_settings = 0;
+    transport_global->dirtied_local_settings = 0;
+    transport_global->sent_local_settings = 1;
+  }
+
+  /* for each grpc_chttp2_stream that's become writable, frame it's data
+     (according to
+     available window sizes) and add to the output buffer */
+  while (grpc_chttp2_list_pop_writable_stream(transport_global,
+                                              transport_writing, &stream_global,
+                                              &stream_writing)) {
+    stream_writing->id = stream_global->id;
+    window_delta = grpc_chttp2_preencode(
+        stream_global->outgoing_sopb->ops, &stream_global->outgoing_sopb->nops,
+        GPR_MIN(transport_global->outgoing_window,
+                stream_global->outgoing_window),
+        &stream_writing->sopb);
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
+        "write", transport_global, outgoing_window, -(gpr_int64)window_delta);
+    GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
+                                     outgoing_window, -(gpr_int64)window_delta);
+    transport_global->outgoing_window -= window_delta;
+    stream_global->outgoing_window -= window_delta;
+
+    if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE &&
+        stream_global->outgoing_sopb->nops == 0) {
+      if (!transport_global->is_client && !stream_global->read_closed) {
+        stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM;
+      } else {
+        stream_writing->send_closed = GRPC_SEND_CLOSED;
+      }
+    }
+    if (stream_writing->sopb.nops > 0 ||
+        stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
+      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
+    }
+
+    if (stream_global->outgoing_window > 0 &&
+        stream_global->outgoing_sopb->nops != 0) {
+      grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
+    }
+  }
+
+  /* for each grpc_chttp2_stream that wants to update its window, add that
+   * window here */
+  while (grpc_chttp2_list_pop_writable_window_update_stream(transport_global,
+                                                            transport_writing,
+                                                            &stream_global,
+                                                            &stream_writing)) {
+    stream_writing->id = stream_global->id;
+    if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) {
+      stream_writing->announce_window = stream_global->unannounced_incoming_window;
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
+                                       incoming_window, stream_global->unannounced_incoming_window);
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
+                                       unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window);
+      stream_global->incoming_window += stream_global->unannounced_incoming_window;
+      stream_global->unannounced_incoming_window = 0;
+      grpc_chttp2_list_add_incoming_window_updated(transport_global,
+                                                   stream_global);
+      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
+    }
+  }
+
+  /* if the grpc_chttp2_transport is ready to send a window update, do so here
+     also; 3/4 is a magic number that will likely get tuned soon */
+  if (transport_global->incoming_window <
+      transport_global->connection_window_target * 3 / 4) {
+    window_delta = transport_global->connection_window_target -
+                   transport_global->incoming_window;
+    gpr_slice_buffer_add(&transport_writing->outbuf,
+                         grpc_chttp2_window_update_create(0, window_delta));
+    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global,
+                                        incoming_window, window_delta);
+    transport_global->incoming_window += window_delta;
+  }
+
+  return transport_writing->outbuf.count > 0 ||
+         grpc_chttp2_list_have_writing_streams(transport_writing);
+}
+
+void grpc_chttp2_perform_writes(
+    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint) {
+  GPR_ASSERT(transport_writing->outbuf.count > 0 ||
+             grpc_chttp2_list_have_writing_streams(transport_writing));
+
+  finalize_outbuf(transport_writing);
+
+  GPR_ASSERT(transport_writing->outbuf.count > 0);
+  GPR_ASSERT(endpoint);
+
+  switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices,
+                              transport_writing->outbuf.count, finish_write_cb,
+                              transport_writing)) {
+    case GRPC_ENDPOINT_WRITE_DONE:
+      grpc_chttp2_terminate_writing(transport_writing, 1);
+      break;
+    case GRPC_ENDPOINT_WRITE_ERROR:
+      grpc_chttp2_terminate_writing(transport_writing, 0);
+      break;
+    case GRPC_ENDPOINT_WRITE_PENDING:
+      break;
+  }
+}
+
+static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
+  grpc_chttp2_stream_writing *stream_writing;
+
+  while (
+      grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
+    if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
+      grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops,
+                         stream_writing->send_closed != GRPC_DONT_SEND_CLOSED,
+                         stream_writing->id, &transport_writing->hpack_compressor,
+                         &transport_writing->outbuf);
+    }
+    if (stream_writing->announce_window > 0) {
+      gpr_slice_buffer_add(
+          &transport_writing->outbuf,
+          grpc_chttp2_window_update_create(
+              stream_writing->id, stream_writing->announce_window));
+      stream_writing->announce_window = 0;
+    }
+    stream_writing->sopb.nops = 0;
+    if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) {
+      gpr_slice_buffer_add(&transport_writing->outbuf,
+                           grpc_chttp2_rst_stream_create(stream_writing->id,
+                                                         GRPC_CHTTP2_NO_ERROR));
+    }
+    grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
+  }
+}
+
+static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status) {
+  grpc_chttp2_transport_writing *transport_writing = tw;
+  grpc_chttp2_terminate_writing(transport_writing,
+                                write_status == GRPC_ENDPOINT_CB_OK);
+}
+
+void grpc_chttp2_cleanup_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing) {
+  grpc_chttp2_stream_writing *stream_writing;
+  grpc_chttp2_stream_global *stream_global;
+
+  while (grpc_chttp2_list_pop_written_stream(
+      transport_global, transport_writing, &stream_global, &stream_writing)) {
+    if (stream_global->outgoing_sopb != NULL &&
+        stream_global->outgoing_sopb->nops == 0) {
+      stream_global->outgoing_sopb = NULL;
+      grpc_chttp2_schedule_closure(transport_global,
+                                   stream_global->send_done_closure, 1);
+    }
+    if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
+      stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
+      if (!transport_global->is_client) {
+        stream_global->read_closed = 1;
+      }
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+    }
+  }
+  transport_writing->outbuf.count = 0;
+  transport_writing->outbuf.length = 0;
+}
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index bd259f7..c923d5e 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -37,447 +37,177 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/frame_data.h"
-#include "src/core/transport/chttp2/frame_goaway.h"
-#include "src/core/transport/chttp2/frame_ping.h"
-#include "src/core/transport/chttp2/frame_rst_stream.h"
-#include "src/core/transport/chttp2/frame_settings.h"
-#include "src/core/transport/chttp2/frame_window_update.h"
-#include "src/core/transport/chttp2/hpack_parser.h"
-#include "src/core/transport/chttp2/http2_errors.h"
-#include "src/core/transport/chttp2/status_conversion.h"
-#include "src/core/transport/chttp2/stream_encoder.h"
-#include "src/core/transport/chttp2/stream_map.h"
-#include "src/core/transport/chttp2/timeout_encoding.h"
-#include "src/core/transport/transport_impl.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/profiling/timers.h"
+#include "src/core/support/string.h"
+#include "src/core/transport/chttp2/http2_errors.h"
+#include "src/core/transport/chttp2/internal.h"
+#include "src/core/transport/chttp2/status_conversion.h"
+#include "src/core/transport/chttp2/timeout_encoding.h"
+#include "src/core/transport/transport_impl.h"
+
 #define DEFAULT_WINDOW 65535
 #define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
 #define MAX_WINDOW 0x7fffffffu
 
 #define MAX_CLIENT_STREAM_ID 0x7fffffffu
 
-#define CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
-#define CLIENT_CONNECT_STRLEN 24
-
 int grpc_http_trace = 0;
 int grpc_flowctl_trace = 0;
 
-typedef struct transport transport;
-typedef struct stream stream;
+#define TRANSPORT_FROM_WRITING(tw)                                        \
+  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
+                                                   writing)))
 
-#define IF_TRACING(stmt)  \
-  if (!(grpc_http_trace)) \
-    ;                     \
-  else                    \
-  stmt
+#define TRANSPORT_FROM_PARSING(tw)                                        \
+  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
+                                                   parsing)))
 
-#define FLOWCTL_TRACE(t, obj, dir, id, delta) \
-  if (!grpc_flowctl_trace)                    \
-    ;                                         \
-  else                                        \
-  flowctl_trace(t, #dir, obj->dir##_window, id, delta)
+#define TRANSPORT_FROM_GLOBAL(tg)                                         \
+  ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \
+                                                   global)))
 
-/* streams are kept in various linked lists depending on what things need to
-   happen to them... this enum labels each list */
-typedef enum {
-  /* streams that have pending writes */
-  WRITABLE = 0,
-  /* streams that have been selected to be written */
-  WRITING,
-  /* streams that have just been written, and included a close */
-  WRITTEN_CLOSED,
-  /* streams that have been cancelled and have some pending state updates
-     to perform */
-  CANCELLED,
-  /* streams that want to send window updates */
-  WINDOW_UPDATE,
-  /* streams that are waiting to start because there are too many concurrent
-     streams on the connection */
-  WAITING_FOR_CONCURRENCY,
-  /* streams that have finished reading: we wait until unlock to coalesce
-     all changes into one callback */
-  FINISHED_READ_OP,
-  STREAM_LIST_COUNT /* must be last */
-} stream_list_id;
-
-/* deframer state for the overall http2 stream of bytes */
-typedef enum {
-  /* prefix: one entry per http2 connection prefix byte */
-  DTS_CLIENT_PREFIX_0 = 0,
-  DTS_CLIENT_PREFIX_1,
-  DTS_CLIENT_PREFIX_2,
-  DTS_CLIENT_PREFIX_3,
-  DTS_CLIENT_PREFIX_4,
-  DTS_CLIENT_PREFIX_5,
-  DTS_CLIENT_PREFIX_6,
-  DTS_CLIENT_PREFIX_7,
-  DTS_CLIENT_PREFIX_8,
-  DTS_CLIENT_PREFIX_9,
-  DTS_CLIENT_PREFIX_10,
-  DTS_CLIENT_PREFIX_11,
-  DTS_CLIENT_PREFIX_12,
-  DTS_CLIENT_PREFIX_13,
-  DTS_CLIENT_PREFIX_14,
-  DTS_CLIENT_PREFIX_15,
-  DTS_CLIENT_PREFIX_16,
-  DTS_CLIENT_PREFIX_17,
-  DTS_CLIENT_PREFIX_18,
-  DTS_CLIENT_PREFIX_19,
-  DTS_CLIENT_PREFIX_20,
-  DTS_CLIENT_PREFIX_21,
-  DTS_CLIENT_PREFIX_22,
-  DTS_CLIENT_PREFIX_23,
-  /* frame header byte 0... */
-  /* must follow from the prefix states */
-  DTS_FH_0,
-  DTS_FH_1,
-  DTS_FH_2,
-  DTS_FH_3,
-  DTS_FH_4,
-  DTS_FH_5,
-  DTS_FH_6,
-  DTS_FH_7,
-  /* ... frame header byte 8 */
-  DTS_FH_8,
-  /* inside a http2 frame */
-  DTS_FRAME
-} deframe_transport_state;
-
-typedef enum {
-  WRITE_STATE_OPEN,
-  WRITE_STATE_QUEUED_CLOSE,
-  WRITE_STATE_SENT_CLOSE
-} write_state;
-
-typedef enum {
-  DONT_SEND_CLOSED = 0,
-  SEND_CLOSED,
-  SEND_CLOSED_WITH_RST_STREAM
-} send_closed;
-
-typedef struct {
-  stream *head;
-  stream *tail;
-} stream_list;
-
-typedef struct {
-  stream *next;
-  stream *prev;
-} stream_link;
-
-typedef enum {
-  ERROR_STATE_NONE,
-  ERROR_STATE_SEEN,
-  ERROR_STATE_NOTIFIED
-} error_state;
-
-/* We keep several sets of connection wide parameters */
-typedef enum {
-  /* The settings our peer has asked for (and we have acked) */
-  PEER_SETTINGS = 0,
-  /* The settings we'd like to have */
-  LOCAL_SETTINGS,
-  /* The settings we've published to our peer */
-  SENT_SETTINGS,
-  /* The settings the peer has acked */
-  ACKED_SETTINGS,
-  NUM_SETTING_SETS
-} setting_set;
-
-/* Outstanding ping request data */
-typedef struct {
-  gpr_uint8 id[8];
-  void (*cb)(void *user_data);
-  void *user_data;
-} outstanding_ping;
-
-typedef struct {
-  grpc_status_code status;
-  gpr_slice debug;
-} pending_goaway;
-
-typedef struct {
-  void (*cb)(void *user_data, int success);
-  void *user_data;
-  int success;
-} op_closure;
-
-typedef struct {
-  op_closure *callbacks;
-  size_t count;
-  size_t capacity;
-} op_closure_array;
-
-struct transport {
-  grpc_transport base; /* must be first */
-  const grpc_transport_callbacks *cb;
-  void *cb_user_data;
-  grpc_endpoint *ep;
-  grpc_mdctx *metadata_context;
-  gpr_refcount refs;
-  gpr_uint8 is_client;
-
-  gpr_mu mu;
-  gpr_cv cv;
-
-  /* basic state management - what are we doing at the moment? */
-  gpr_uint8 reading;
-  gpr_uint8 writing;
-  /** are we calling back (via cb) with a channel-level event */
-  gpr_uint8 calling_back_channel;
-  /** are we calling back any grpc_transport_op completion events */
-  gpr_uint8 calling_back_ops;
-  gpr_uint8 destroying;
-  gpr_uint8 closed;
-  error_state error_state;
-
-  /* queued callbacks */
-  op_closure_array pending_callbacks;
-  op_closure_array executing_callbacks;
-
-  /* stream indexing */
-  gpr_uint32 next_stream_id;
-  gpr_uint32 last_incoming_stream_id;
-
-  /* settings */
-  gpr_uint32 settings[NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS];
-  gpr_uint32 force_send_settings;   /* bitmask of setting indexes to send out */
-  gpr_uint8 sent_local_settings;    /* have local settings been sent? */
-  gpr_uint8 dirtied_local_settings; /* are the local settings dirty? */
-
-  /* window management */
-  gpr_uint32 outgoing_window;
-  gpr_uint32 incoming_window;
-  gpr_uint32 connection_window_target;
-
-  /* deframing */
-  deframe_transport_state deframe_state;
-  gpr_uint8 incoming_frame_type;
-  gpr_uint8 incoming_frame_flags;
-  gpr_uint8 header_eof;
-  gpr_uint32 expect_continuation_stream_id;
-  gpr_uint32 incoming_frame_size;
-  gpr_uint32 incoming_stream_id;
-
-  /* hpack encoding */
-  grpc_chttp2_hpack_compressor hpack_compressor;
-
-  /* various parsers */
-  grpc_chttp2_hpack_parser hpack_parser;
-  /* simple one shot parsers */
-  union {
-    grpc_chttp2_window_update_parser window_update;
-    grpc_chttp2_settings_parser settings;
-    grpc_chttp2_ping_parser ping;
-    grpc_chttp2_rst_stream_parser rst_stream;
-  } simple_parsers;
-
-  /* goaway */
-  grpc_chttp2_goaway_parser goaway_parser;
-  pending_goaway *pending_goaways;
-  size_t num_pending_goaways;
-  size_t cap_pending_goaways;
-
-  /* state for a stream that's not yet been created */
-  grpc_stream_op_buffer new_stream_sopb;
-
-  /* stream ops that need to be destroyed, but outside of the lock */
-  grpc_stream_op_buffer nuke_later_sopb;
-
-  /* active parser */
-  void *parser_data;
-  stream *incoming_stream;
-  grpc_chttp2_parse_error (*parser)(void *parser_user_data,
-                                    grpc_chttp2_parse_state *state,
-                                    gpr_slice slice, int is_last);
-
-  gpr_slice_buffer outbuf;
-  gpr_slice_buffer qbuf;
-
-  stream_list lists[STREAM_LIST_COUNT];
-  grpc_chttp2_stream_map stream_map;
-
-  /* metadata object cache */
-  grpc_mdstr *str_grpc_timeout;
-
-  /* pings */
-  outstanding_ping *pings;
-  size_t ping_count;
-  size_t ping_capacity;
-  gpr_int64 ping_counter;
-};
-
-struct stream {
-  gpr_uint32 id;
-
-  gpr_uint32 incoming_window;
-  gpr_int64 outgoing_window;
-  /* when the application requests writes be closed, the write_closed is
-     'queued'; when the close is flow controlled into the send path, we are
-     'sending' it; when the write has been performed it is 'sent' */
-  write_state write_state;
-  send_closed send_closed;
-  gpr_uint8 read_closed;
-  gpr_uint8 cancelled;
-
-  op_closure send_done_closure;
-  op_closure recv_done_closure;
-
-  stream_link links[STREAM_LIST_COUNT];
-  gpr_uint8 included[STREAM_LIST_COUNT];
-
-  /* incoming metadata */
-  grpc_linked_mdelem *incoming_metadata;
-  size_t incoming_metadata_count;
-  size_t incoming_metadata_capacity;
-  grpc_linked_mdelem *old_incoming_metadata;
-  gpr_timespec incoming_deadline;
-
-  /* sops from application */
-  grpc_stream_op_buffer *outgoing_sopb;
-  grpc_stream_op_buffer *incoming_sopb;
-  grpc_stream_state *publish_state;
-  grpc_stream_state published_state;
-  /* sops that have passed flow control to be written */
-  grpc_stream_op_buffer writing_sopb;
-
-  grpc_chttp2_data_parser parser;
-
-  grpc_stream_state callback_state;
-  grpc_stream_op_buffer callback_sopb;
-};
+#define STREAM_FROM_GLOBAL(sg) \
+  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
 
 static const grpc_transport_vtable vtable;
 
-static void push_setting(transport *t, grpc_chttp2_setting_id id,
+static void lock(grpc_chttp2_transport *t);
+static void unlock(grpc_chttp2_transport *t);
+
+static void unlock_check_read_write_state(grpc_chttp2_transport *t);
+
+/* forward declarations of various callbacks that we'll build closures around */
+static void writing_action(void *t, int iomgr_success_ignored);
+static void reading_action(void *t, int iomgr_success_ignored);
+
+/** Set a transport level setting, and push it to our peer */
+static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
                          gpr_uint32 value);
 
-static int prepare_callbacks(transport *t);
-static void run_callbacks(transport *t);
-static void call_cb_closed(transport *t, const grpc_transport_callbacks *cb);
-
-static int prepare_write(transport *t);
-static void perform_write(transport *t, grpc_endpoint *ep);
-
-static void lock(transport *t);
-static void unlock(transport *t);
-
-static void drop_connection(transport *t);
-static void end_all_the_calls(transport *t);
-
-static stream *stream_list_remove_head(transport *t, stream_list_id id);
-static void stream_list_remove(transport *t, stream *s, stream_list_id id);
-static void stream_list_add_tail(transport *t, stream *s, stream_list_id id);
-static void stream_list_join(transport *t, stream *s, stream_list_id id);
-
-static void cancel_stream_id(transport *t, gpr_uint32 id,
-                             grpc_status_code local_status,
-                             grpc_chttp2_error_code error_code, int send_rst);
-static void cancel_stream(transport *t, stream *s,
-                          grpc_status_code local_status,
-                          grpc_chttp2_error_code error_code,
-                          grpc_mdstr *optional_message, int send_rst);
-static void finalize_cancellations(transport *t);
-static stream *lookup_stream(transport *t, gpr_uint32 id);
-static void remove_from_stream_map(transport *t, stream *s);
-static void maybe_start_some_streams(transport *t);
-
-static void become_skip_parser(transport *t);
-
+/** Endpoint callback to process incoming data */
 static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
                       grpc_endpoint_cb_status error);
 
-static void schedule_cb(transport *t, op_closure closure, int success);
-static void maybe_finish_read(transport *t, stream *s);
-static void maybe_join_window_updates(transport *t, stream *s);
-static void finish_reads(transport *t);
-static void add_to_pollset_locked(transport *t, grpc_pollset *pollset);
-static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op);
-static void add_metadata_batch(transport *t, stream *s);
+/** Start disconnection chain */
+static void drop_connection(grpc_chttp2_transport *t);
 
-static void flowctl_trace(transport *t, const char *flow, gpr_int32 window,
-                          gpr_uint32 id, gpr_int32 delta) {
-  gpr_log(GPR_DEBUG, "HTTP:FLOW:%p:%d:%s: %d + %d = %d", t, id, flow, window,
-          delta, window + delta);
-}
+/** Perform a transport_op */
+static void perform_stream_op_locked(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
+
+/** Cancel a stream: coming from the transport API */
+static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
+                            grpc_chttp2_stream_global *stream_global,
+                            grpc_status_code status);
+
+/** Add endpoint from this transport to pollset */
+static void add_to_pollset_locked(grpc_chttp2_transport *t,
+                                  grpc_pollset *pollset);
+
+/** Start new streams that have been created if we can */
+static void maybe_start_some_streams(
+    grpc_chttp2_transport_global *transport_global);
+
+static void connectivity_state_set(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_connectivity_state state);
 
 /*
  * CONSTRUCTION/DESTRUCTION/REFCOUNTING
  */
 
-static void destruct_transport(transport *t) {
+static void destruct_transport(grpc_chttp2_transport *t) {
   size_t i;
 
   gpr_mu_lock(&t->mu);
 
   GPR_ASSERT(t->ep == NULL);
 
-  gpr_slice_buffer_destroy(&t->outbuf);
-  gpr_slice_buffer_destroy(&t->qbuf);
-  grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
-  grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
-  grpc_chttp2_goaway_parser_destroy(&t->goaway_parser);
+  gpr_slice_buffer_destroy(&t->global.qbuf);
 
-  grpc_mdstr_unref(t->str_grpc_timeout);
+  gpr_slice_buffer_destroy(&t->writing.outbuf);
+  grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
+
+  gpr_slice_buffer_destroy(&t->parsing.qbuf);
+  grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
+  grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
+
+  GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout);
 
   for (i = 0; i < STREAM_LIST_COUNT; i++) {
     GPR_ASSERT(t->lists[i].head == NULL);
     GPR_ASSERT(t->lists[i].tail == NULL);
   }
 
-  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->stream_map) == 0);
+  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0);
+  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
 
-  grpc_chttp2_stream_map_destroy(&t->stream_map);
+  grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
+  grpc_chttp2_stream_map_destroy(&t->new_stream_map);
+  grpc_connectivity_state_destroy(&t->channel_callback.state_tracker);
 
   gpr_mu_unlock(&t->mu);
   gpr_mu_destroy(&t->mu);
-  gpr_cv_destroy(&t->cv);
 
   /* callback remaining pings: they're not allowed to call into the transpot,
      and maybe they hold resources that need to be freed */
-  for (i = 0; i < t->ping_count; i++) {
-    t->pings[i].cb(t->pings[i].user_data);
+  while (t->global.pings.next != &t->global.pings) {
+    grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
+    grpc_iomgr_add_delayed_callback(ping->on_recv, 0);
+    ping->next->prev = ping->prev;
+    ping->prev->next = ping->next;
+    gpr_free(ping);
   }
-  gpr_free(t->pings);
-
-  gpr_free(t->pending_callbacks.callbacks);
-  gpr_free(t->executing_callbacks.callbacks);
-
-  for (i = 0; i < t->num_pending_goaways; i++) {
-    gpr_slice_unref(t->pending_goaways[i].debug);
-  }
-  gpr_free(t->pending_goaways);
-
-  grpc_sopb_destroy(&t->nuke_later_sopb);
 
   grpc_mdctx_unref(t->metadata_context);
 
   gpr_free(t);
 }
 
-static void unref_transport(transport *t) {
+#ifdef REFCOUNTING_DEBUG
+#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
+#define UNREF_TRANSPORT(t, r) unref_transport(t, r, __FILE__, __LINE__)
+static void unref_transport(grpc_chttp2_transport *t, const char *reason,
+                            const char *file, int line) {
+  gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count,
+          t->refs.count - 1, reason, file, line);
   if (!gpr_unref(&t->refs)) return;
   destruct_transport(t);
 }
 
-static void ref_transport(transport *t) { gpr_ref(&t->refs); }
+static void ref_transport(grpc_chttp2_transport *t, const char *reason,
+                          const char *file, int line) {
+  gpr_log(GPR_DEBUG, "chttp2:  ref:%p %d->%d %s [%s:%d]", t, t->refs.count,
+          t->refs.count + 1, reason, file, line);
+  gpr_ref(&t->refs);
+}
+#else
+#define REF_TRANSPORT(t, r) ref_transport(t)
+#define UNREF_TRANSPORT(t, r) unref_transport(t)
+static void unref_transport(grpc_chttp2_transport *t) {
+  if (!gpr_unref(&t->refs)) return;
+  destruct_transport(t);
+}
 
-static void init_transport(transport *t, grpc_transport_setup_callback setup,
-                           void *arg, const grpc_channel_args *channel_args,
-                           grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
-                           grpc_mdctx *mdctx, int is_client) {
+static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
+#endif
+
+static void init_transport(grpc_chttp2_transport *t,
+                           const grpc_channel_args *channel_args,
+                           grpc_endpoint *ep, grpc_mdctx *mdctx,
+                           int is_client) {
   size_t i;
   int j;
-  grpc_transport_setup_result sr;
 
-  GPR_ASSERT(strlen(CLIENT_CONNECT_STRING) == CLIENT_CONNECT_STRLEN);
+  GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
+             GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
 
   memset(t, 0, sizeof(*t));
 
@@ -486,51 +216,65 @@
   /* one ref is for destroy, the other for when ep becomes NULL */
   gpr_ref_init(&t->refs, 2);
   gpr_mu_init(&t->mu);
-  gpr_cv_init(&t->cv);
   grpc_mdctx_ref(mdctx);
   t->metadata_context = mdctx;
-  t->str_grpc_timeout =
+  t->endpoint_reading = 1;
+  t->global.next_stream_id = is_client ? 1 : 2;
+  t->global.is_client = is_client;
+  t->global.outgoing_window = DEFAULT_WINDOW;
+  t->global.incoming_window = DEFAULT_WINDOW;
+  t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
+  t->global.ping_counter = 1;
+  t->global.pings.next = t->global.pings.prev = &t->global.pings;
+  t->parsing.is_client = is_client;
+  t->parsing.str_grpc_timeout =
       grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
-  t->reading = 1;
-  t->error_state = ERROR_STATE_NONE;
-  t->next_stream_id = is_client ? 1 : 2;
-  t->is_client = is_client;
-  t->outgoing_window = DEFAULT_WINDOW;
-  t->incoming_window = DEFAULT_WINDOW;
-  t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
-  t->deframe_state = is_client ? DTS_FH_0 : DTS_CLIENT_PREFIX_0;
-  t->ping_counter = gpr_now().tv_nsec;
-  grpc_chttp2_hpack_compressor_init(&t->hpack_compressor, mdctx);
-  grpc_chttp2_goaway_parser_init(&t->goaway_parser);
-  gpr_slice_buffer_init(&t->outbuf);
-  gpr_slice_buffer_init(&t->qbuf);
-  grpc_sopb_init(&t->nuke_later_sopb);
-  grpc_chttp2_hpack_parser_init(&t->hpack_parser, t->metadata_context);
+  t->parsing.deframe_state =
+      is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
+  t->writing.is_client = is_client;
+  grpc_connectivity_state_init(&t->channel_callback.state_tracker,
+                               GRPC_CHANNEL_READY);
+
+  gpr_slice_buffer_init(&t->global.qbuf);
+
+  gpr_slice_buffer_init(&t->writing.outbuf);
+  grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
+  grpc_iomgr_closure_init(&t->writing_action, writing_action, t);
+  grpc_iomgr_closure_init(&t->reading_action, reading_action, t);
+
+  gpr_slice_buffer_init(&t->parsing.qbuf);
+  grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
+  grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);
+
   if (is_client) {
-    gpr_slice_buffer_add(&t->qbuf,
-                         gpr_slice_from_copied_string(CLIENT_CONNECT_STRING));
+    gpr_slice_buffer_add(
+        &t->global.qbuf,
+        gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
   }
   /* 8 is a random stab in the dark as to a good initial size: it's small enough
      that it shouldn't waste memory for infrequently used connections, yet
      large enough that the exponential growth should happen nicely when it's
      needed.
      TODO(ctiller): tune this */
-  grpc_chttp2_stream_map_init(&t->stream_map, 8);
+  grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8);
+  grpc_chttp2_stream_map_init(&t->new_stream_map, 8);
 
   /* copy in initial settings to all setting sets */
-  for (i = 0; i < NUM_SETTING_SETS; i++) {
-    for (j = 0; j < GRPC_CHTTP2_NUM_SETTINGS; j++) {
-      t->settings[i][j] = grpc_chttp2_settings_parameters[j].default_value;
+  for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
+    t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value;
+    for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
+      t->global.settings[j][i] =
+          grpc_chttp2_settings_parameters[i].default_value;
     }
   }
-  t->dirtied_local_settings = 1;
+  t->global.dirtied_local_settings = 1;
   /* Hack: it's common for implementations to assume 65536 bytes initial send
      window -- this should by rights be 0 */
-  t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
-  t->sent_local_settings = 0;
+  t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+  t->global.sent_local_settings = 0;
 
   /* configure http2 the way we like it */
-  if (t->is_client) {
+  if (is_client) {
     push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
     push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
   }
@@ -540,7 +284,7 @@
     for (i = 0; i < channel_args->num_args; i++) {
       if (0 ==
           strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
-        if (t->is_client) {
+        if (is_client) {
           gpr_log(GPR_ERROR, "%s: is ignored on the client",
                   GRPC_ARG_MAX_CONCURRENT_STREAMS);
         } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
@@ -555,357 +299,182 @@
         if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
           gpr_log(GPR_ERROR, "%s: must be an integer",
                   GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
-        } else if ((t->next_stream_id & 1) !=
+        } else if ((t->global.next_stream_id & 1) !=
                    (channel_args->args[i].value.integer & 1)) {
           gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
-                  GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, t->next_stream_id & 1,
-                  t->is_client ? "client" : "server");
+                  GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
+                  t->global.next_stream_id & 1,
+                  is_client ? "client" : "server");
         } else {
-          t->next_stream_id = channel_args->args[i].value.integer;
+          t->global.next_stream_id = channel_args->args[i].value.integer;
         }
       }
     }
   }
-
-  gpr_mu_lock(&t->mu);
-  t->calling_back_channel = 1;
-  ref_transport(t); /* matches unref at end of this function */
-  gpr_mu_unlock(&t->mu);
-
-  sr = setup(arg, &t->base, t->metadata_context);
-
-  lock(t);
-  t->cb = sr.callbacks;
-  t->cb_user_data = sr.user_data;
-  t->calling_back_channel = 0;
-  if (t->destroying) gpr_cv_signal(&t->cv);
-  unlock(t);
-
-  ref_transport(t); /* matches unref inside recv_data */
-  recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
-
-  unref_transport(t);
 }
 
 static void destroy_transport(grpc_transport *gt) {
-  transport *t = (transport *)gt;
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
 
   lock(t);
   t->destroying = 1;
-  /* Wait for pending stuff to finish.
-     We need to be not calling back to ensure that closed() gets a chance to
-     trigger if needed during unlock() before we die.
-     We need to be not writing as cancellation finalization may produce some
-     callbacks that NEED to be made to close out some streams when t->writing
-     becomes 0. */
-  while (t->calling_back_channel || t->writing) {
-    gpr_cv_wait(&t->cv, &t->mu, gpr_inf_future);
-  }
   drop_connection(t);
   unlock(t);
 
-  /* The drop_connection() above puts the transport into an error state, and
-     the follow-up unlock should then (as part of the cleanup work it does)
-     ensure that cb is NULL, and therefore not call back anything further.
-     This check validates this very subtle behavior.
-     It's shutdown path, so I don't believe an extra lock pair is going to be
-     problematic for performance. */
-  lock(t);
-  GPR_ASSERT(!t->cb);
-  unlock(t);
-
-  unref_transport(t);
+  UNREF_TRANSPORT(t, "destroy");
 }
 
-static void close_transport(grpc_transport *gt) {
-  transport *t = (transport *)gt;
-  gpr_mu_lock(&t->mu);
-  GPR_ASSERT(!t->closed);
-  t->closed = 1;
-  if (t->ep) {
-    grpc_endpoint_shutdown(t->ep);
+static void close_transport_locked(grpc_chttp2_transport *t) {
+  if (!t->closed) {
+    t->closed = 1;
+    connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE);
+    if (t->ep) {
+      grpc_endpoint_shutdown(t->ep);
+    }
   }
-  gpr_mu_unlock(&t->mu);
-}
-
-static void goaway(grpc_transport *gt, grpc_status_code status,
-                   gpr_slice debug_data) {
-  transport *t = (transport *)gt;
-  lock(t);
-  grpc_chttp2_goaway_append(t->last_incoming_stream_id,
-                            grpc_chttp2_grpc_status_to_http2_error(status),
-                            debug_data, &t->qbuf);
-  unlock(t);
 }
 
 static int init_stream(grpc_transport *gt, grpc_stream *gs,
-                       const void *server_data, grpc_transport_op *initial_op) {
-  transport *t = (transport *)gt;
-  stream *s = (stream *)gs;
+                       const void *server_data,
+                       grpc_transport_stream_op *initial_op) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
   memset(s, 0, sizeof(*s));
 
-  ref_transport(t);
+  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.incoming_metadata);
+  grpc_chttp2_incoming_metadata_buffer_init(&s->global.incoming_metadata);
+  grpc_sopb_init(&s->writing.sopb);
+  grpc_sopb_init(&s->global.incoming_sopb);
+  grpc_chttp2_data_parser_init(&s->parsing.data_parser);
 
-  if (!server_data) {
-    lock(t);
-    s->id = 0;
-    s->outgoing_window = 0;
-    s->incoming_window = 0;
-  } else {
-    /* already locked */
-    s->id = (gpr_uint32)(gpr_uintptr)server_data;
-    s->outgoing_window =
-        t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    s->incoming_window =
-        t->settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    t->incoming_stream = s;
-    grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+  REF_TRANSPORT(t, "stream");
+
+  lock(t);
+  grpc_chttp2_register_stream(t, s);
+  if (server_data) {
+    GPR_ASSERT(t->parsing_active);
+    s->global.id = (gpr_uint32)(gpr_uintptr)server_data;
+    s->global.outgoing_window =
+        t->global.settings[GRPC_PEER_SETTINGS]
+                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    s->global.max_recv_bytes = 
+        s->parsing.incoming_window = 
+        s->global.incoming_window =
+        t->global.settings[GRPC_SENT_SETTINGS]
+                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    *t->accepting_stream = s;
+    grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
+    s->global.in_stream_map = 1;
   }
 
-  s->incoming_deadline = gpr_inf_future;
-  grpc_sopb_init(&s->writing_sopb);
-  grpc_sopb_init(&s->callback_sopb);
-  grpc_chttp2_data_parser_init(&s->parser);
-
-  if (initial_op) perform_op_locked(t, s, initial_op);
-
-  if (!server_data) {
-    unlock(t);
-  }
+  if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op);
+  unlock(t);
 
   return 0;
 }
 
-static void schedule_nuke_sopb(transport *t, grpc_stream_op_buffer *sopb) {
-  grpc_sopb_append(&t->nuke_later_sopb, sopb->ops, sopb->nops);
-  sopb->nops = 0;
-}
-
 static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
-  transport *t = (transport *)gt;
-  stream *s = (stream *)gs;
-  size_t i;
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
+  int i;
 
   gpr_mu_lock(&t->mu);
 
-  /* stop parsing if we're currently parsing this stream */
-  if (t->deframe_state == DTS_FRAME && t->incoming_stream_id == s->id &&
-      s->id != 0) {
-    become_skip_parser(t);
+  GPR_ASSERT(s->global.published_state == GRPC_STREAM_CLOSED ||
+             s->global.id == 0);
+  GPR_ASSERT(!s->global.in_stream_map);
+  if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
+    close_transport_locked(t);
+  }
+  if (!t->parsing_active && s->global.id) {
+    GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
+                                           s->global.id) == NULL);
   }
 
-  for (i = 0; i < STREAM_LIST_COUNT; i++) {
-    stream_list_remove(t, s, i);
-  }
-  remove_from_stream_map(t, s);
+  grpc_chttp2_list_remove_incoming_window_updated(&t->global, &s->global);
+  grpc_chttp2_list_remove_writable_window_update_stream(&t->global, &s->global);
 
   gpr_mu_unlock(&t->mu);
 
-  GPR_ASSERT(s->outgoing_sopb == NULL);
-  GPR_ASSERT(s->incoming_sopb == NULL);
-  grpc_sopb_destroy(&s->writing_sopb);
-  grpc_sopb_destroy(&s->callback_sopb);
-  grpc_chttp2_data_parser_destroy(&s->parser);
-  for (i = 0; i < s->incoming_metadata_count; i++) {
-    grpc_mdelem_unref(s->incoming_metadata[i].md);
+  for (i = 0; i < STREAM_LIST_COUNT; i++) {
+    GPR_ASSERT(!s->included[i]);
   }
-  gpr_free(s->incoming_metadata);
-  gpr_free(s->old_incoming_metadata);
 
-  unref_transport(t);
+  GPR_ASSERT(s->global.outgoing_sopb == NULL);
+  GPR_ASSERT(s->global.publish_sopb == NULL);
+  grpc_sopb_destroy(&s->writing.sopb);
+  grpc_sopb_destroy(&s->global.incoming_sopb);
+  grpc_chttp2_data_parser_destroy(&s->parsing.data_parser);
+  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.incoming_metadata);
+  grpc_chttp2_incoming_metadata_buffer_destroy(&s->global.incoming_metadata);
+  grpc_chttp2_incoming_metadata_live_op_buffer_end(
+      &s->global.outstanding_metadata);
+
+  UNREF_TRANSPORT(t, "stream");
 }
 
-/*
- * LIST MANAGEMENT
- */
-
-static int stream_list_empty(transport *t, stream_list_id id) {
-  return t->lists[id].head == NULL;
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
+    grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) {
+  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
+  grpc_chttp2_stream *s =
+      grpc_chttp2_stream_map_find(&t->parsing_stream_map, id);
+  return s ? &s->parsing : NULL;
 }
 
-static stream *stream_list_remove_head(transport *t, stream_list_id id) {
-  stream *s = t->lists[id].head;
-  if (s) {
-    stream *new_head = s->links[id].next;
-    GPR_ASSERT(s->included[id]);
-    if (new_head) {
-      t->lists[id].head = new_head;
-      new_head->links[id].prev = NULL;
-    } else {
-      t->lists[id].head = NULL;
-      t->lists[id].tail = NULL;
-    }
-    s->included[id] = 0;
-  }
-  return s;
-}
-
-static void stream_list_remove(transport *t, stream *s, stream_list_id id) {
-  if (!s->included[id]) return;
-  s->included[id] = 0;
-  if (s->links[id].prev) {
-    s->links[id].prev->links[id].next = s->links[id].next;
-  } else {
-    GPR_ASSERT(t->lists[id].head == s);
-    t->lists[id].head = s->links[id].next;
-  }
-  if (s->links[id].next) {
-    s->links[id].next->links[id].prev = s->links[id].prev;
-  } else {
-    t->lists[id].tail = s->links[id].prev;
-  }
-}
-
-static void stream_list_add_tail(transport *t, stream *s, stream_list_id id) {
-  stream *old_tail;
-  GPR_ASSERT(!s->included[id]);
-  old_tail = t->lists[id].tail;
-  s->links[id].next = NULL;
-  s->links[id].prev = old_tail;
-  if (old_tail) {
-    old_tail->links[id].next = s;
-  } else {
-    s->links[id].prev = NULL;
-    t->lists[id].head = s;
-  }
-  t->lists[id].tail = s;
-  s->included[id] = 1;
-}
-
-static void stream_list_join(transport *t, stream *s, stream_list_id id) {
-  if (s->included[id]) {
-    return;
-  }
-  stream_list_add_tail(t, s, id);
-}
-
-static void remove_from_stream_map(transport *t, stream *s) {
-  if (s->id == 0) return;
-  IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Removing stream %d",
-                     t->is_client ? "CLI" : "SVR", s->id));
-  if (grpc_chttp2_stream_map_delete(&t->stream_map, s->id)) {
-    maybe_start_some_streams(t);
-  }
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
+    grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id) {
+  grpc_chttp2_stream *accepting;
+  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
+  GPR_ASSERT(t->accepting_stream == NULL);
+  t->accepting_stream = &accepting;
+  t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data,
+                                    &t->base, (void *)(gpr_uintptr)id);
+  t->accepting_stream = NULL;
+  return &accepting->parsing;
 }
 
 /*
  * LOCK MANAGEMENT
  */
 
-/* We take a transport-global lock in response to calls coming in from above,
+/* We take a grpc_chttp2_transport-global lock in response to calls coming in
+   from above,
    and in response to data being received from below. New data to be written
    is always queued, as are callbacks to process data. During unlock() we
    check our todo lists and initiate callbacks and flush writes. */
 
-static void lock(transport *t) { gpr_mu_lock(&t->mu); }
+static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
 
-static void unlock(transport *t) {
-  int start_write = 0;
-  int perform_callbacks = 0;
-  int call_closed = 0;
-  int num_goaways = 0;
-  int i;
-  pending_goaway *goaways = NULL;
-  grpc_endpoint *ep = t->ep;
-  grpc_stream_op_buffer nuke_now;
-  const grpc_transport_callbacks *cb = t->cb;
+static void unlock(grpc_chttp2_transport *t) {
+  grpc_iomgr_closure *run_closures;
 
-  GRPC_TIMER_BEGIN(GRPC_PTAG_HTTP2_UNLOCK, 0);
-
-  grpc_sopb_init(&nuke_now);
-  if (t->nuke_later_sopb.nops) {
-    grpc_sopb_swap(&nuke_now, &t->nuke_later_sopb);
+  unlock_check_read_write_state(t);
+  if (!t->writing_active && !t->closed &&
+      grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
+    t->writing_active = 1;
+    REF_TRANSPORT(t, "writing");
+    grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1);
   }
 
-  /* see if we need to trigger a write - and if so, get the data ready */
-  if (ep && !t->writing) {
-    t->writing = start_write = prepare_write(t);
-    if (start_write) {
-      ref_transport(t);
-    }
-  }
+  run_closures = t->global.pending_closures_head;
+  t->global.pending_closures_head = NULL;
+  t->global.pending_closures_tail = NULL;
 
-  if (!t->writing) {
-    finalize_cancellations(t);
-  }
-
-  finish_reads(t);
-
-  /* gather any callbacks that need to be made */
-  if (!t->calling_back_ops) {
-    t->calling_back_ops = perform_callbacks = prepare_callbacks(t);
-    if (perform_callbacks) ref_transport(t);
-  }
-
-  if (!t->calling_back_channel && cb) {
-    if (t->error_state == ERROR_STATE_SEEN && !t->writing) {
-      call_closed = 1;
-      t->calling_back_channel = 1;
-      t->cb = NULL; /* no more callbacks */
-      t->error_state = ERROR_STATE_NOTIFIED;
-    }
-    if (t->num_pending_goaways) {
-      goaways = t->pending_goaways;
-      num_goaways = t->num_pending_goaways;
-      t->pending_goaways = NULL;
-      t->num_pending_goaways = 0;
-      t->cap_pending_goaways = 0;
-      t->calling_back_channel = 1;
-    }
-    if (call_closed || num_goaways) {
-      ref_transport(t);
-    }
-  }
-
-  /* finally unlock */
   gpr_mu_unlock(&t->mu);
 
-  GRPC_TIMER_MARK(GRPC_PTAG_HTTP2_UNLOCK_CLEANUP, 0);
-
-  /* perform some callbacks if necessary */
-  for (i = 0; i < num_goaways; i++) {
-    cb->goaway(t->cb_user_data, &t->base, goaways[i].status, goaways[i].debug);
+  while (run_closures) {
+    grpc_iomgr_closure *next = run_closures->next;
+    run_closures->cb(run_closures->cb_arg, run_closures->success);
+    run_closures = next;
   }
-
-  if (perform_callbacks) {
-    run_callbacks(t);
-    lock(t);
-    t->calling_back_ops = 0;
-    unlock(t);
-    unref_transport(t);
-  }
-
-  if (call_closed) {
-    call_cb_closed(t, cb);
-  }
-
-  /* write some bytes if necessary */
-  if (start_write) {
-    /* ultimately calls unref_transport(t); and clears t->writing */
-    perform_write(t, ep);
-  }
-
-  if (call_closed || num_goaways) {
-    lock(t);
-    t->calling_back_channel = 0;
-    if (t->destroying) gpr_cv_signal(&t->cv);
-    unlock(t);
-    unref_transport(t);
-  }
-
-  grpc_sopb_destroy(&nuke_now);
-
-  gpr_free(goaways);
-
-  GRPC_TIMER_END(GRPC_PTAG_HTTP2_UNLOCK, 0);
 }
 
 /*
  * OUTPUT PROCESSING
  */
 
-static void push_setting(transport *t, grpc_chttp2_setting_id id,
+static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
                          gpr_uint32 value) {
   const grpc_chttp2_setting_parameters *sp =
       &grpc_chttp2_settings_parameters[id];
@@ -914,292 +483,251 @@
     gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
             value, use_value);
   }
-  if (use_value != t->settings[LOCAL_SETTINGS][id]) {
-    t->settings[LOCAL_SETTINGS][id] = use_value;
-    t->dirtied_local_settings = 1;
+  if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
+    t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
+    t->global.dirtied_local_settings = 1;
   }
 }
 
-static int prepare_write(transport *t) {
-  stream *s;
-  gpr_uint32 window_delta;
-
-  /* simple writes are queued to qbuf, and flushed here */
-  gpr_slice_buffer_swap(&t->qbuf, &t->outbuf);
-  GPR_ASSERT(t->qbuf.count == 0);
-
-  if (t->dirtied_local_settings && !t->sent_local_settings) {
-    gpr_slice_buffer_add(
-        &t->outbuf, grpc_chttp2_settings_create(
-                        t->settings[SENT_SETTINGS], t->settings[LOCAL_SETTINGS],
-                        t->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
-    t->force_send_settings = 0;
-    t->dirtied_local_settings = 0;
-    t->sent_local_settings = 1;
-  }
-
-  /* for each stream that's become writable, frame it's data (according to
-     available window sizes) and add to the output buffer */
-  while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE)) &&
-         s->outgoing_window > 0) {
-    window_delta = grpc_chttp2_preencode(
-        s->outgoing_sopb->ops, &s->outgoing_sopb->nops,
-        GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb);
-    FLOWCTL_TRACE(t, t, outgoing, 0, -(gpr_int64)window_delta);
-    FLOWCTL_TRACE(t, s, outgoing, s->id, -(gpr_int64)window_delta);
-    t->outgoing_window -= window_delta;
-    s->outgoing_window -= window_delta;
-
-    if (s->write_state == WRITE_STATE_QUEUED_CLOSE &&
-        s->outgoing_sopb->nops == 0) {
-      if (!t->is_client && !s->read_closed) {
-        s->send_closed = SEND_CLOSED_WITH_RST_STREAM;
-      } else {
-        s->send_closed = SEND_CLOSED;
-      }
-    }
-    if (s->writing_sopb.nops > 0 || s->send_closed) {
-      stream_list_join(t, s, WRITING);
-    }
-
-    /* we should either exhaust window or have no ops left, but not both */
-    if (s->outgoing_sopb->nops == 0) {
-      s->outgoing_sopb = NULL;
-      schedule_cb(t, s->send_done_closure, 1);
-    } else if (s->outgoing_window) {
-      stream_list_add_tail(t, s, WRITABLE);
-    }
-  }
-
-  /* for each stream that wants to update its window, add that window here */
-  while ((s = stream_list_remove_head(t, WINDOW_UPDATE))) {
-    window_delta =
-        t->settings[LOCAL_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] -
-        s->incoming_window;
-    if (!s->read_closed && window_delta) {
-      gpr_slice_buffer_add(
-          &t->outbuf, grpc_chttp2_window_update_create(s->id, window_delta));
-      FLOWCTL_TRACE(t, s, incoming, s->id, window_delta);
-      s->incoming_window += window_delta;
-    }
-  }
-
-  /* if the transport is ready to send a window update, do so here also */
-  if (t->incoming_window < t->connection_window_target * 3 / 4) {
-    window_delta = t->connection_window_target - t->incoming_window;
-    gpr_slice_buffer_add(&t->outbuf,
-                         grpc_chttp2_window_update_create(0, window_delta));
-    FLOWCTL_TRACE(t, t, incoming, 0, window_delta);
-    t->incoming_window += window_delta;
-  }
-
-  return t->outbuf.length > 0 || !stream_list_empty(t, WRITING);
-}
-
-static void finalize_outbuf(transport *t) {
-  stream *s;
-
-  while ((s = stream_list_remove_head(t, WRITING))) {
-    grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops,
-                       s->send_closed != DONT_SEND_CLOSED, s->id, &t->hpack_compressor, &t->outbuf);
-    s->writing_sopb.nops = 0;
-    if (s->send_closed == SEND_CLOSED_WITH_RST_STREAM) {
-      gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR));
-    }
-    if (s->send_closed != DONT_SEND_CLOSED) {
-      stream_list_join(t, s, WRITTEN_CLOSED);
-    }
-  }
-}
-
-static void finish_write_common(transport *t, int success) {
-  stream *s;
+void grpc_chttp2_terminate_writing(
+    grpc_chttp2_transport_writing *transport_writing, int success) {
+  grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
 
   lock(t);
+
   if (!success) {
     drop_connection(t);
   }
-  while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) {
-    s->write_state = WRITE_STATE_SENT_CLOSE;
-    if (!t->is_client) {
-      s->read_closed = 1;
-    }
-    maybe_finish_read(t, s);
-  }
-  t->outbuf.count = 0;
-  t->outbuf.length = 0;
+
+  /* cleanup writing related jazz */
+  grpc_chttp2_cleanup_writing(&t->global, &t->writing);
+
   /* leave the writing flag up on shutdown to prevent further writes in unlock()
      from starting */
-  t->writing = 0;
-  if (t->destroying) {
-    gpr_cv_signal(&t->cv);
-  }
-  if (!t->reading) {
+  t->writing_active = 0;
+  if (t->ep && !t->endpoint_reading) {
     grpc_endpoint_destroy(t->ep);
     t->ep = NULL;
-    unref_transport(t); /* safe because we'll still have the ref for write */
+    UNREF_TRANSPORT(
+        t, "disconnect"); /* safe because we'll still have the ref for write */
   }
+
   unlock(t);
 
-  unref_transport(t);
+  UNREF_TRANSPORT(t, "writing");
 }
 
-static void finish_write(void *tp, grpc_endpoint_cb_status error) {
-  transport *t = tp;
-  finish_write_common(t, error == GRPC_ENDPOINT_CB_OK);
+static void writing_action(void *gt, int iomgr_success_ignored) {
+  grpc_chttp2_transport *t = gt;
+  grpc_chttp2_perform_writes(&t->writing, t->ep);
 }
 
-static void perform_write(transport *t, grpc_endpoint *ep) {
-  finalize_outbuf(t);
-
-  GPR_ASSERT(t->outbuf.count > 0);
-
-  switch (grpc_endpoint_write(ep, t->outbuf.slices, t->outbuf.count,
-                              finish_write, t)) {
-    case GRPC_ENDPOINT_WRITE_DONE:
-      finish_write_common(t, 1);
-      break;
-    case GRPC_ENDPOINT_WRITE_ERROR:
-      finish_write_common(t, 0);
-      break;
-    case GRPC_ENDPOINT_WRITE_PENDING:
-      break;
-  }
+void grpc_chttp2_add_incoming_goaway(
+    grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error,
+    gpr_slice goaway_text) {
+  char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+  gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg);
+  gpr_free(msg);
+  gpr_slice_unref(goaway_text);
+  transport_global->seen_goaway = 1;
+  connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE);
 }
 
-static void add_goaway(transport *t, gpr_uint32 goaway_error, gpr_slice goaway_text) {
-  if (t->num_pending_goaways == t->cap_pending_goaways) {
-    t->cap_pending_goaways = GPR_MAX(1, t->cap_pending_goaways * 2);
-    t->pending_goaways =
-        gpr_realloc(t->pending_goaways,
-                    sizeof(pending_goaway) * t->cap_pending_goaways);
-  }
-  t->pending_goaways[t->num_pending_goaways].status =
-      grpc_chttp2_http2_error_to_grpc_status(goaway_error);
-  t->pending_goaways[t->num_pending_goaways].debug = goaway_text;
-  t->num_pending_goaways++;
-}
+static void maybe_start_some_streams(
+    grpc_chttp2_transport_global *transport_global) {
+  grpc_chttp2_stream_global *stream_global;
+  /* start streams where we have free grpc_chttp2_stream ids and free
+   * concurrency */
+  while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID &&
+         transport_global->concurrent_stream_count <
+             transport_global
+                 ->settings[GRPC_PEER_SETTINGS]
+                           [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
+         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
+                                                      &stream_global)) {
+    GRPC_CHTTP2_IF_TRACING(gpr_log(
+        GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d",
+        transport_global->is_client ? "CLI" : "SVR", stream_global,
+        transport_global->next_stream_id));
 
+    GPR_ASSERT(stream_global->id == 0);
+    stream_global->id = transport_global->next_stream_id;
+    transport_global->next_stream_id += 2;
 
-static void maybe_start_some_streams(transport *t) {
-  /* start streams where we have free stream ids and free concurrency */
-  while (
-      t->next_stream_id <= MAX_CLIENT_STREAM_ID &&
-      grpc_chttp2_stream_map_size(&t->stream_map) <
-      t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) {
-    stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY);
-    if (!s) return;
-
-    IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Allocating new stream %p to id %d",
-                       t->is_client ? "CLI" : "SVR", s, t->next_stream_id));
-
-    if (t->next_stream_id == MAX_CLIENT_STREAM_ID) {
-      add_goaway(t, GRPC_CHTTP2_NO_ERROR, gpr_slice_from_copied_string("Exceeded sequence number limit"));
+    if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
+      connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE);
     }
 
-    GPR_ASSERT(s->id == 0);
-    s->id = t->next_stream_id;
-    t->next_stream_id += 2;
-    s->outgoing_window =
-        t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    s->incoming_window =
-        t->settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
-    stream_list_join(t, s, WRITABLE);
+    stream_global->outgoing_window =
+        transport_global->settings[GRPC_PEER_SETTINGS]
+                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    stream_global->incoming_window =
+        transport_global->settings[GRPC_SENT_SETTINGS]
+                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    stream_global->max_recv_bytes = 
+        GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes);
+    grpc_chttp2_stream_map_add(
+        &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
+        stream_global->id, STREAM_FROM_GLOBAL(stream_global));
+    stream_global->in_stream_map = 1;
+    transport_global->concurrent_stream_count++;
+    grpc_chttp2_list_add_incoming_window_updated(transport_global,
+                                                 stream_global);
+    grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
+    grpc_chttp2_list_add_writable_window_update_stream(transport_global,
+                                                       stream_global);
+
   }
   /* cancel out streams that will never be started */
-  while (t->next_stream_id > MAX_CLIENT_STREAM_ID) {
-    stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY);
-    if (!s) return;
-
-    cancel_stream(t, s, GRPC_STATUS_UNAVAILABLE, grpc_chttp2_grpc_status_to_http2_error(GRPC_STATUS_UNAVAILABLE), NULL, 0);
+  while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
+         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
+                                                      &stream_global)) {
+    cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
   }
 }
 
-static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) {
+static void perform_stream_op_locked(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
   if (op->cancel_with_status != GRPC_STATUS_OK) {
-    cancel_stream(
-        t, s, op->cancel_with_status,
-        grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status),
-        op->cancel_message, 1);
+    cancel_from_api(transport_global, stream_global, op->cancel_with_status);
   }
 
   if (op->send_ops) {
-    GPR_ASSERT(s->outgoing_sopb == NULL);
-    s->send_done_closure.cb = op->on_done_send;
-    s->send_done_closure.user_data = op->send_user_data;
-    if (!s->cancelled) {
-      s->outgoing_sopb = op->send_ops;
-      if (op->is_last_send && s->write_state == WRITE_STATE_OPEN) {
-        s->write_state = WRITE_STATE_QUEUED_CLOSE;
+    GPR_ASSERT(stream_global->outgoing_sopb == NULL);
+    stream_global->send_done_closure = op->on_done_send;
+    if (!stream_global->cancelled) {
+      stream_global->outgoing_sopb = op->send_ops;
+      if (op->is_last_send &&
+          stream_global->write_state == GRPC_WRITE_STATE_OPEN) {
+        stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE;
       }
-      if (s->id == 0) {
-        IF_TRACING(gpr_log(GPR_DEBUG,
-                           "HTTP:%s: New stream %p waiting for concurrency",
-                           t->is_client ? "CLI" : "SVR", s));
-        stream_list_join(t, s, WAITING_FOR_CONCURRENCY);
-        maybe_start_some_streams(t);
-      } else if (s->outgoing_window > 0) {
-        stream_list_join(t, s, WRITABLE);
+      if (stream_global->id == 0) {
+        GRPC_CHTTP2_IF_TRACING(gpr_log(
+            GPR_DEBUG,
+            "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency",
+            transport_global->is_client ? "CLI" : "SVR", stream_global));
+        grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
+                                                     stream_global);
+        maybe_start_some_streams(transport_global);
+      } else if (stream_global->outgoing_window > 0) {
+        grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
       }
     } else {
-      schedule_nuke_sopb(t, op->send_ops);
-      schedule_cb(t, s->send_done_closure, 0);
+      grpc_sopb_reset(op->send_ops);
+      grpc_chttp2_schedule_closure(transport_global,
+                                   stream_global->send_done_closure, 0);
     }
   }
 
   if (op->recv_ops) {
-    GPR_ASSERT(s->incoming_sopb == NULL);
-    GPR_ASSERT(s->published_state != GRPC_STREAM_CLOSED);
-    s->recv_done_closure.cb = op->on_done_recv;
-    s->recv_done_closure.user_data = op->recv_user_data;
-    s->incoming_sopb = op->recv_ops;
-    s->incoming_sopb->nops = 0;
-    s->publish_state = op->recv_state;
-    gpr_free(s->old_incoming_metadata);
-    s->old_incoming_metadata = NULL;
-    maybe_finish_read(t, s);
-    maybe_join_window_updates(t, s);
+    GPR_ASSERT(stream_global->publish_sopb == NULL);
+    GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED);
+    stream_global->recv_done_closure = op->on_done_recv;
+    stream_global->publish_sopb = op->recv_ops;
+    stream_global->publish_sopb->nops = 0;
+    stream_global->publish_state = op->recv_state;
+    if (stream_global->max_recv_bytes < op->max_recv_bytes) {
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("op", transport_global, stream_global,
+          max_recv_bytes, op->max_recv_bytes - stream_global->max_recv_bytes);
+      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+          "op", transport_global, stream_global, unannounced_incoming_window,
+          op->max_recv_bytes - stream_global->max_recv_bytes);
+      stream_global->unannounced_incoming_window += op->max_recv_bytes - stream_global->max_recv_bytes;
+      stream_global->max_recv_bytes = op->max_recv_bytes;
+    }
+    grpc_chttp2_incoming_metadata_live_op_buffer_end(
+        &stream_global->outstanding_metadata);
+    if (stream_global->id != 0) {
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+      grpc_chttp2_list_add_writable_window_update_stream(transport_global,
+                                                         stream_global);
+    }
+  }
+
+  if (op->bind_pollset) {
+    add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global),
+                          op->bind_pollset);
+  }
+
+  if (op->on_consumed) {
+    grpc_chttp2_schedule_closure(transport_global, op->on_consumed, 1);
+  }
+}
+
+static void perform_stream_op(grpc_transport *gt, grpc_stream *gs,
+                              grpc_transport_stream_op *op) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
+
+  lock(t);
+  perform_stream_op_locked(&t->global, &s->global, op);
+  unlock(t);
+}
+
+static void send_ping_locked(grpc_chttp2_transport *t,
+                             grpc_iomgr_closure *on_recv) {
+  grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
+  p->next = &t->global.pings;
+  p->prev = p->next->prev;
+  p->prev->next = p->next->prev = p;
+  p->id[0] = (t->global.ping_counter >> 56) & 0xff;
+  p->id[1] = (t->global.ping_counter >> 48) & 0xff;
+  p->id[2] = (t->global.ping_counter >> 40) & 0xff;
+  p->id[3] = (t->global.ping_counter >> 32) & 0xff;
+  p->id[4] = (t->global.ping_counter >> 24) & 0xff;
+  p->id[5] = (t->global.ping_counter >> 16) & 0xff;
+  p->id[6] = (t->global.ping_counter >> 8) & 0xff;
+  p->id[7] = t->global.ping_counter & 0xff;
+  p->on_recv = on_recv;
+  gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
+}
+
+static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+
+  lock(t);
+
+  if (op->on_consumed) {
+    grpc_chttp2_schedule_closure(&t->global, op->on_consumed, 1);
+  }
+
+  if (op->on_connectivity_state_change) {
+    grpc_connectivity_state_notify_on_state_change(
+        &t->channel_callback.state_tracker, op->connectivity_state,
+        op->on_connectivity_state_change);
+  }
+
+  if (op->send_goaway) {
+    t->global.sent_goaway = 1;
+    grpc_chttp2_goaway_append(
+        t->global.last_incoming_stream_id,
+        grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
+        gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
+    if (!grpc_chttp2_has_streams(t)) {
+      close_transport_locked(t);
+    }
+  }
+
+  if (op->set_accept_stream != NULL) {
+    t->channel_callback.accept_stream = op->set_accept_stream;
+    t->channel_callback.accept_stream_user_data =
+        op->set_accept_stream_user_data;
   }
 
   if (op->bind_pollset) {
     add_to_pollset_locked(t, op->bind_pollset);
   }
-}
 
-static void perform_op(grpc_transport *gt, grpc_stream *gs,
-                       grpc_transport_op *op) {
-  transport *t = (transport *)gt;
-  stream *s = (stream *)gs;
-
-  lock(t);
-  perform_op_locked(t, s, op);
-  unlock(t);
-}
-
-static void send_ping(grpc_transport *gt, void (*cb)(void *user_data),
-                      void *user_data) {
-  transport *t = (transport *)gt;
-  outstanding_ping *p;
-
-  lock(t);
-  if (t->ping_capacity == t->ping_count) {
-    t->ping_capacity = GPR_MAX(1, t->ping_capacity * 3 / 2);
-    t->pings =
-        gpr_realloc(t->pings, sizeof(outstanding_ping) * t->ping_capacity);
+  if (op->send_ping) {
+    send_ping_locked(t, op->send_ping);
   }
-  p = &t->pings[t->ping_count++];
-  p->id[0] = (t->ping_counter >> 56) & 0xff;
-  p->id[1] = (t->ping_counter >> 48) & 0xff;
-  p->id[2] = (t->ping_counter >> 40) & 0xff;
-  p->id[3] = (t->ping_counter >> 32) & 0xff;
-  p->id[4] = (t->ping_counter >> 24) & 0xff;
-  p->id[5] = (t->ping_counter >> 16) & 0xff;
-  p->id[6] = (t->ping_counter >> 8) & 0xff;
-  p->id[7] = t->ping_counter & 0xff;
-  p->cb = cb;
-  p->user_data = user_data;
-  gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id));
+
+  if (op->disconnect) {
+    close_transport_locked(t);
+  }
+
   unlock(t);
 }
 
@@ -1207,798 +735,6 @@
  * INPUT PROCESSING
  */
 
-static void finalize_cancellations(transport *t) {
-  stream *s;
-
-  while ((s = stream_list_remove_head(t, CANCELLED))) {
-    s->read_closed = 1;
-    s->write_state = WRITE_STATE_SENT_CLOSE;
-    maybe_finish_read(t, s);
-  }
-}
-
-static void add_incoming_metadata(transport *t, stream *s, grpc_mdelem *elem) {
-  if (s->incoming_metadata_capacity == s->incoming_metadata_count) {
-    s->incoming_metadata_capacity =
-        GPR_MAX(8, 2 * s->incoming_metadata_capacity);
-    s->incoming_metadata =
-        gpr_realloc(s->incoming_metadata, sizeof(*s->incoming_metadata) *
-                                              s->incoming_metadata_capacity);
-  }
-  s->incoming_metadata[s->incoming_metadata_count++].md = elem;
-}
-
-static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
-                                grpc_status_code local_status,
-                                grpc_chttp2_error_code error_code,
-                                grpc_mdstr *optional_message, int send_rst) {
-  int had_outgoing;
-  char buffer[GPR_LTOA_MIN_BUFSIZE];
-
-  if (s) {
-    /* clear out any unreported input & output: nobody cares anymore */
-    had_outgoing = s->outgoing_sopb && s->outgoing_sopb->nops != 0;
-    if (error_code != GRPC_CHTTP2_NO_ERROR) {
-      schedule_nuke_sopb(t, &s->parser.incoming_sopb);
-      if (s->outgoing_sopb) {
-        schedule_nuke_sopb(t, s->outgoing_sopb);
-        s->outgoing_sopb = NULL;
-        stream_list_remove(t, s, WRITABLE);
-        schedule_cb(t, s->send_done_closure, 0);
-      }
-    }
-    if (s->cancelled) {
-      send_rst = 0;
-    } else if (!s->read_closed || s->write_state != WRITE_STATE_SENT_CLOSE ||
-               had_outgoing) {
-      s->cancelled = 1;
-      stream_list_join(t, s, CANCELLED);
-
-      if (error_code != GRPC_CHTTP2_NO_ERROR) {
-        /* synthesize a status if we don't believe we'll get one */
-        gpr_ltoa(local_status, buffer);
-        add_incoming_metadata(
-            t, s,
-            grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer));
-        if (!optional_message) {
-          switch (local_status) {
-            case GRPC_STATUS_CANCELLED:
-              add_incoming_metadata(
-                  t, s, grpc_mdelem_from_strings(t->metadata_context,
-                                                 "grpc-message", "Cancelled"));
-              break;
-            default:
-              break;
-          }
-        } else {
-          add_incoming_metadata(
-              t, s,
-              grpc_mdelem_from_metadata_strings(
-                  t->metadata_context,
-                  grpc_mdstr_from_string(t->metadata_context, "grpc-message"),
-                  grpc_mdstr_ref(optional_message)));
-        }
-        add_metadata_batch(t, s);
-      }
-    }
-    maybe_finish_read(t, s);
-  }
-  if (!id) send_rst = 0;
-  if (send_rst) {
-    gpr_slice_buffer_add(&t->qbuf,
-                         grpc_chttp2_rst_stream_create(id, error_code));
-  }
-  if (optional_message) {
-    grpc_mdstr_unref(optional_message);
-  }
-}
-
-static void cancel_stream_id(transport *t, gpr_uint32 id,
-                             grpc_status_code local_status,
-                             grpc_chttp2_error_code error_code, int send_rst) {
-  cancel_stream_inner(t, lookup_stream(t, id), id, local_status, error_code,
-                      NULL, send_rst);
-}
-
-static void cancel_stream(transport *t, stream *s,
-                          grpc_status_code local_status,
-                          grpc_chttp2_error_code error_code,
-                          grpc_mdstr *optional_message, int send_rst) {
-  cancel_stream_inner(t, s, s->id, local_status, error_code, optional_message,
-                      send_rst);
-}
-
-static void cancel_stream_cb(void *user_data, gpr_uint32 id, void *stream) {
-  cancel_stream(user_data, stream, GRPC_STATUS_UNAVAILABLE,
-                GRPC_CHTTP2_INTERNAL_ERROR, NULL, 0);
-}
-
-static void end_all_the_calls(transport *t) {
-  grpc_chttp2_stream_map_for_each(&t->stream_map, cancel_stream_cb, t);
-}
-
-static void drop_connection(transport *t) {
-  if (t->error_state == ERROR_STATE_NONE) {
-    t->error_state = ERROR_STATE_SEEN;
-  }
-  end_all_the_calls(t);
-}
-
-static void maybe_finish_read(transport *t, stream *s) {
-  if (s->incoming_sopb) {
-    stream_list_join(t, s, FINISHED_READ_OP);
-  }
-}
-
-static void maybe_join_window_updates(transport *t, stream *s) {
-  if (s->incoming_sopb != NULL &&
-      s->incoming_window <
-          t->settings[LOCAL_SETTINGS]
-                     [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] *
-              3 / 4) {
-    stream_list_join(t, s, WINDOW_UPDATE);
-  }
-}
-
-static grpc_chttp2_parse_error update_incoming_window(transport *t, stream *s) {
-  if (t->incoming_frame_size > t->incoming_window) {
-    gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
-            t->incoming_frame_size, t->incoming_window);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-
-  if (t->incoming_frame_size > s->incoming_window) {
-    gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
-            t->incoming_frame_size, s->incoming_window);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-
-  FLOWCTL_TRACE(t, t, incoming, 0, -(gpr_int64)t->incoming_frame_size);
-  FLOWCTL_TRACE(t, s, incoming, s->id, -(gpr_int64)t->incoming_frame_size);
-  t->incoming_window -= t->incoming_frame_size;
-  s->incoming_window -= t->incoming_frame_size;
-
-  /* if the stream incoming window is getting low, schedule an update */
-  maybe_join_window_updates(t, s);
-
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-static stream *lookup_stream(transport *t, gpr_uint32 id) {
-  return grpc_chttp2_stream_map_find(&t->stream_map, id);
-}
-
-static grpc_chttp2_parse_error skip_parser(void *parser,
-                                           grpc_chttp2_parse_state *st,
-                                           gpr_slice slice, int is_last) {
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-static void skip_header(void *tp, grpc_mdelem *md) { grpc_mdelem_unref(md); }
-
-static int init_skip_frame(transport *t, int is_header) {
-  if (is_header) {
-    int is_eoh = t->expect_continuation_stream_id != 0;
-    t->parser = grpc_chttp2_header_parser_parse;
-    t->parser_data = &t->hpack_parser;
-    t->hpack_parser.on_header = skip_header;
-    t->hpack_parser.on_header_user_data = NULL;
-    t->hpack_parser.is_boundary = is_eoh;
-    t->hpack_parser.is_eof = is_eoh ? t->header_eof : 0;
-  } else {
-    t->parser = skip_parser;
-  }
-  return 1;
-}
-
-static void become_skip_parser(transport *t) {
-  init_skip_frame(t, t->parser == grpc_chttp2_header_parser_parse);
-}
-
-static int init_data_frame_parser(transport *t) {
-  stream *s = lookup_stream(t, t->incoming_stream_id);
-  grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK;
-  if (!s || s->read_closed) return init_skip_frame(t, 0);
-  if (err == GRPC_CHTTP2_PARSE_OK) {
-    err = update_incoming_window(t, s);
-  }
-  if (err == GRPC_CHTTP2_PARSE_OK) {
-    err = grpc_chttp2_data_parser_begin_frame(&s->parser,
-                                              t->incoming_frame_flags);
-  }
-  switch (err) {
-    case GRPC_CHTTP2_PARSE_OK:
-      t->incoming_stream = s;
-      t->parser = grpc_chttp2_data_parser_parse;
-      t->parser_data = &s->parser;
-      return 1;
-    case GRPC_CHTTP2_STREAM_ERROR:
-      cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
-                              GRPC_CHTTP2_INTERNAL_ERROR),
-                    GRPC_CHTTP2_INTERNAL_ERROR, NULL, 1);
-      return init_skip_frame(t, 0);
-    case GRPC_CHTTP2_CONNECTION_ERROR:
-      drop_connection(t);
-      return 0;
-  }
-  gpr_log(GPR_ERROR, "should never reach here");
-  abort();
-  return 0;
-}
-
-static void free_timeout(void *p) { gpr_free(p); }
-
-static void on_header(void *tp, grpc_mdelem *md) {
-  transport *t = tp;
-  stream *s = t->incoming_stream;
-
-  GPR_ASSERT(s);
-
-  IF_TRACING(gpr_log(
-      GPR_INFO, "HTTP:%d:%s:HDR: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
-      grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
-
-  if (md->key == t->str_grpc_timeout) {
-    gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
-    if (!cached_timeout) {
-      /* not already parsed: parse it now, and store the result away */
-      cached_timeout = gpr_malloc(sizeof(gpr_timespec));
-      if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
-                                      cached_timeout)) {
-        gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
-                grpc_mdstr_as_c_string(md->value));
-        *cached_timeout = gpr_inf_future;
-      }
-      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
-    }
-    s->incoming_deadline = gpr_time_add(gpr_now(), *cached_timeout);
-    grpc_mdelem_unref(md);
-  } else {
-    add_incoming_metadata(t, s, md);
-  }
-  maybe_finish_read(t, s);
-}
-
-static int init_header_frame_parser(transport *t, int is_continuation) {
-  int is_eoh =
-      (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
-  stream *s;
-
-  if (is_eoh) {
-    t->expect_continuation_stream_id = 0;
-  } else {
-    t->expect_continuation_stream_id = t->incoming_stream_id;
-  }
-
-  if (!is_continuation) {
-    t->header_eof =
-        (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
-  }
-
-  /* could be a new stream or an existing stream */
-  s = lookup_stream(t, t->incoming_stream_id);
-  if (!s) {
-    if (is_continuation) {
-      gpr_log(GPR_ERROR, "stream disbanded before CONTINUATION received");
-      return init_skip_frame(t, 1);
-    }
-    if (t->is_client) {
-      if ((t->incoming_stream_id & 1) &&
-          t->incoming_stream_id < t->next_stream_id) {
-        /* this is an old (probably cancelled) stream */
-      } else {
-        gpr_log(GPR_ERROR, "ignoring new stream creation on client");
-      }
-      return init_skip_frame(t, 1);
-    } else if (t->last_incoming_stream_id > t->incoming_stream_id) {
-      gpr_log(GPR_ERROR,
-              "ignoring out of order new stream request on server; last stream "
-              "id=%d, new stream id=%d",
-              t->last_incoming_stream_id, t->incoming_stream_id);
-      return init_skip_frame(t, 1);
-    } else if ((t->incoming_stream_id & 1) == 0) {
-      gpr_log(GPR_ERROR, "ignoring stream with non-client generated index %d", t->incoming_stream_id);
-      return init_skip_frame(t, 1);
-    }
-    t->incoming_stream = NULL;
-    /* if stream is accepted, we set incoming_stream in init_stream */
-    t->cb->accept_stream(t->cb_user_data, &t->base,
-                         (void *)(gpr_uintptr)t->incoming_stream_id);
-    s = t->incoming_stream;
-    if (!s) {
-      gpr_log(GPR_ERROR, "stream not accepted");
-      return init_skip_frame(t, 1);
-    }
-  } else {
-    t->incoming_stream = s;
-  }
-  if (t->incoming_stream->read_closed) {
-    gpr_log(GPR_ERROR, "skipping already closed stream header");
-    t->incoming_stream = NULL;
-    return init_skip_frame(t, 1);
-  }
-  t->parser = grpc_chttp2_header_parser_parse;
-  t->parser_data = &t->hpack_parser;
-  t->hpack_parser.on_header = on_header;
-  t->hpack_parser.on_header_user_data = t;
-  t->hpack_parser.is_boundary = is_eoh;
-  t->hpack_parser.is_eof = is_eoh ? t->header_eof : 0;
-  if (!is_continuation &&
-      (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
-    grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser);
-  }
-  return 1;
-}
-
-static int init_window_update_frame_parser(transport *t) {
-  int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame(
-                                       &t->simple_parsers.window_update,
-                                       t->incoming_frame_size,
-                                       t->incoming_frame_flags);
-  if (!ok) {
-    drop_connection(t);
-  }
-  t->parser = grpc_chttp2_window_update_parser_parse;
-  t->parser_data = &t->simple_parsers.window_update;
-  return ok;
-}
-
-static int init_ping_parser(transport *t) {
-  int ok = GRPC_CHTTP2_PARSE_OK ==
-           grpc_chttp2_ping_parser_begin_frame(&t->simple_parsers.ping,
-                                               t->incoming_frame_size,
-                                               t->incoming_frame_flags);
-  if (!ok) {
-    drop_connection(t);
-  }
-  t->parser = grpc_chttp2_ping_parser_parse;
-  t->parser_data = &t->simple_parsers.ping;
-  return ok;
-}
-
-static int init_rst_stream_parser(transport *t) {
-  int ok = GRPC_CHTTP2_PARSE_OK ==
-           grpc_chttp2_rst_stream_parser_begin_frame(&t->simple_parsers.rst_stream,
-                                                     t->incoming_frame_size,
-                                                     t->incoming_frame_flags);
-  if (!ok) {
-    drop_connection(t);
-  }
-  t->parser = grpc_chttp2_rst_stream_parser_parse;
-  t->parser_data = &t->simple_parsers.rst_stream;
-  return ok;
-}
-
-static int init_goaway_parser(transport *t) {
-  int ok =
-      GRPC_CHTTP2_PARSE_OK ==
-      grpc_chttp2_goaway_parser_begin_frame(
-          &t->goaway_parser, t->incoming_frame_size, t->incoming_frame_flags);
-  if (!ok) {
-    drop_connection(t);
-  }
-  t->parser = grpc_chttp2_goaway_parser_parse;
-  t->parser_data = &t->goaway_parser;
-  return ok;
-}
-
-static int init_settings_frame_parser(transport *t) {
-  int ok;
-
-  if (t->incoming_stream_id != 0) {
-    gpr_log(GPR_ERROR, "settings frame received for stream %d", t->incoming_stream_id);
-    drop_connection(t);
-    return 0;
-  }
-
-  ok = GRPC_CHTTP2_PARSE_OK ==
-           grpc_chttp2_settings_parser_begin_frame(
-               &t->simple_parsers.settings, t->incoming_frame_size,
-               t->incoming_frame_flags, t->settings[PEER_SETTINGS]);
-  if (!ok) {
-    drop_connection(t);
-    return 0;
-  }
-  if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
-    memcpy(t->settings[ACKED_SETTINGS], t->settings[SENT_SETTINGS],
-           GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
-  }
-  t->parser = grpc_chttp2_settings_parser_parse;
-  t->parser_data = &t->simple_parsers.settings;
-  return ok;
-}
-
-static int init_frame_parser(transport *t) {
-  if (t->expect_continuation_stream_id != 0) {
-    if (t->incoming_frame_type != GRPC_CHTTP2_FRAME_CONTINUATION) {
-      gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x",
-              t->incoming_frame_type);
-      return 0;
-    }
-    if (t->expect_continuation_stream_id != t->incoming_stream_id) {
-      gpr_log(GPR_ERROR,
-              "Expected CONTINUATION frame for stream %08x, got stream %08x",
-              t->expect_continuation_stream_id, t->incoming_stream_id);
-      return 0;
-    }
-    return init_header_frame_parser(t, 1);
-  }
-  switch (t->incoming_frame_type) {
-    case GRPC_CHTTP2_FRAME_DATA:
-      return init_data_frame_parser(t);
-    case GRPC_CHTTP2_FRAME_HEADER:
-      return init_header_frame_parser(t, 0);
-    case GRPC_CHTTP2_FRAME_CONTINUATION:
-      gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame");
-      return 0;
-    case GRPC_CHTTP2_FRAME_RST_STREAM:
-      return init_rst_stream_parser(t);
-    case GRPC_CHTTP2_FRAME_SETTINGS:
-      return init_settings_frame_parser(t);
-    case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
-      return init_window_update_frame_parser(t);
-    case GRPC_CHTTP2_FRAME_PING:
-      return init_ping_parser(t);
-    case GRPC_CHTTP2_FRAME_GOAWAY:
-      return init_goaway_parser(t);
-    default:
-      gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type);
-      return init_skip_frame(t, 0);
-  }
-}
-
-static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
-  return window + window_update < MAX_WINDOW;
-}
-
-static void add_metadata_batch(transport *t, stream *s) {
-  grpc_metadata_batch b;
-
-  b.list.head = NULL;
-  /* Store away the last element of the list, so that in patch_metadata_ops
-     we can reconstitute the list.
-     We can't do list building here as later incoming metadata may reallocate
-     the underlying array. */
-  b.list.tail = (void*)(gpr_intptr)s->incoming_metadata_count;
-  b.garbage.head = b.garbage.tail = NULL;
-  b.deadline = s->incoming_deadline;
-  s->incoming_deadline = gpr_inf_future;
-
-  grpc_sopb_add_metadata(&s->parser.incoming_sopb, b);
-}
-
-static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
-  grpc_chttp2_parse_state st;
-  size_t i;
-  memset(&st, 0, sizeof(st));
-  switch (t->parser(t->parser_data, &st, slice, is_last)) {
-    case GRPC_CHTTP2_PARSE_OK:
-      if (st.end_of_stream) {
-        t->incoming_stream->read_closed = 1;
-        maybe_finish_read(t, t->incoming_stream);
-      }
-      if (st.need_flush_reads) {
-        maybe_finish_read(t, t->incoming_stream);
-      }
-      if (st.metadata_boundary) {
-        add_metadata_batch(t, t->incoming_stream);
-        maybe_finish_read(t, t->incoming_stream);
-      }
-      if (st.ack_settings) {
-        gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
-        maybe_start_some_streams(t);
-      }
-      if (st.send_ping_ack) {
-        gpr_slice_buffer_add(
-            &t->qbuf,
-            grpc_chttp2_ping_create(1, t->simple_parsers.ping.opaque_8bytes));
-      }
-      if (st.goaway) {
-        add_goaway(t, st.goaway_error, st.goaway_text);
-      }
-      if (st.rst_stream) {
-        cancel_stream_id(
-            t, t->incoming_stream_id,
-            grpc_chttp2_http2_error_to_grpc_status(st.rst_stream_reason),
-            st.rst_stream_reason, 0);
-      }
-      if (st.process_ping_reply) {
-        for (i = 0; i < t->ping_count; i++) {
-          if (0 ==
-              memcmp(t->pings[i].id, t->simple_parsers.ping.opaque_8bytes, 8)) {
-            t->pings[i].cb(t->pings[i].user_data);
-            memmove(&t->pings[i], &t->pings[i + 1],
-                    (t->ping_count - i - 1) * sizeof(outstanding_ping));
-            t->ping_count--;
-            break;
-          }
-        }
-      }
-      if (st.initial_window_update) {
-        for (i = 0; i < t->stream_map.count; i++) {
-          stream *s = (stream *)(t->stream_map.values[i]);
-          int was_window_empty = s->outgoing_window <= 0;
-          FLOWCTL_TRACE(t, s, outgoing, s->id, st.initial_window_update);
-          s->outgoing_window += st.initial_window_update;
-          if (was_window_empty && s->outgoing_window > 0 && s->outgoing_sopb &&
-              s->outgoing_sopb->nops > 0) {
-            stream_list_join(t, s, WRITABLE);
-          }
-        }
-      }
-      if (st.window_update) {
-        if (t->incoming_stream_id) {
-          /* if there was a stream id, this is for some stream */
-          stream *s = lookup_stream(t, t->incoming_stream_id);
-          if (s) {
-            int was_window_empty = s->outgoing_window <= 0;
-            if (!is_window_update_legal(st.window_update, s->outgoing_window)) {
-              cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
-                                      GRPC_CHTTP2_FLOW_CONTROL_ERROR),
-                            GRPC_CHTTP2_FLOW_CONTROL_ERROR, NULL, 1);
-            } else {
-              FLOWCTL_TRACE(t, s, outgoing, s->id, st.window_update);
-              s->outgoing_window += st.window_update;
-              /* if this window update makes outgoing ops writable again,
-                 flag that */
-              if (was_window_empty && s->outgoing_sopb &&
-                  s->outgoing_sopb->nops > 0) {
-                stream_list_join(t, s, WRITABLE);
-              }
-            }
-          }
-        } else {
-          /* transport level window update */
-          if (!is_window_update_legal(st.window_update, t->outgoing_window)) {
-            drop_connection(t);
-          } else {
-            FLOWCTL_TRACE(t, t, outgoing, 0, st.window_update);
-            t->outgoing_window += st.window_update;
-          }
-        }
-      }
-      return 1;
-    case GRPC_CHTTP2_STREAM_ERROR:
-      become_skip_parser(t);
-      cancel_stream_id(
-          t, t->incoming_stream_id,
-          grpc_chttp2_http2_error_to_grpc_status(GRPC_CHTTP2_INTERNAL_ERROR),
-          GRPC_CHTTP2_INTERNAL_ERROR, 1);
-      return 1;
-    case GRPC_CHTTP2_CONNECTION_ERROR:
-      drop_connection(t);
-      return 0;
-  }
-  gpr_log(GPR_ERROR, "should never reach here");
-  abort();
-  return 0;
-}
-
-static int process_read(transport *t, gpr_slice slice) {
-  gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
-  gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
-  gpr_uint8 *cur = beg;
-
-  if (cur == end) return 1;
-
-  switch (t->deframe_state) {
-    case DTS_CLIENT_PREFIX_0:
-    case DTS_CLIENT_PREFIX_1:
-    case DTS_CLIENT_PREFIX_2:
-    case DTS_CLIENT_PREFIX_3:
-    case DTS_CLIENT_PREFIX_4:
-    case DTS_CLIENT_PREFIX_5:
-    case DTS_CLIENT_PREFIX_6:
-    case DTS_CLIENT_PREFIX_7:
-    case DTS_CLIENT_PREFIX_8:
-    case DTS_CLIENT_PREFIX_9:
-    case DTS_CLIENT_PREFIX_10:
-    case DTS_CLIENT_PREFIX_11:
-    case DTS_CLIENT_PREFIX_12:
-    case DTS_CLIENT_PREFIX_13:
-    case DTS_CLIENT_PREFIX_14:
-    case DTS_CLIENT_PREFIX_15:
-    case DTS_CLIENT_PREFIX_16:
-    case DTS_CLIENT_PREFIX_17:
-    case DTS_CLIENT_PREFIX_18:
-    case DTS_CLIENT_PREFIX_19:
-    case DTS_CLIENT_PREFIX_20:
-    case DTS_CLIENT_PREFIX_21:
-    case DTS_CLIENT_PREFIX_22:
-    case DTS_CLIENT_PREFIX_23:
-      while (cur != end && t->deframe_state != DTS_FH_0) {
-        if (*cur != CLIENT_CONNECT_STRING[t->deframe_state]) {
-          gpr_log(GPR_ERROR,
-                  "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
-                  "at byte %d",
-                  CLIENT_CONNECT_STRING[t->deframe_state],
-                  (int)(gpr_uint8)CLIENT_CONNECT_STRING[t->deframe_state], *cur,
-                  (int)*cur, t->deframe_state);
-          drop_connection(t);
-          return 0;
-        }
-        ++cur;
-        ++t->deframe_state;
-      }
-      if (cur == end) {
-        return 1;
-      }
-    /* fallthrough */
-    dts_fh_0:
-    case DTS_FH_0:
-      GPR_ASSERT(cur < end);
-      t->incoming_frame_size = ((gpr_uint32)*cur) << 16;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_1;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_1:
-      GPR_ASSERT(cur < end);
-      t->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_2;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_2:
-      GPR_ASSERT(cur < end);
-      t->incoming_frame_size |= *cur;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_3;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_3:
-      GPR_ASSERT(cur < end);
-      t->incoming_frame_type = *cur;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_4;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_4:
-      GPR_ASSERT(cur < end);
-      t->incoming_frame_flags = *cur;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_5;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_5:
-      GPR_ASSERT(cur < end);
-      t->incoming_stream_id = (((gpr_uint32)*cur) & 0x7f) << 24;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_6;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_6:
-      GPR_ASSERT(cur < end);
-      t->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_7;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_7:
-      GPR_ASSERT(cur < end);
-      t->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
-      if (++cur == end) {
-        t->deframe_state = DTS_FH_8;
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FH_8:
-      GPR_ASSERT(cur < end);
-      t->incoming_stream_id |= ((gpr_uint32)*cur);
-      t->deframe_state = DTS_FRAME;
-      if (!init_frame_parser(t)) {
-        return 0;
-      }
-      /* t->last_incoming_stream_id is used as last-stream-id when
-         sending GOAWAY frame.
-         https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
-         says that last-stream-id is peer-initiated stream ID.  So,
-         since we don't have server pushed streams, client should send
-         GOAWAY last-stream-id=0 in this case. */
-      if (!t->is_client) {
-        t->last_incoming_stream_id = t->incoming_stream_id;
-      }
-      if (t->incoming_frame_size == 0) {
-        if (!parse_frame_slice(t, gpr_empty_slice(), 1)) {
-          return 0;
-        }
-        if (++cur == end) {
-          t->deframe_state = DTS_FH_0;
-          return 1;
-        }
-        goto dts_fh_0; /* loop */
-      }
-      if (++cur == end) {
-        return 1;
-      }
-    /* fallthrough */
-    case DTS_FRAME:
-      GPR_ASSERT(cur < end);
-      if ((gpr_uint32)(end - cur) == t->incoming_frame_size) {
-        if (!parse_frame_slice(
-                t, gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) {
-          return 0;
-        }
-        t->deframe_state = DTS_FH_0;
-        return 1;
-      } else if ((gpr_uint32)(end - cur) > t->incoming_frame_size) {
-        if (!parse_frame_slice(
-                t, gpr_slice_sub_no_ref(slice, cur - beg,
-                                        cur + t->incoming_frame_size - beg),
-                1)) {
-          return 0;
-        }
-        cur += t->incoming_frame_size;
-        goto dts_fh_0; /* loop */
-      } else {
-        if (!parse_frame_slice(
-                t, gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) {
-          return 0;
-        }
-        t->incoming_frame_size -= (end - cur);
-        return 1;
-      }
-      gpr_log(GPR_ERROR, "should never reach here");
-      abort();
-  }
-
-  gpr_log(GPR_ERROR, "should never reach here");
-  abort();
-
-  return 0;
-}
-
-/* tcp read callback */
-static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
-                      grpc_endpoint_cb_status error) {
-  transport *t = tp;
-  size_t i;
-  int keep_reading = 0;
-
-  switch (error) {
-    case GRPC_ENDPOINT_CB_SHUTDOWN:
-    case GRPC_ENDPOINT_CB_EOF:
-    case GRPC_ENDPOINT_CB_ERROR:
-      lock(t);
-      drop_connection(t);
-      t->reading = 0;
-      if (!t->writing && t->ep) {
-        grpc_endpoint_destroy(t->ep);
-        t->ep = NULL;
-        unref_transport(t); /* safe as we still have a ref for read */
-      }
-      unlock(t);
-      unref_transport(t);
-      break;
-    case GRPC_ENDPOINT_CB_OK:
-      lock(t);
-      if (t->cb) {
-        for (i = 0; i < nslices && process_read(t, slices[i]); i++)
-          ;
-      }
-      unlock(t);
-      keep_reading = 1;
-      break;
-  }
-
-  for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]);
-
-  if (keep_reading) {
-    grpc_endpoint_notify_on_read(t->ep, recv_data, t);
-  }
-}
-
-/*
- * CALLBACK LOOP
- */
-
 static grpc_stream_state compute_state(gpr_uint8 write_closed,
                                        gpr_uint8 read_closed) {
   if (write_closed && read_closed) return GRPC_STREAM_CLOSED;
@@ -2007,136 +743,326 @@
   return GRPC_STREAM_OPEN;
 }
 
-static void patch_metadata_ops(stream *s) {
-  grpc_stream_op *ops = s->incoming_sopb->ops;
-  size_t nops = s->incoming_sopb->nops;
-  size_t i;
-  size_t j;
-  size_t mdidx = 0;
-  size_t last_mdidx;
-  int found_metadata = 0;
-
-  /* rework the array of metadata into a linked list, making use
-     of the breadcrumbs we left in metadata batches during 
-     add_metadata_batch */
-  for (i = 0; i < nops; i++) {
-    grpc_stream_op *op = &ops[i];
-    if (op->type != GRPC_OP_METADATA) continue;
-    found_metadata = 1;
-    /* we left a breadcrumb indicating where the end of this list is,
-       and since we add sequentially, we know from the end of the last
-       segment where this segment begins */
-    last_mdidx = (size_t)(gpr_intptr)(op->data.metadata.list.tail);
-    GPR_ASSERT(last_mdidx > mdidx);
-    GPR_ASSERT(last_mdidx <= s->incoming_metadata_count);
-    /* turn the array into a doubly linked list */
-    op->data.metadata.list.head = &s->incoming_metadata[mdidx];
-    op->data.metadata.list.tail = &s->incoming_metadata[last_mdidx - 1];
-    for (j = mdidx + 1; j < last_mdidx; j++) {
-      s->incoming_metadata[j].prev = &s->incoming_metadata[j-1];
-      s->incoming_metadata[j-1].next = &s->incoming_metadata[j];
-    }
-    s->incoming_metadata[mdidx].prev = NULL;
-    s->incoming_metadata[last_mdidx-1].next = NULL;
-    /* track where we're up to */
-    mdidx = last_mdidx;
+static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
+  size_t new_stream_count;
+  grpc_chttp2_stream *s =
+      grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
+  if (!s) {
+    s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
   }
-  if (found_metadata) {
-    s->old_incoming_metadata = s->incoming_metadata;
-    if (mdidx != s->incoming_metadata_count) {
-      /* we have a partially read metadata batch still in incoming_metadata */
-      size_t new_count = s->incoming_metadata_count - mdidx;
-      size_t copy_bytes = sizeof(*s->incoming_metadata) * new_count;
-      GPR_ASSERT(mdidx < s->incoming_metadata_count);
-      s->incoming_metadata = gpr_malloc(copy_bytes);
-      memcpy(s->old_incoming_metadata + mdidx, s->incoming_metadata, copy_bytes);
-      s->incoming_metadata_count = s->incoming_metadata_capacity = new_count;
-    } else {
-      s->incoming_metadata = NULL;
-      s->incoming_metadata_count = 0;
-      s->incoming_metadata_capacity = 0;
-    }
+  GPR_ASSERT(s);
+  s->global.in_stream_map = 0;
+  if (t->parsing.incoming_stream == &s->parsing) {
+    t->parsing.incoming_stream = NULL;
+    grpc_chttp2_parsing_become_skip_parser(&t->parsing);
+  }
+  if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
+    close_transport_locked(t);
+  }
+
+  new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
+                     grpc_chttp2_stream_map_size(&t->new_stream_map);
+  if (new_stream_count != t->global.concurrent_stream_count) {
+    t->global.concurrent_stream_count = new_stream_count;
+    maybe_start_some_streams(&t->global);
   }
 }
 
-static void finish_reads(transport *t) {
-  stream *s;
+static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
+  grpc_chttp2_transport_global *transport_global = &t->global;
+  grpc_chttp2_stream_global *stream_global;
+  grpc_stream_state state;
 
-  while ((s = stream_list_remove_head(t, FINISHED_READ_OP)) != NULL) {
-    int publish = 0;
-    GPR_ASSERT(s->incoming_sopb);
-    *s->publish_state =
-        compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, s->read_closed);
-    if (*s->publish_state != s->published_state) {
-      s->published_state = *s->publish_state;
-      publish = 1;
-      if (s->published_state == GRPC_STREAM_CLOSED) {
-        remove_from_stream_map(t, s);
+  if (!t->parsing_active) {
+    /* if a stream is in the stream map, and gets cancelled, we need to ensure
+       we are not parsing before continuing the cancellation to keep things in
+       a sane state */
+    while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
+                                                           &stream_global)) {
+      GPR_ASSERT(stream_global->in_stream_map);
+      GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN);
+      GPR_ASSERT(stream_global->read_closed);
+      remove_stream(t, stream_global->id);
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+    }
+  }
+
+  if (!t->writing_active) {
+    while (grpc_chttp2_list_pop_cancelled_waiting_for_writing(transport_global,
+                                                              &stream_global)) {
+      grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                    stream_global);
+    }
+  }
+
+  while (grpc_chttp2_list_pop_read_write_state_changed(transport_global,
+                                                       &stream_global)) {
+    if (stream_global->cancelled) {
+      if (t->writing_active &&
+          stream_global->write_state != GRPC_WRITE_STATE_SENT_CLOSE) {
+        grpc_chttp2_list_add_cancelled_waiting_for_writing(transport_global,
+                                                           stream_global);
+      } else {
+        stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
+        stream_global->read_closed = 1;
+        if (!stream_global->published_cancelled) {
+          char buffer[GPR_LTOA_MIN_BUFSIZE];
+          gpr_ltoa(stream_global->cancelled_status, buffer);
+          grpc_chttp2_incoming_metadata_buffer_add(
+              &stream_global->incoming_metadata,
+              grpc_mdelem_from_strings(t->metadata_context, "grpc-status",
+                                       buffer));
+          grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
+              &stream_global->incoming_metadata, &stream_global->incoming_sopb);
+          stream_global->published_cancelled = 1;
+        }
       }
     }
-    if (s->parser.incoming_sopb.nops > 0) {
-      grpc_sopb_swap(s->incoming_sopb, &s->parser.incoming_sopb);
-      publish = 1;
-    }
-    if (publish) {
-      if (s->incoming_metadata_count > 0) {
-        patch_metadata_ops(s);
+    if (stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
+        stream_global->read_closed && stream_global->in_stream_map) {
+      if (t->parsing_active) {
+        grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
+                                                        stream_global);
+      } else {
+        remove_stream(t, stream_global->id);
       }
-      s->incoming_sopb = NULL;
-      schedule_cb(t, s->recv_done_closure, 1);
     }
+    if (!stream_global->publish_sopb) {
+      continue;
+    }
+    /* FIXME(ctiller): we include in_stream_map in our computation of
+       whether the stream is write-closed. This is completely bogus,
+       but has the effect of delaying stream-closed until the stream
+       is indeed evicted from the stream map, making it safe to delete.
+       To fix this will require having an edge after stream-closed
+       indicating that the stream is closed AND safe to delete. */
+    state = compute_state(
+        stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
+            !stream_global->in_stream_map,
+        stream_global->read_closed);
+    if (stream_global->incoming_sopb.nops == 0 &&
+        state == stream_global->published_state) {
+      continue;
+    }
+    grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
+        &stream_global->incoming_metadata, &stream_global->incoming_sopb,
+        &stream_global->outstanding_metadata);
+    grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb);
+    stream_global->published_state = *stream_global->publish_state = state;
+    grpc_chttp2_schedule_closure(transport_global,
+                                 stream_global->recv_done_closure, 1);
+    stream_global->recv_done_closure = NULL;
+    stream_global->publish_sopb = NULL;
+    stream_global->publish_state = NULL;
   }
-
 }
 
-static void schedule_cb(transport *t, op_closure closure, int success) {
-  if (t->pending_callbacks.capacity == t->pending_callbacks.count) {
-    t->pending_callbacks.capacity =
-        GPR_MAX(t->pending_callbacks.capacity * 2, 8);
-    t->pending_callbacks.callbacks =
-        gpr_realloc(t->pending_callbacks.callbacks,
-                    t->pending_callbacks.capacity *
-                        sizeof(*t->pending_callbacks.callbacks));
+static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
+                            grpc_chttp2_stream_global *stream_global,
+                            grpc_status_code status) {
+  stream_global->cancelled = 1;
+  stream_global->cancelled_status = status;
+  if (stream_global->id != 0) {
+    gpr_slice_buffer_add(
+        &transport_global->qbuf,
+        grpc_chttp2_rst_stream_create(
+            stream_global->id, grpc_chttp2_grpc_status_to_http2_error(status)));
   }
-  closure.success = success;
-  t->pending_callbacks.callbacks[t->pending_callbacks.count++] = closure;
+  grpc_chttp2_list_add_read_write_state_changed(transport_global,
+                                                stream_global);
 }
 
-static int prepare_callbacks(transport *t) {
-  op_closure_array temp = t->pending_callbacks;
-  t->pending_callbacks = t->executing_callbacks;
-  t->executing_callbacks = temp;
-  return t->executing_callbacks.count > 0;
+static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
+                             void *user_data,
+                             grpc_chttp2_stream_global *stream_global) {
+  cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
 }
 
-static void run_callbacks(transport *t) {
+static void end_all_the_calls(grpc_chttp2_transport *t) {
+  grpc_chttp2_for_all_streams(&t->global, NULL, cancel_stream_cb);
+}
+
+static void drop_connection(grpc_chttp2_transport *t) {
+  close_transport_locked(t);
+  end_all_the_calls(t);
+}
+
+/** update window from a settings change */
+static void update_global_window(void *args, gpr_uint32 id, void *stream) {
+  grpc_chttp2_transport *t = args;
+  grpc_chttp2_stream *s = stream;
+  grpc_chttp2_transport_global *transport_global = &t->global;
+  grpc_chttp2_stream_global *stream_global = &s->global;
+  int was_zero;
+  int is_zero;
+
+  GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global,
+                                   outgoing_window,
+                                   t->parsing.initial_window_update);
+  was_zero = stream_global->outgoing_window <= 0;
+  stream_global->outgoing_window += t->parsing.initial_window_update;
+  is_zero = stream_global->outgoing_window <= 0;
+
+  if (was_zero && !is_zero) {
+    grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
+  }
+}
+
+static void read_error_locked(grpc_chttp2_transport *t) {
+  t->endpoint_reading = 0;
+  if (!t->writing_active && t->ep) {
+    grpc_endpoint_destroy(t->ep);
+    t->ep = NULL;
+    /* safe as we still have a ref for read */
+    UNREF_TRANSPORT(t, "disconnect");
+  }
+}
+
+/* tcp read callback */
+static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
+                      grpc_endpoint_cb_status error) {
+  grpc_chttp2_transport *t = tp;
   size_t i;
-  for (i = 0; i < t->executing_callbacks.count; i++) {
-    op_closure c = t->executing_callbacks.callbacks[i];
-    c.cb(c.user_data, c.success);
+  int unref = 0;
+
+  switch (error) {
+    case GRPC_ENDPOINT_CB_SHUTDOWN:
+    case GRPC_ENDPOINT_CB_EOF:
+    case GRPC_ENDPOINT_CB_ERROR:
+      lock(t);
+      drop_connection(t);
+      read_error_locked(t);
+      unlock(t);
+      unref = 1;
+      for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]);
+      break;
+    case GRPC_ENDPOINT_CB_OK:
+      lock(t);
+      i = 0;
+      GPR_ASSERT(!t->parsing_active);
+      if (!t->closed) {
+        t->parsing_active = 1;
+        /* merge stream lists */
+        grpc_chttp2_stream_map_move_into(&t->new_stream_map,
+                                         &t->parsing_stream_map);
+        grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
+        gpr_mu_unlock(&t->mu);
+        for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]);
+             i++) {
+          gpr_slice_unref(slices[i]);
+        }
+        gpr_mu_lock(&t->mu);
+        if (i != nslices) {
+          drop_connection(t);
+        }
+        /* merge stream lists */
+        grpc_chttp2_stream_map_move_into(&t->new_stream_map,
+                                         &t->parsing_stream_map);
+        t->global.concurrent_stream_count =
+            grpc_chttp2_stream_map_size(&t->parsing_stream_map);
+        if (t->parsing.initial_window_update != 0) {
+          grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
+                                          update_global_window, t);
+          t->parsing.initial_window_update = 0;
+        }
+        /* handle higher level things */
+        grpc_chttp2_publish_reads(&t->global, &t->parsing);
+        t->parsing_active = 0;
+      }
+      if (i == nslices) {
+        grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1);
+      } else {
+        read_error_locked(t);
+        unref = 1;
+      }
+      unlock(t);
+      for (; i < nslices; i++) gpr_slice_unref(slices[i]);
+      break;
   }
-  t->executing_callbacks.count = 0;
+  if (unref) {
+    UNREF_TRANSPORT(t, "recv_data");
+  }
 }
 
-static void call_cb_closed(transport *t, const grpc_transport_callbacks *cb) {
-  cb->closed(t->cb_user_data, &t->base);
+static void reading_action(void *pt, int iomgr_success_ignored) {
+  grpc_chttp2_transport *t = pt;
+  grpc_endpoint_notify_on_read(t->ep, recv_data, t);
+}
+
+/*
+ * CALLBACK LOOP
+ */
+
+static void schedule_closure_for_connectivity(void *a,
+                                              grpc_iomgr_closure *closure) {
+  grpc_chttp2_schedule_closure(a, closure, 1);
+}
+
+static void connectivity_state_set(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_connectivity_state state) {
+  GRPC_CHTTP2_IF_TRACING(
+      gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
+  grpc_connectivity_state_set_with_scheduler(
+      &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
+      state, schedule_closure_for_connectivity, transport_global);
+}
+
+void grpc_chttp2_schedule_closure(
+    grpc_chttp2_transport_global *transport_global, grpc_iomgr_closure *closure,
+    int success) {
+  closure->success = success;
+  if (transport_global->pending_closures_tail == NULL) {
+    transport_global->pending_closures_head =
+        transport_global->pending_closures_tail = closure;
+  } else {
+    transport_global->pending_closures_tail->next = closure;
+    transport_global->pending_closures_tail = closure;
+  }
+  closure->next = NULL;
 }
 
 /*
  * POLLSET STUFF
  */
 
-static void add_to_pollset_locked(transport *t, grpc_pollset *pollset) {
+static void add_to_pollset_locked(grpc_chttp2_transport *t,
+                                  grpc_pollset *pollset) {
   if (t->ep) {
     grpc_endpoint_add_to_pollset(t->ep, pollset);
   }
 }
 
-static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) {
-  transport *t = (transport *)gt;
-  lock(t);
-  add_to_pollset_locked(t, pollset);
-  unlock(t);
+/*
+ * TRACING
+ */
+
+void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason,
+                               const char *context, const char *var,
+                               int is_client, gpr_uint32 stream_id,
+                               gpr_int64 current_value, gpr_int64 delta) {
+  char *identifier;
+  char *context_scope;
+  char *context_thread;
+  char *underscore_pos = strchr(context, '_');
+  GPR_ASSERT(underscore_pos);
+  context_thread = gpr_strdup(underscore_pos + 1);
+  context_scope = gpr_strdup(context);
+  context_scope[underscore_pos - context] = 0;
+  if (stream_id) {
+    gpr_asprintf(&identifier, "%s[%d]", context_scope, stream_id);
+  } else {
+    identifier = gpr_strdup(context_scope);
+  }
+  gpr_log(GPR_INFO,
+          "FLOWCTL: %s %-10s %8s %-27s %8lld %c %8lld = %8lld %-10s [%s:%d]",
+          is_client ? "client" : "server", identifier, context_thread, var,
+          current_value, delta < 0 ? '-' : '+', delta < 0 ? -delta : delta,
+          current_value + delta, reason, file, line);
+  gpr_free(identifier);
+  gpr_free(context_thread);
+  gpr_free(context_scope);
 }
 
 /*
@@ -2144,17 +1070,20 @@
  */
 
 static const grpc_transport_vtable vtable = {
-    sizeof(stream),  init_stream,    perform_op,
-    add_to_pollset,  destroy_stream, goaway,
-    close_transport, send_ping,      destroy_transport};
+    sizeof(grpc_chttp2_stream), init_stream,    perform_stream_op,
+    perform_transport_op,       destroy_stream, destroy_transport};
 
-void grpc_create_chttp2_transport(grpc_transport_setup_callback setup,
-                                  void *arg,
-                                  const grpc_channel_args *channel_args,
-                                  grpc_endpoint *ep, gpr_slice *slices,
-                                  size_t nslices, grpc_mdctx *mdctx,
-                                  int is_client) {
-  transport *t = gpr_malloc(sizeof(transport));
-  init_transport(t, setup, arg, channel_args, ep, slices, nslices, mdctx,
-                 is_client);
+grpc_transport *grpc_create_chttp2_transport(
+    const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *mdctx,
+    int is_client) {
+  grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
+  init_transport(t, channel_args, ep, mdctx, is_client);
+  return &t->base;
+}
+
+void grpc_chttp2_transport_start_reading(grpc_transport *transport,
+                                         gpr_slice *slices, size_t nslices) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
+  REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
+  recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
 }
diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
index fad714f..fa0d6e4 100644
--- a/src/core/transport/chttp2_transport.h
+++ b/src/core/transport/chttp2_transport.h
@@ -40,11 +40,11 @@
 extern int grpc_http_trace;
 extern int grpc_flowctl_trace;
 
-void grpc_create_chttp2_transport(grpc_transport_setup_callback setup,
-                                  void *arg,
-                                  const grpc_channel_args *channel_args,
-                                  grpc_endpoint *ep, gpr_slice *slices,
-                                  size_t nslices, grpc_mdctx *metadata_context,
-                                  int is_client);
+grpc_transport *grpc_create_chttp2_transport(
+    const grpc_channel_args *channel_args, grpc_endpoint *ep,
+    grpc_mdctx *metadata_context, int is_client);
 
-#endif  /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H */
+void grpc_chttp2_transport_start_reading(grpc_transport *transport,
+                                         gpr_slice *slices, size_t nslices);
+
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/src/core/transport/connectivity_state.c b/src/core/transport/connectivity_state.c
new file mode 100644
index 0000000..1091cea
--- /dev/null
+++ b/src/core/transport/connectivity_state.c
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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/transport/connectivity_state.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
+                                  grpc_connectivity_state init_state) {
+  tracker->current_state = init_state;
+  tracker->watchers = NULL;
+}
+
+void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) {
+  grpc_connectivity_state_watcher *w;
+  while ((w = tracker->watchers)) {
+    tracker->watchers = w->next;
+
+    if (GRPC_CHANNEL_FATAL_FAILURE != *w->current) {
+      *w->current = GRPC_CHANNEL_FATAL_FAILURE;
+      grpc_iomgr_add_callback(w->notify);
+    } else {
+      grpc_iomgr_add_delayed_callback(w->notify, 0);
+    }
+    gpr_free(w);
+  }
+}
+
+grpc_connectivity_state grpc_connectivity_state_check(
+    grpc_connectivity_state_tracker *tracker) {
+  return tracker->current_state;
+}
+
+int grpc_connectivity_state_notify_on_state_change(
+    grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current,
+    grpc_iomgr_closure *notify) {
+  if (tracker->current_state != *current) {
+    *current = tracker->current_state;
+    grpc_iomgr_add_callback(notify);
+  } else {
+    grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
+    w->current = current;
+    w->notify = notify;
+    w->next = tracker->watchers;
+    tracker->watchers = w;
+  }
+  return tracker->current_state == GRPC_CHANNEL_IDLE;
+}
+
+void grpc_connectivity_state_set_with_scheduler(
+    grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state,
+    void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg) {
+  grpc_connectivity_state_watcher *new = NULL;
+  grpc_connectivity_state_watcher *w;
+  if (tracker->current_state == state) {
+    return;
+  }
+  tracker->current_state = state;
+  while ((w = tracker->watchers)) {
+    tracker->watchers = w->next;
+
+    if (state != *w->current) {
+      *w->current = state;
+      scheduler(arg, w->notify);
+      gpr_free(w);
+    } else {
+      w->next = new;
+      new = w;
+    }
+  }
+  tracker->watchers = new;
+}
+
+static void default_scheduler(void *ignored, grpc_iomgr_closure *closure) {
+  grpc_iomgr_add_callback(closure);
+}
+
+void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker,
+                                 grpc_connectivity_state state) {
+  grpc_connectivity_state_set_with_scheduler(tracker, state, default_scheduler,
+                                             NULL);
+}
diff --git a/src/core/transport/connectivity_state.h b/src/core/transport/connectivity_state.h
new file mode 100644
index 0000000..bbdcbcb
--- /dev/null
+++ b/src/core/transport/connectivity_state.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * 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_TRANSPORT_CONNECTIVITY_STATE_H
+#define GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H
+
+#include <grpc/grpc.h>
+#include "src/core/iomgr/iomgr.h"
+
+typedef struct grpc_connectivity_state_watcher {
+  /** we keep watchers in a linked list */
+  struct grpc_connectivity_state_watcher *next;
+  /** closure to notify on change */
+  grpc_iomgr_closure *notify;
+  /** the current state as believed by the watcher */
+  grpc_connectivity_state *current;
+} grpc_connectivity_state_watcher;
+
+typedef struct {
+  /** current connectivity state */
+  grpc_connectivity_state current_state;
+  /** all our watchers */
+  grpc_connectivity_state_watcher *watchers;
+} grpc_connectivity_state_tracker;
+
+void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
+                                  grpc_connectivity_state init_state);
+void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker);
+
+void grpc_connectivity_state_set(grpc_connectivity_state_tracker *tracker,
+                                 grpc_connectivity_state state);
+void grpc_connectivity_state_set_with_scheduler(
+    grpc_connectivity_state_tracker *tracker, grpc_connectivity_state state,
+    void (*scheduler)(void *arg, grpc_iomgr_closure *closure), void *arg);
+
+grpc_connectivity_state grpc_connectivity_state_check(
+    grpc_connectivity_state_tracker *tracker);
+
+/** Return 1 if the channel should start connecting, 0 otherwise */
+int grpc_connectivity_state_notify_on_state_change(
+    grpc_connectivity_state_tracker *tracker, grpc_connectivity_state *current,
+    grpc_iomgr_closure *notify);
+
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index e75b449..e95b7a2 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -48,6 +48,20 @@
 #define INITIAL_STRTAB_CAPACITY 4
 #define INITIAL_MDTAB_CAPACITY 4
 
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+#define DEBUG_ARGS , const char *file, int line
+#define FWD_DEBUG_ARGS , file, line
+#define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__)
+#define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__)
+#define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__)
+#else
+#define DEBUG_ARGS
+#define FWD_DEBUG_ARGS
+#define INTERNAL_STRING_REF(s) internal_string_ref((s))
+#define INTERNAL_STRING_UNREF(s) internal_string_unref((s))
+#define REF_MD_LOCKED(s) ref_md_locked((s))
+#endif
+
 typedef struct internal_string {
   /* must be byte compatible with grpc_mdstr */
   gpr_slice slice;
@@ -73,6 +87,7 @@
   gpr_atm refcnt;
 
   /* private only data */
+  gpr_mu mu_user_data;
   void *user_data;
   void (*destroy_user_data)(void *user_data);
 
@@ -96,8 +111,8 @@
   size_t mdtab_capacity;
 };
 
-static void internal_string_ref(internal_string *s);
-static void internal_string_unref(internal_string *s);
+static void internal_string_ref(internal_string *s DEBUG_ARGS);
+static void internal_string_unref(internal_string *s DEBUG_ARGS);
 static void discard_metadata(grpc_mdctx *ctx);
 static void gc_mdtab(grpc_mdctx *ctx);
 static void metadata_context_destroy_locked(grpc_mdctx *ctx);
@@ -120,7 +135,7 @@
   if (ctx->refs == 0) {
     /* uncomment if you're having trouble diagnosing an mdelem leak to make
        things clearer (slows down destruction a lot, however) */
-    /* gc_mdtab(ctx); */
+    gc_mdtab(ctx);
     if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
       discard_metadata(ctx);
     }
@@ -132,7 +147,15 @@
   gpr_mu_unlock(&ctx->mu);
 }
 
-static void ref_md_locked(internal_metadata *md) {
+static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
+          gpr_atm_no_barrier_load(&md->refcnt),
+          gpr_atm_no_barrier_load(&md->refcnt) + 1,
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+#endif
   if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
     md->context->mdtab_free--;
   }
@@ -161,7 +184,7 @@
   /* This seed is used to prevent remote connections from controlling hash table
    * collisions. It needs to be somewhat unpredictable to a remote connection.
    */
-  return grpc_mdctx_create_with_seed(gpr_now().tv_nsec);
+  return grpc_mdctx_create_with_seed(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
 }
 
 static void discard_metadata(grpc_mdctx *ctx) {
@@ -173,11 +196,12 @@
     while (cur) {
       GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0);
       next = cur->bucket_next;
-      internal_string_unref(cur->key);
-      internal_string_unref(cur->value);
+      INTERNAL_STRING_UNREF(cur->key);
+      INTERNAL_STRING_UNREF(cur->value);
       if (cur->user_data) {
         cur->destroy_user_data(cur->user_data);
       }
+      gpr_mu_destroy(&cur->mu_user_data);
       gpr_free(cur);
       cur = next;
       ctx->mdtab_free--;
@@ -248,9 +272,19 @@
   gpr_free(is);
 }
 
-static void internal_string_ref(internal_string *s) { ++s->refs; }
+static void internal_string_ref(internal_string *s DEBUG_ARGS) {
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR   REF:%p:%d->%d: '%s'", s,
+          s->refs, s->refs + 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
+#endif
+  ++s->refs;
+}
 
-static void internal_string_unref(internal_string *s) {
+static void internal_string_unref(internal_string *s DEBUG_ARGS) {
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%d->%d: '%s'", s,
+          s->refs, s->refs - 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
+#endif
   GPR_ASSERT(s->refs > 0);
   if (0 == --s->refs) {
     internal_destroy_string(s);
@@ -262,7 +296,7 @@
       (internal_string *)((char *)p - offsetof(internal_string, refcount));
   grpc_mdctx *ctx = is->context;
   lock(ctx);
-  internal_string_ref(is);
+  INTERNAL_STRING_REF(is);
   unlock(ctx);
 }
 
@@ -271,7 +305,7 @@
       (internal_string *)((char *)p - offsetof(internal_string, refcount));
   grpc_mdctx *ctx = is->context;
   lock(ctx);
-  internal_string_unref(is);
+  INTERNAL_STRING_UNREF(is);
   unlock(ctx);
 }
 
@@ -297,7 +331,7 @@
   for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) {
     if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
         0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
-      internal_string_ref(s);
+      INTERNAL_STRING_REF(s);
       unlock(ctx);
       return (grpc_mdstr *)s;
     }
@@ -353,8 +387,8 @@
     for (md = ctx->mdtab[i]; md; md = next) {
       next = md->bucket_next;
       if (gpr_atm_acq_load(&md->refcnt) == 0) {
-        internal_string_unref(md->key);
-        internal_string_unref(md->value);
+        INTERNAL_STRING_UNREF(md->key);
+        INTERNAL_STRING_UNREF(md->value);
         if (md->user_data) {
           md->destroy_user_data(md->user_data);
         }
@@ -418,9 +452,9 @@
   /* search for an existing pair */
   for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
     if (md->key == key && md->value == value) {
-      ref_md_locked(md);
-      internal_string_unref(key);
-      internal_string_unref(value);
+      REF_MD_LOCKED(md);
+      INTERNAL_STRING_UNREF(key);
+      INTERNAL_STRING_UNREF(value);
       unlock(ctx);
       return (grpc_mdelem *)md;
     }
@@ -435,6 +469,13 @@
   md->user_data = NULL;
   md->destroy_user_data = NULL;
   md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
+  gpr_mu_init(&md->mu_user_data);
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(GPR_DEBUG, "ELM   NEW:%p:%d: '%s' = '%s'", md,
+          gpr_atm_no_barrier_load(&md->refcnt),
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+#endif
   ctx->mdtab[hash % ctx->mdtab_capacity] = md;
   ctx->mdtab_count++;
 
@@ -469,8 +510,16 @@
       grpc_mdstr_from_buffer(ctx, value, value_length));
 }
 
-grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd) {
+grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
   internal_metadata *md = (internal_metadata *)gmd;
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
+          gpr_atm_no_barrier_load(&md->refcnt),
+          gpr_atm_no_barrier_load(&md->refcnt) + 1,
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+#endif
   /* we can assume the ref count is >= 1 as the application is calling
      this function - meaning that no adjustment to mdtab_free is necessary,
      simplifying the logic here to be just an atomic increment */
@@ -480,10 +529,18 @@
   return gmd;
 }
 
-void grpc_mdelem_unref(grpc_mdelem *gmd) {
+void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
   internal_metadata *md = (internal_metadata *)gmd;
   grpc_mdctx *ctx = md->context;
   lock(ctx);
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
+          gpr_atm_no_barrier_load(&md->refcnt),
+          gpr_atm_no_barrier_load(&md->refcnt) - 1,
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+#endif
   assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
   if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     ctx->mdtab_free++;
@@ -495,20 +552,20 @@
   return (const char *)GPR_SLICE_START_PTR(s->slice);
 }
 
-grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs) {
+grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
   internal_string *s = (internal_string *)gs;
   grpc_mdctx *ctx = s->context;
   lock(ctx);
-  internal_string_ref(s);
+  internal_string_ref(s FWD_DEBUG_ARGS);
   unlock(ctx);
   return gs;
 }
 
-void grpc_mdstr_unref(grpc_mdstr *gs) {
+void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
   internal_string *s = (internal_string *)gs;
   grpc_mdctx *ctx = s->context;
   lock(ctx);
-  internal_string_unref(s);
+  internal_string_unref(s FWD_DEBUG_ARGS);
   unlock(ctx);
 }
 
@@ -527,18 +584,29 @@
 void *grpc_mdelem_get_user_data(grpc_mdelem *md,
                                 void (*if_destroy_func)(void *)) {
   internal_metadata *im = (internal_metadata *)md;
-  return im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
+  void *result;
+  gpr_mu_lock(&im->mu_user_data);
+  result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
+  gpr_mu_unlock(&im->mu_user_data);
+  return result;
 }
 
 void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
                                void *user_data) {
   internal_metadata *im = (internal_metadata *)md;
   GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
+  gpr_mu_lock(&im->mu_user_data);
   if (im->destroy_user_data) {
-    im->destroy_user_data(im->user_data);
+    /* user data can only be set once */
+    gpr_mu_unlock(&im->mu_user_data);
+    if (destroy_func != NULL) {
+      destroy_func(user_data);
+    }
+    return;
   }
   im->destroy_user_data = destroy_func;
   im->user_data = user_data;
+  gpr_mu_unlock(&im->mu_user_data);
 }
 
 gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
@@ -558,10 +626,19 @@
 
 void grpc_mdctx_lock(grpc_mdctx *ctx) { lock(ctx); }
 
-void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *gmd) {
+void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx,
+                                    grpc_mdelem *gmd DEBUG_ARGS) {
   internal_metadata *md = (internal_metadata *)gmd;
   grpc_mdctx *elem_ctx = md->context;
   GPR_ASSERT(ctx == elem_ctx);
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
+          gpr_atm_no_barrier_load(&md->refcnt),
+          gpr_atm_no_barrier_load(&md->refcnt) - 1,
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
+          grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
+#endif
   assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
   if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     ctx->mdtab_free++;
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 76e3f3c..99b1532 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -127,11 +127,25 @@
                                void *user_data);
 
 /* Reference counting */
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__)
+#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s), __FILE__, __LINE__)
+#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__)
+#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__)
+grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line);
+void grpc_mdstr_unref(grpc_mdstr *s, const char *file, int line);
+grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line);
+void grpc_mdelem_unref(grpc_mdelem *md, const char *file, int line);
+#else
+#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s))
+#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s))
+#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s))
+#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s))
 grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s);
 void grpc_mdstr_unref(grpc_mdstr *s);
-
 grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md);
 void grpc_mdelem_unref(grpc_mdelem *md);
+#endif
 
 /* Recover a char* from a grpc_mdstr. The returned string is null terminated.
    Does not promise that the returned string has no embedded nulls however. */
@@ -147,8 +161,18 @@
 /* Lock the metadata context: it's only safe to call _locked_ functions against
    this context from the calling thread until grpc_mdctx_unlock is called */
 void grpc_mdctx_lock(grpc_mdctx *ctx);
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+#define GRPC_MDCTX_LOCKED_MDELEM_UNREF(ctx, elem) \
+  grpc_mdctx_locked_mdelem_unref((ctx), (elem), __FILE__, __LINE__)
+/* Unref a metadata element */
+void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *elem,
+                                    const char *file, int line);
+#else
+#define GRPC_MDCTX_LOCKED_MDELEM_UNREF(ctx, elem) \
+  grpc_mdctx_locked_mdelem_unref((ctx), (elem))
 /* Unref a metadata element */
 void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *elem);
+#endif
 /* Unlock the metadata context */
 void grpc_mdctx_unlock(grpc_mdctx *ctx);
 
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
index 8996eca..a5dfec9 100644
--- a/src/core/transport/stream_op.c
+++ b/src/core/transport/stream_op.c
@@ -65,7 +65,7 @@
   if (a->ops == a->inlined_ops) {
     if (b->ops == b->inlined_ops) {
       /* swap contents of inlined buffer */
-      gpr_slice temp[GRPC_SOPB_INLINE_ELEMENTS];
+      grpc_stream_op temp[GRPC_SOPB_INLINE_ELEMENTS];
       memcpy(temp, a->ops, b->nops * sizeof(grpc_stream_op));
       memcpy(a->ops, b->ops, a->nops * sizeof(grpc_stream_op));
       memcpy(b->ops, temp, b->nops * sizeof(grpc_stream_op));
@@ -163,6 +163,18 @@
   sopb->nops = new_nops;
 }
 
+void grpc_sopb_move_to(grpc_stream_op_buffer *src, grpc_stream_op_buffer *dst) {
+  if (src->nops == 0) {
+    return;
+  }
+  if (dst->nops == 0) {
+    grpc_sopb_swap(src, dst);
+    return;
+  }
+  grpc_sopb_append(dst, src->ops, src->nops);
+  src->nops = 0;
+}
+
 static void assert_valid_list(grpc_mdelem_list *list) {
 #ifndef NDEBUG
   grpc_linked_mdelem *l;
@@ -184,34 +196,34 @@
 }
 
 #ifndef NDEBUG
-void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd) {
-  assert_valid_list(&comd->list);
-  assert_valid_list(&comd->garbage);
+void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) {
+  assert_valid_list(&batch->list);
+  assert_valid_list(&batch->garbage);
 }
 #endif /* NDEBUG */
 
-void grpc_metadata_batch_init(grpc_metadata_batch *comd) {
-  comd->list.head = comd->list.tail = comd->garbage.head = comd->garbage.tail =
+void grpc_metadata_batch_init(grpc_metadata_batch *batch) {
+  batch->list.head = batch->list.tail = batch->garbage.head = batch->garbage.tail =
       NULL;
-  comd->deadline = gpr_inf_future;
+  batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
 }
 
-void grpc_metadata_batch_destroy(grpc_metadata_batch *comd) {
+void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) {
   grpc_linked_mdelem *l;
-  for (l = comd->list.head; l; l = l->next) {
-    grpc_mdelem_unref(l->md);
+  for (l = batch->list.head; l; l = l->next) {
+    GRPC_MDELEM_UNREF(l->md);
   }
-  for (l = comd->garbage.head; l; l = l->next) {
-    grpc_mdelem_unref(l->md);
+  for (l = batch->garbage.head; l; l = l->next) {
+    GRPC_MDELEM_UNREF(l->md);
   }
 }
 
-void grpc_metadata_batch_add_head(grpc_metadata_batch *comd,
+void grpc_metadata_batch_add_head(grpc_metadata_batch *batch,
                                   grpc_linked_mdelem *storage,
                                   grpc_mdelem *elem_to_add) {
   GPR_ASSERT(elem_to_add);
   storage->md = elem_to_add;
-  grpc_metadata_batch_link_head(comd, storage);
+  grpc_metadata_batch_link_head(batch, storage);
 }
 
 static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
@@ -228,17 +240,17 @@
   assert_valid_list(list);
 }
 
-void grpc_metadata_batch_link_head(grpc_metadata_batch *comd,
+void grpc_metadata_batch_link_head(grpc_metadata_batch *batch,
                                    grpc_linked_mdelem *storage) {
-  link_head(&comd->list, storage);
+  link_head(&batch->list, storage);
 }
 
-void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd,
+void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch,
                                   grpc_linked_mdelem *storage,
                                   grpc_mdelem *elem_to_add) {
   GPR_ASSERT(elem_to_add);
   storage->md = elem_to_add;
-  grpc_metadata_batch_link_tail(comd, storage);
+  grpc_metadata_batch_link_tail(batch, storage);
 }
 
 static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
@@ -255,9 +267,9 @@
   assert_valid_list(list);
 }
 
-void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd,
+void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
                                    grpc_linked_mdelem *storage) {
-  link_tail(&comd->list, storage);
+  link_tail(&batch->list, storage);
 }
 
 void grpc_metadata_batch_merge(grpc_metadata_batch *target,
@@ -274,16 +286,22 @@
   }
 }
 
-void grpc_metadata_batch_filter(grpc_metadata_batch *comd,
+void grpc_metadata_batch_move(grpc_metadata_batch *dst,
+                               grpc_metadata_batch *src) {
+  *dst = *src;
+  memset(src, 0, sizeof(grpc_metadata_batch));
+}
+
+void grpc_metadata_batch_filter(grpc_metadata_batch *batch,
                                 grpc_mdelem *(*filter)(void *user_data,
                                                        grpc_mdelem *elem),
                                 void *user_data) {
   grpc_linked_mdelem *l;
   grpc_linked_mdelem *next;
 
-  assert_valid_list(&comd->list);
-  assert_valid_list(&comd->garbage);
-  for (l = comd->list.head; l; l = next) {
+  assert_valid_list(&batch->list);
+  assert_valid_list(&batch->garbage);
+  for (l = batch->list.head; l; l = next) {
     grpc_mdelem *orig = l->md;
     grpc_mdelem *filt = filter(user_data, orig);
     next = l->next;
@@ -294,19 +312,19 @@
       if (l->next) {
         l->next->prev = l->prev;
       }
-      if (comd->list.head == l) {
-        comd->list.head = l->next;
+      if (batch->list.head == l) {
+        batch->list.head = l->next;
       }
-      if (comd->list.tail == l) {
-        comd->list.tail = l->prev;
+      if (batch->list.tail == l) {
+        batch->list.tail = l->prev;
       }
-      assert_valid_list(&comd->list);
-      link_head(&comd->garbage, l);
+      assert_valid_list(&batch->list);
+      link_head(&batch->garbage, l);
     } else if (filt != orig) {
-      grpc_mdelem_unref(orig);
+      GRPC_MDELEM_UNREF(orig);
       l->md = filt;
     }
   }
-  assert_valid_list(&comd->list);
-  assert_valid_list(&comd->garbage);
+  assert_valid_list(&batch->list);
+  assert_valid_list(&batch->garbage);
 }
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
index e080701..f27ef1b 100644
--- a/src/core/transport/stream_op.h
+++ b/src/core/transport/stream_op.h
@@ -41,7 +41,7 @@
 #include "src/core/transport/metadata.h"
 
 /* this many stream ops are inlined into a sopb before allocating */
-#define GRPC_SOPB_INLINE_ELEMENTS 16
+#define GRPC_SOPB_INLINE_ELEMENTS 4
 
 /* Operations that can be performed on a stream.
    Used by grpc_stream_op. */
@@ -85,29 +85,67 @@
 } grpc_mdelem_list;
 
 typedef struct grpc_metadata_batch {
+  /** Metadata elements in this batch */
   grpc_mdelem_list list;
+  /** Elements that have been removed from the batch, but have
+      not yet been unreffed - used to allow collecting garbage
+      under a single metadata context lock */
   grpc_mdelem_list garbage;
+  /** Used to calculate grpc-timeout at the point of sending,
+      or gpr_inf_future if this batch does not need to send a
+      grpc-timeout */
   gpr_timespec deadline;
 } grpc_metadata_batch;
 
-void grpc_metadata_batch_init(grpc_metadata_batch *comd);
-void grpc_metadata_batch_destroy(grpc_metadata_batch *comd);
+void grpc_metadata_batch_init(grpc_metadata_batch *batch);
+void grpc_metadata_batch_destroy(grpc_metadata_batch *batch);
 void grpc_metadata_batch_merge(grpc_metadata_batch *target,
                                grpc_metadata_batch *add);
 
-void grpc_metadata_batch_link_head(grpc_metadata_batch *comd,
+/** Moves the metadata information from \a src to \a dst. Upon return, \a src is
+ * zeroed. */
+void grpc_metadata_batch_move(grpc_metadata_batch *dst,
+                              grpc_metadata_batch *src);
+
+/** Add \a storage to the beginning of \a batch. storage->md is
+    assumed to be valid. 
+    \a storage is owned by the caller and must survive for the
+    lifetime of batch. This usually means it should be around
+    for the lifetime of the call. */
+void grpc_metadata_batch_link_head(grpc_metadata_batch *batch,
                                    grpc_linked_mdelem *storage);
-void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd,
+/** Add \a storage to the end of \a batch. storage->md is
+    assumed to be valid.
+    \a storage is owned by the caller and must survive for the
+    lifetime of batch. This usually means it should be around
+    for the lifetime of the call. */
+void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
                                    grpc_linked_mdelem *storage);
 
-void grpc_metadata_batch_add_head(grpc_metadata_batch *comd,
+/** Add \a elem_to_add as the first element in \a batch, using
+    \a storage as backing storage for the linked list element.
+    \a storage is owned by the caller and must survive for the
+    lifetime of batch. This usually means it should be around
+    for the lifetime of the call.
+    Takes ownership of \a elem_to_add */
+void grpc_metadata_batch_add_head(grpc_metadata_batch *batch,
                                   grpc_linked_mdelem *storage,
                                   grpc_mdelem *elem_to_add);
-void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd,
+/** Add \a elem_to_add as the last element in \a batch, using
+    \a storage as backing storage for the linked list element.
+    \a storage is owned by the caller and must survive for the
+    lifetime of batch. This usually means it should be around
+    for the lifetime of the call.
+    Takes ownership of \a elem_to_add */
+void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch,
                                   grpc_linked_mdelem *storage,
                                   grpc_mdelem *elem_to_add);
 
-void grpc_metadata_batch_filter(grpc_metadata_batch *comd,
+/** For each element in \a batch, execute \a filter.
+    The return value from \a filter will be substituted for the
+    grpc_mdelem passed to \a filter. If \a filter returns NULL,
+    the element will be moved to the garbage list. */
+void grpc_metadata_batch_filter(grpc_metadata_batch *batch,
                                 grpc_mdelem *(*filter)(void *user_data,
                                                        grpc_mdelem *elem),
                                 void *user_data);
@@ -166,6 +204,8 @@
 void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
                       size_t nops);
 
+void grpc_sopb_move_to(grpc_stream_op_buffer *src, grpc_stream_op_buffer *dst);
+
 char *grpc_sopb_string(grpc_stream_op_buffer *sopb);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
index d9a1319..2689e30 100644
--- a/src/core/transport/transport.c
+++ b/src/core/transport/transport.c
@@ -38,34 +38,26 @@
   return transport->vtable->sizeof_stream;
 }
 
-void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
-                           gpr_slice message) {
-  transport->vtable->goaway(transport, status, message);
-}
-
-void grpc_transport_close(grpc_transport *transport) {
-  transport->vtable->close(transport);
-}
-
 void grpc_transport_destroy(grpc_transport *transport) {
   transport->vtable->destroy(transport);
 }
 
 int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
                                const void *server_data,
-                               grpc_transport_op *initial_op) {
+                               grpc_transport_stream_op *initial_op) {
   return transport->vtable->init_stream(transport, stream, server_data,
                                         initial_op);
 }
 
-void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream,
-                               grpc_transport_op *op) {
-  transport->vtable->perform_op(transport, stream, op);
+void grpc_transport_perform_stream_op(grpc_transport *transport,
+                                      grpc_stream *stream,
+                                      grpc_transport_stream_op *op) {
+  transport->vtable->perform_stream_op(transport, stream, op);
 }
 
-void grpc_transport_add_to_pollset(grpc_transport *transport,
-                                   grpc_pollset *pollset) {
-  transport->vtable->add_to_pollset(transport, pollset);
+void grpc_transport_perform_op(grpc_transport *transport,
+                               grpc_transport_op *op) {
+  transport->vtable->perform_op(transport, op);
 }
 
 void grpc_transport_destroy_stream(grpc_transport *transport,
@@ -73,35 +65,26 @@
   transport->vtable->destroy_stream(transport, stream);
 }
 
-void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data),
-                         void *user_data) {
-  transport->vtable->ping(transport, cb, user_data);
-}
-
-void grpc_transport_setup_cancel(grpc_transport_setup *setup) {
-  setup->vtable->cancel(setup);
-}
-
-void grpc_transport_setup_initiate(grpc_transport_setup *setup) {
-  setup->vtable->initiate(setup);
-}
-
-void grpc_transport_op_finish_with_failure(grpc_transport_op *op) {
+void grpc_transport_stream_op_finish_with_failure(
+    grpc_transport_stream_op *op) {
   if (op->send_ops) {
-    op->on_done_send(op->send_user_data, 0);
+    op->on_done_send->cb(op->on_done_send->cb_arg, 0);
   }
   if (op->recv_ops) {
-    op->on_done_recv(op->recv_user_data, 0);
+    op->on_done_recv->cb(op->on_done_recv->cb_arg, 0);
+  }
+  if (op->on_consumed) {
+    op->on_consumed->cb(op->on_consumed->cb_arg, 0);
   }
 }
 
-void grpc_transport_op_add_cancellation(grpc_transport_op *op,
-                                        grpc_status_code status,
-                                        grpc_mdstr *message) {
+void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
+                                               grpc_status_code status,
+                                               grpc_mdstr *message) {
   if (op->cancel_with_status == GRPC_STATUS_OK) {
     op->cancel_with_status = status;
-    op->cancel_message = message;
-  } else if (message) {
-    grpc_mdstr_unref(message);
+  }
+  if (message) {
+    GRPC_MDSTR_UNREF(message);
   }
 }
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index 6f8d39e..6450360 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -37,12 +37,12 @@
 #include <stddef.h>
 
 #include "src/core/iomgr/pollset.h"
+#include "src/core/iomgr/pollset_set.h"
 #include "src/core/transport/stream_op.h"
 #include "src/core/channel/context.h"
 
 /* forward declarations */
 typedef struct grpc_transport grpc_transport;
-typedef struct grpc_transport_callbacks grpc_transport_callbacks;
 
 /* grpc_stream doesn't actually exist. It's used as a typesafe
    opaque pointer for whatever data the transport wants to track
@@ -61,52 +61,58 @@
   GRPC_STREAM_CLOSED
 } grpc_stream_state;
 
-/* Transport op: a set of operations to perform on a transport */
-typedef struct grpc_transport_op {
+/* Transport stream op: a set of operations to perform on a transport
+   against a single stream */
+typedef struct grpc_transport_stream_op {
+  grpc_iomgr_closure *on_consumed;
+
   grpc_stream_op_buffer *send_ops;
   int is_last_send;
-  void (*on_done_send)(void *user_data, int success);
-  void *send_user_data;
+  grpc_iomgr_closure *on_done_send;
 
   grpc_stream_op_buffer *recv_ops;
   grpc_stream_state *recv_state;
-  void (*on_done_recv)(void *user_data, int success);
-  void *recv_user_data;
+  /** The number of bytes this peer is currently prepared to receive.
+      These bytes will be eventually used to replenish per-stream flow control
+      windows. */
+  gpr_uint32 max_recv_bytes;
+  grpc_iomgr_closure *on_done_recv;
 
   grpc_pollset *bind_pollset;
 
   grpc_status_code cancel_with_status;
-  grpc_mdstr *cancel_message;
 
   /* Indexes correspond to grpc_context_index enum values */
   grpc_call_context_element *context;
+} grpc_transport_stream_op;
+
+/** Transport op: a set of operations to perform on a transport as a whole */
+typedef struct grpc_transport_op {
+  /** called when processing of this op is done */
+  grpc_iomgr_closure *on_consumed;
+  /** connectivity monitoring */
+  grpc_iomgr_closure *on_connectivity_state_change;
+  grpc_connectivity_state *connectivity_state;
+  /** should the transport be disconnected */
+  int disconnect;
+  /** should we send a goaway?
+      after a goaway is sent, once there are no more active calls on
+      the transport, the transport should disconnect */
+  int send_goaway;
+  /** what should the goaway contain? */
+  grpc_status_code goaway_status;
+  gpr_slice *goaway_message;
+  /** set the callback for accepting new streams;
+      this is a permanent callback, unlike the other one-shot closures */
+  void (*set_accept_stream)(void *user_data, grpc_transport *transport,
+                            const void *server_data);
+  void *set_accept_stream_user_data;
+  /** add this transport to a pollset */
+  grpc_pollset *bind_pollset;
+  /** send a ping, call this back if not NULL */
+  grpc_iomgr_closure *send_ping;
 } grpc_transport_op;
 
-/* Callbacks made from the transport to the upper layers of grpc. */
-struct grpc_transport_callbacks {
-  /* Initialize a new stream on behalf of the transport.
-     Must result in a call to
-     grpc_transport_init_stream(transport, ..., request) in the same call
-     stack.
-     Must not result in any other calls to the transport.
-
-     Arguments:
-       user_data     - the transport user data set at transport creation time
-       transport     - the grpc_transport instance making this call
-       request       - request parameters for this stream (owned by the caller)
-       server_data   - opaque transport dependent argument that should be passed
-                       to grpc_transport_init_stream
-     */
-  void (*accept_stream)(void *user_data, grpc_transport *transport,
-                        const void *server_data);
-
-  void (*goaway)(void *user_data, grpc_transport *transport,
-                 grpc_status_code status, gpr_slice debug);
-
-  /* The transport has been closed */
-  void (*closed)(void *user_data, grpc_transport *transport);
-};
-
 /* Returns the amount of memory required to store a grpc_stream for this
    transport */
 size_t grpc_transport_stream_size(grpc_transport *transport);
@@ -122,7 +128,7 @@
                    supplied from the accept_stream callback function */
 int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
                                const void *server_data,
-                               grpc_transport_op *initial_op);
+                               grpc_transport_stream_op *initial_op);
 
 /* Destroy transport data for a stream.
 
@@ -137,17 +143,13 @@
 void grpc_transport_destroy_stream(grpc_transport *transport,
                                    grpc_stream *stream);
 
-void grpc_transport_op_finish_with_failure(grpc_transport_op *op);
+void grpc_transport_stream_op_finish_with_failure(grpc_transport_stream_op *op);
 
-void grpc_transport_op_add_cancellation(grpc_transport_op *op,
-                                        grpc_status_code status,
-                                        grpc_mdstr *message);
+void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
+                                               grpc_status_code status,
+                                               grpc_mdstr *message);
 
-/* TODO(ctiller): remove this */
-void grpc_transport_add_to_pollset(grpc_transport *transport,
-                                   grpc_pollset *pollset);
-
-char *grpc_transport_op_string(grpc_transport_op *op);
+char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
 
 /* Send a batch of operations on a transport
 
@@ -157,17 +159,18 @@
      transport - the transport on which to initiate the stream
      stream    - the stream on which to send the operations. This must be
                  non-NULL and previously initialized by the same transport.
-     op        - a grpc_transport_op specifying the op to perform */
-void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream,
+     op        - a grpc_transport_stream_op specifying the op to perform */
+void grpc_transport_perform_stream_op(grpc_transport *transport,
+                                      grpc_stream *stream,
+                                      grpc_transport_stream_op *op);
+
+void grpc_transport_perform_op(grpc_transport *transport,
                                grpc_transport_op *op);
 
 /* Send a ping on a transport
 
-   Calls cb with user data when a response is received.
-   cb *MAY* be called with arbitrary transport level locks held. It is not safe
-   to call into the transport during cb. */
-void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data),
-                         void *user_data);
+   Calls cb with user data when a response is received. */
+void grpc_transport_ping(grpc_transport *transport, grpc_iomgr_closure *cb);
 
 /* Advise peer of pending connection termination. */
 void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
@@ -179,42 +182,4 @@
 /* Destroy the transport */
 void grpc_transport_destroy(grpc_transport *transport);
 
-/* Return type for grpc_transport_setup_callback */
-typedef struct grpc_transport_setup_result {
-  void *user_data;
-  const grpc_transport_callbacks *callbacks;
-} grpc_transport_setup_result;
-
-/* Given a transport, return callbacks for that transport. Used to finalize
-   setup as a transport is being created */
-typedef grpc_transport_setup_result (*grpc_transport_setup_callback)(
-    void *setup_arg, grpc_transport *transport, grpc_mdctx *mdctx);
-
-typedef struct grpc_transport_setup grpc_transport_setup;
-typedef struct grpc_transport_setup_vtable grpc_transport_setup_vtable;
-
-struct grpc_transport_setup_vtable {
-  void (*initiate)(grpc_transport_setup *setup);
-  void (*cancel)(grpc_transport_setup *setup);
-};
-
-/* Transport setup is an asynchronous utility interface for client channels to
-   establish connections. It's transport agnostic. */
-struct grpc_transport_setup {
-  const grpc_transport_setup_vtable *vtable;
-};
-
-/* Initiate transport setup: e.g. for TCP+DNS trigger a resolve of the name
-   given at transport construction time, create the tcp connection, perform
-   handshakes, and call some grpc_transport_setup_result function provided at
-   setup construction time.
-   This *may* be implemented as a no-op if the setup process monitors something
-   continuously. */
-void grpc_transport_setup_initiate(grpc_transport_setup *setup);
-/* Cancel transport setup. After this returns, no new transports should be
-   created, and all pending transport setup callbacks should be completed.
-   After this call completes, setup should be considered invalid (this can be
-   used as a destruction call by setup). */
-void grpc_transport_setup_cancel(grpc_transport_setup *setup);
-
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
index 479e153..515721d 100644
--- a/src/core/transport/transport_impl.h
+++ b/src/core/transport/transport_impl.h
@@ -43,29 +43,19 @@
 
   /* implementation of grpc_transport_init_stream */
   int (*init_stream)(grpc_transport *self, grpc_stream *stream,
-                     const void *server_data, grpc_transport_op *initial_op);
+                     const void *server_data,
+                     grpc_transport_stream_op *initial_op);
 
-  /* implementation of grpc_transport_send_batch */
-  void (*perform_op)(grpc_transport *self, grpc_stream *stream,
-                     grpc_transport_op *op);
+  /* implementation of grpc_transport_perform_stream_op */
+  void (*perform_stream_op)(grpc_transport *self, grpc_stream *stream,
+                            grpc_transport_stream_op *op);
 
-  /* implementation of grpc_transport_add_to_pollset */
-  void (*add_to_pollset)(grpc_transport *self, grpc_pollset *pollset);
+  /* implementation of grpc_transport_perform_op */
+  void (*perform_op)(grpc_transport *self, grpc_transport_op *op);
 
   /* implementation of grpc_transport_destroy_stream */
   void (*destroy_stream)(grpc_transport *self, grpc_stream *stream);
 
-  /* implementation of grpc_transport_goaway */
-  void (*goaway)(grpc_transport *self, grpc_status_code status,
-                 gpr_slice debug_data);
-
-  /* implementation of grpc_transport_close */
-  void (*close)(grpc_transport *self);
-
-  /* implementation of grpc_transport_ping */
-  void (*ping)(grpc_transport *self, void (*cb)(void *user_data),
-               void *user_data);
-
   /* implementation of grpc_transport_destroy */
   void (*destroy)(grpc_transport *self);
 } grpc_transport_vtable;
diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c
index 5c4edb0..9d127c5 100644
--- a/src/core/transport/transport_op_string.c
+++ b/src/core/transport/transport_op_string.c
@@ -47,14 +47,12 @@
 
 static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
   gpr_strvec_add(b, gpr_strdup("key="));
-  gpr_strvec_add(
-      b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice),
-                     GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT));
+  gpr_strvec_add(b,
+                 gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
 
   gpr_strvec_add(b, gpr_strdup(" value="));
-  gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice),
-                                GPR_SLICE_LENGTH(md->value->slice),
-                                GPR_HEXDUMP_PLAINTEXT));
+  gpr_strvec_add(
+      b, gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
 }
 
 static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
@@ -63,7 +61,7 @@
     if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", "));
     put_metadata(b, m->md);
   }
-  if (gpr_time_cmp(md.deadline, gpr_inf_future) != 0) {
+  if (gpr_time_cmp(md.deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) != 0) {
     char *tmp;
     gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec,
                  md.deadline.tv_nsec);
@@ -107,7 +105,7 @@
   return out;
 }
 
-char *grpc_transport_op_string(grpc_transport_op *op) {
+char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
   char *tmp;
   char *out;
   int first = 1;
@@ -130,7 +128,8 @@
   if (op->recv_ops) {
     if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
     first = 0;
-    gpr_strvec_add(&b, gpr_strdup("RECV"));
+    gpr_asprintf(&tmp, "RECV:max_recv_bytes=%d", op->max_recv_bytes);
+    gpr_strvec_add(&b, tmp);
   }
 
   if (op->bind_pollset) {
@@ -144,11 +143,13 @@
     first = 0;
     gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status);
     gpr_strvec_add(&b, tmp);
-    if (op->cancel_message) {
-      gpr_asprintf(&tmp, ";msg='%s'",
-                   grpc_mdstr_as_c_string(op->cancel_message));
-      gpr_strvec_add(&b, tmp);
-    }
+  }
+
+  if (op->on_consumed != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_asprintf(&tmp, "ON_CONSUMED:%p", op->on_consumed);
+    gpr_strvec_add(&b, tmp);
   }
 
   out = gpr_strvec_flatten(&b, NULL);
@@ -158,8 +159,8 @@
 }
 
 void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
-                      grpc_call_element *elem, grpc_transport_op *op) {
-  char *str = grpc_transport_op_string(op);
+                      grpc_call_element *elem, grpc_transport_stream_op *op) {
+  char *str = grpc_transport_stream_op_string(op);
   gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str);
   gpr_free(str);
 }
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 63b4c42..6156a39 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -54,8 +54,16 @@
 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
 
+
+/* Putting a macro like this and littering the source file with #if is really
+   bad practice.
+   TODO(jboeuf): refactor all the #if / #endif in a separate module. */
+#ifndef TSI_OPENSSL_ALPN_SUPPORT
+#define TSI_OPENSSL_ALPN_SUPPORT 1
+#endif
+
 /* TODO(jboeuf): I have not found a way to get this number dynamically from the
- * SSL structure. This is what we would ultimately want though... */
+   SSL structure. This is what we would ultimately want though... */
 #define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
 
 /* --- Structure definitions. ---*/
@@ -70,6 +78,8 @@
 typedef struct {
   tsi_ssl_handshaker_factory base;
   SSL_CTX* ssl_context;
+  unsigned char* alpn_protocol_list;
+  size_t alpn_protocol_list_length;
 } tsi_ssl_client_handshaker_factory;
 
 typedef struct {
@@ -841,7 +851,7 @@
 static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
                                               tsi_peer* peer) {
   tsi_result result = TSI_OK;
-  const unsigned char* alpn_selected;
+  const unsigned char* alpn_selected = NULL;
   unsigned int alpn_selected_len;
   tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
   X509* peer_cert = SSL_get_peer_certificate(impl->ssl);
@@ -850,7 +860,14 @@
     X509_free(peer_cert);
     if (result != TSI_OK) return result;
   }
+#if TSI_OPENSSL_ALPN_SUPPORT
   SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
+#endif /* TSI_OPENSSL_ALPN_SUPPORT */
+  if (alpn_selected == NULL) {
+    /* Try npn. */
+    SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
+                                   &alpn_selected_len);
+  }
   if (alpn_selected != NULL) {
     size_t i;
     tsi_peer_property* new_properties =
@@ -1012,6 +1029,32 @@
   return TSI_OK;
 }
 
+static int select_protocol_list(const unsigned char** out,
+                                unsigned char* outlen,
+                                const unsigned char* client_list,
+                                unsigned int client_list_len,
+                                const unsigned char* server_list,
+                                unsigned int server_list_len) {
+  const unsigned char* client_current = client_list;
+  while ((unsigned int)(client_current - client_list) < client_list_len) {
+    unsigned char client_current_len = *(client_current++);
+    const unsigned char* server_current = server_list;
+    while ((server_current >= server_list) &&
+           (gpr_uintptr)(server_current - server_list) < server_list_len) {
+      unsigned char server_current_len = *(server_current++);
+      if ((client_current_len == server_current_len) &&
+          !memcmp(client_current, server_current, server_current_len)) {
+        *out = server_current;
+        *outlen = server_current_len;
+        return SSL_TLSEXT_ERR_OK;
+      }
+      server_current += server_current_len;
+    }
+    client_current += client_current_len;
+  }
+  return SSL_TLSEXT_ERR_NOACK;
+}
+
 /* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
 
 static tsi_result ssl_client_handshaker_factory_create_handshaker(
@@ -1027,10 +1070,21 @@
     tsi_ssl_handshaker_factory* self) {
   tsi_ssl_client_handshaker_factory* impl =
       (tsi_ssl_client_handshaker_factory*)self;
-  SSL_CTX_free(impl->ssl_context);
+  if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context);
+  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
   free(impl);
 }
 
+static int client_handshaker_factory_npn_callback(
+    SSL* ssl, unsigned char** out, unsigned char* outlen,
+    const unsigned char* in, unsigned int inlen, void* arg) {
+  tsi_ssl_client_handshaker_factory* factory =
+      (tsi_ssl_client_handshaker_factory*)arg;
+  return select_protocol_list((const unsigned char**)out, outlen,
+                              factory->alpn_protocol_list,
+                              factory->alpn_protocol_list_length, in, inlen);
+}
+
 /* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
 
 static tsi_result ssl_server_handshaker_factory_create_handshaker(
@@ -1134,30 +1188,25 @@
   return SSL_TLSEXT_ERR_ALERT_WARNING;
 }
 
+#if TSI_OPENSSL_ALPN_SUPPORT
 static int server_handshaker_factory_alpn_callback(
     SSL* ssl, const unsigned char** out, unsigned char* outlen,
     const unsigned char* in, unsigned int inlen, void* arg) {
   tsi_ssl_server_handshaker_factory* factory =
       (tsi_ssl_server_handshaker_factory*)arg;
-  const unsigned char* client_current = in;
-  while ((unsigned int)(client_current - in) < inlen) {
-    unsigned char client_current_len = *(client_current++);
-    const unsigned char* server_current = factory->alpn_protocol_list;
-    while ((server_current >= factory->alpn_protocol_list) &&
-           (gpr_uintptr)(server_current - factory->alpn_protocol_list) <
-           factory->alpn_protocol_list_length) {
-      unsigned char server_current_len = *(server_current++);
-      if ((client_current_len == server_current_len) &&
-          !memcmp(client_current, server_current, server_current_len)) {
-        *out = server_current;
-        *outlen = server_current_len;
-        return SSL_TLSEXT_ERR_OK;
-      }
-      server_current += server_current_len;
-    }
-    client_current += client_current_len;
-  }
-  return SSL_TLSEXT_ERR_NOACK;
+  return select_protocol_list(out, outlen, in, inlen,
+                              factory->alpn_protocol_list,
+                              factory->alpn_protocol_list_length);
+}
+#endif /* TSI_OPENSSL_ALPN_SUPPORT */
+
+static int server_handshaker_factory_npn_advertised_callback(
+    SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) {
+  tsi_ssl_server_handshaker_factory* factory =
+      (tsi_ssl_server_handshaker_factory*)arg;
+  *out = factory->alpn_protocol_list;
+  *outlen = factory->alpn_protocol_list_length;
+  return SSL_TLSEXT_ERR_OK;
 }
 
 /* --- tsi_ssl_handshaker_factory constructors. --- */
@@ -1184,6 +1233,14 @@
     gpr_log(GPR_ERROR, "Could not create ssl context.");
     return TSI_INVALID_ARGUMENT;
   }
+
+  impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory));
+  if (impl == NULL) {
+    SSL_CTX_free(ssl_context);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  impl->ssl_context = ssl_context;
+
   do {
     result =
         populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size,
@@ -1197,41 +1254,33 @@
     }
 
     if (num_alpn_protocols != 0) {
-      unsigned char* alpn_protocol_list = NULL;
-      size_t alpn_protocol_list_length = 0;
-      int ssl_failed;
       result = build_alpn_protocol_name_list(
           alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
-          &alpn_protocol_list, &alpn_protocol_list_length);
+          &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
       if (result != TSI_OK) {
         gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
                 tsi_result_to_string(result));
-        free(alpn_protocol_list);
         break;
       }
-      ssl_failed = SSL_CTX_set_alpn_protos(ssl_context, alpn_protocol_list,
-                                           alpn_protocol_list_length);
-      free(alpn_protocol_list);
-      if (ssl_failed) {
+#if TSI_OPENSSL_ALPN_SUPPORT
+      if (SSL_CTX_set_alpn_protos(ssl_context, impl->alpn_protocol_list,
+                                  impl->alpn_protocol_list_length)) {
         gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
         result = TSI_INVALID_ARGUMENT;
         break;
       }
+#endif /* TSI_OPENSSL_ALPN_SUPPORT */
+      SSL_CTX_set_next_proto_select_cb(
+          ssl_context, client_handshaker_factory_npn_callback, impl);
     }
   } while (0);
   if (result != TSI_OK) {
-    SSL_CTX_free(ssl_context);
+    ssl_client_handshaker_factory_destroy(&impl->base);
     return result;
   }
   SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
   /* TODO(jboeuf): Add revocation verification. */
 
-  impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory));
-  if (impl == NULL) {
-    SSL_CTX_free(ssl_context);
-    return TSI_OUT_OF_RESOURCES;
-  }
-  impl->ssl_context = ssl_context;
   impl->base.create_handshaker =
       ssl_client_handshaker_factory_create_handshaker;
   impl->base.destroy = ssl_client_handshaker_factory_destroy;
@@ -1322,8 +1371,13 @@
           impl->ssl_contexts[i],
           ssl_server_handshaker_factory_servername_callback);
       SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
+#if TSI_OPENSSL_ALPN_SUPPORT
       SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
                                  server_handshaker_factory_alpn_callback, impl);
+#endif /* TSI_OPENSSL_ALPN_SUPPORT */
+      SSL_CTX_set_next_protos_advertised_cb(
+          impl->ssl_contexts[i],
+          server_handshaker_factory_npn_advertised_callback, impl);
     } while (0);
 
     if (result != TSI_OK) {
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 475a20d..da31d00 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -36,12 +36,11 @@
 #include <memory>
 
 #include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
 
+#include "src/core/census/grpc_context.h"
 #include "src/core/profiling/timers.h"
-#include "src/cpp/proto/proto_utils.h"
 #include <grpc++/channel_arguments.h>
 #include <grpc++/client_context.h>
 #include <grpc++/completion_queue.h>
@@ -61,7 +60,7 @@
 Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
                          CompletionQueue* cq) {
   auto c_call =
-      method.channel_tag()
+      method.channel_tag() && context->authority().empty()
           ? grpc_channel_create_registered_call(c_channel_, cq->cq(),
                                                 method.channel_tag(),
                                                 context->raw_deadline())
@@ -70,19 +69,20 @@
                                          ? target_.c_str()
                                          : context->authority().c_str(),
                                      context->raw_deadline());
+  grpc_census_call_set_context(c_call, context->get_census_context());
   GRPC_TIMER_MARK(GRPC_PTAG_CPP_CALL_CREATED, c_call);
   context->set_call(c_call, shared_from_this());
   return Call(c_call, this, cq);
 }
 
-void Channel::PerformOpsOnCall(CallOpBuffer* buf, Call* call) {
+void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) {
   static const size_t MAX_OPS = 8;
-  size_t nops = MAX_OPS;
-  grpc_op ops[MAX_OPS];
+  size_t nops = 0;
+  grpc_op cops[MAX_OPS];
   GRPC_TIMER_BEGIN(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
-  buf->FillOps(ops, &nops);
+  ops->FillOps(cops, &nops);
   GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call->call(), ops, nops, buf));
+             grpc_call_start_batch(call->call(), cops, nops, ops));
   GRPC_TIMER_END(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
 }
 
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
index cd23924..9108713 100644
--- a/src/cpp/client/channel.h
+++ b/src/cpp/client/channel.h
@@ -44,22 +44,22 @@
 
 namespace grpc {
 class Call;
-class CallOpBuffer;
+class CallOpSetInterface;
 class ChannelArguments;
 class CompletionQueue;
 class Credentials;
 class StreamContextInterface;
 
-class Channel GRPC_FINAL : public GrpcLibrary,
-                           public ChannelInterface {
+class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface {
  public:
   Channel(const grpc::string& target, grpc_channel* c_channel);
   ~Channel() GRPC_OVERRIDE;
 
-  virtual void *RegisterMethod(const char *method) GRPC_OVERRIDE;
+  virtual void* RegisterMethod(const char* method) GRPC_OVERRIDE;
   virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
                           CompletionQueue* cq) GRPC_OVERRIDE;
-  virtual void PerformOpsOnCall(CallOpBuffer* ops, Call* call) GRPC_OVERRIDE;
+  virtual void PerformOpsOnCall(CallOpSetInterface* ops,
+                                Call* call) GRPC_OVERRIDE;
 
  private:
   const grpc::string target_;
diff --git a/src/cpp/client/channel_arguments.cc b/src/cpp/client/channel_arguments.cc
index 679c4f1..4263e37 100644
--- a/src/cpp/client/channel_arguments.cc
+++ b/src/cpp/client/channel_arguments.cc
@@ -33,26 +33,13 @@
 
 #include <grpc++/channel_arguments.h>
 
-#include <grpc/grpc_security.h>
 #include "src/core/channel/channel_args.h"
 
 namespace grpc {
 
-void ChannelArguments::SetSslTargetNameOverride(const grpc::string& name) {
-  SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name);
-}
-
-void ChannelArguments::SetCompressionLevel(grpc_compression_level level) {
-  SetInt(GRPC_COMPRESSION_LEVEL_ARG, level);
-}
-
-grpc::string ChannelArguments::GetSslTargetNameOverride() const {
-  for (unsigned int i = 0; i < args_.size(); i++) {
-    if (grpc::string(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == args_[i].key) {
-      return args_[i].value.string;
-    }
-  }
-  return "";
+void ChannelArguments::SetCompressionAlgorithm(
+    grpc_compression_algorithm algorithm) {
+  SetInt(GRPC_COMPRESSION_ALGORITHM_ARG, algorithm);
 }
 
 void ChannelArguments::SetInt(const grpc::string& key, int value) {
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 72cdd49..14ab772 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -34,16 +34,20 @@
 #include <grpc++/client_context.h>
 
 #include <grpc/grpc.h>
+#include <grpc/support/string_util.h>
 #include <grpc++/credentials.h>
 #include <grpc++/time.h>
 
+#include "src/core/channel/compress_filter.h"
+#include "src/cpp/common/create_auth_context.h"
+
 namespace grpc {
 
 ClientContext::ClientContext()
     : initial_metadata_received_(false),
       call_(nullptr),
       cq_(nullptr),
-      deadline_(gpr_inf_future) {}
+      deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)) {}
 
 ClientContext::~ClientContext() {
   if (call_) {
@@ -52,8 +56,8 @@
   if (cq_) {
     // Drain cq_.
     grpc_completion_queue_shutdown(cq_);
-    while (grpc_completion_queue_next(cq_, gpr_inf_future).type !=
-           GRPC_QUEUE_SHUTDOWN)
+    while (grpc_completion_queue_next(cq_, gpr_inf_future(GPR_CLOCK_REALTIME))
+               .type != GRPC_QUEUE_SHUTDOWN)
       ;
     grpc_completion_queue_destroy(cq_);
   }
@@ -75,6 +79,25 @@
   }
 }
 
+void ClientContext::set_compression_algorithm(
+    grpc_compression_algorithm algorithm) {
+  char* algorithm_name = NULL;
+  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);
+  AddMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
+}
+
+std::shared_ptr<const AuthContext> ClientContext::auth_context() const {
+  if (auth_context_.get() == nullptr) {
+    auth_context_ = CreateAuthContext(call_);
+  }
+  return auth_context_;
+}
+
 void ClientContext::TryCancel() {
   if (call_) {
     grpc_call_cancel(call_);
diff --git a/src/cpp/client/client_unary_call.cc b/src/cpp/client/client_unary_call.cc
deleted file mode 100644
index 55e5893..0000000
--- a/src/cpp/client/client_unary_call.cc
+++ /dev/null
@@ -1,64 +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.
- *
- */
-
-#include <grpc++/impl/client_unary_call.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/channel_interface.h>
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/status.h>
-#include <grpc/support/log.h>
-
-namespace grpc {
-
-// Wrapper that performs a blocking unary call
-Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
-                         ClientContext* context,
-                         const grpc::protobuf::Message& request,
-                         grpc::protobuf::Message* result) {
-  CompletionQueue cq;
-  Call call(channel->CreateCall(method, context, &cq));
-  CallOpBuffer buf;
-  Status status;
-  buf.AddSendInitialMetadata(context);
-  buf.AddSendMessage(request);
-  buf.AddRecvInitialMetadata(context);
-  buf.AddRecvMessage(result);
-  buf.AddClientSendClose();
-  buf.AddClientRecvStatus(context, &status);
-  call.PerformOps(&buf);
-  GPR_ASSERT((cq.Pluck(&buf) && buf.got_message) || !status.ok());
-  return status;
-}
-
-}  // namespace grpc
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.m b/src/cpp/client/secure_channel_arguments.cc
similarity index 74%
copy from src/objective-c/GRPCClient/GRPCMethodName.m
copy to src/cpp/client/secure_channel_arguments.cc
index 9672407..d89df99 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.m
+++ b/src/cpp/client/secure_channel_arguments.cc
@@ -31,17 +31,24 @@
  *
  */
 
-#import "GRPCMethodName.h"
+#include <grpc++/channel_arguments.h>
+#include <grpc/grpc_security.h>
 
-@implementation GRPCMethodName
-- (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
-                         method:(NSString *)method {
-  if ((self = [super init])) {
-    _package = [package copy];
-    _interface = [interface copy];
-    _method = [method copy];
-  }
-  return self;
+#include "src/core/channel/channel_args.h"
+
+namespace grpc {
+
+void ChannelArguments::SetSslTargetNameOverride(const grpc::string& name) {
+  SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name);
 }
-@end
+
+grpc::string ChannelArguments::GetSslTargetNameOverride() const {
+  for (unsigned int i = 0; i < args_.size(); i++) {
+    if (grpc::string(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == args_[i].key) {
+      return args_[i].value.string;
+    }
+  }
+  return "";
+}
+
+}  // namespace grpc
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index b5134b3..01c7f14 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -92,7 +92,8 @@
             "with non-positive lifetime");
     return WrapCredentials(nullptr);
   }
-  gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds);
+  gpr_timespec lifetime =
+      gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
   return WrapCredentials(grpc_service_account_credentials_create(
       json_key.c_str(), scope.c_str(), lifetime));
 }
@@ -105,7 +106,8 @@
             "Trying to create JWTCredentials with non-positive lifetime");
     return WrapCredentials(nullptr);
   }
-  gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds);
+  gpr_timespec lifetime =
+      gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
   return WrapCredentials(
       grpc_jwt_credentials_create(json_key.c_str(), lifetime));
 }
@@ -117,6 +119,13 @@
       grpc_refresh_token_credentials_create(json_refresh_token.c_str()));
 }
 
+// Builds access token credentials.
+std::shared_ptr<Credentials> AccessTokenCredentials(
+    const grpc::string& access_token) {
+  return WrapCredentials(
+      grpc_access_token_credentials_create(access_token.c_str()));
+}
+
 // Builds IAM credentials.
 std::shared_ptr<Credentials> IAMCredentials(
     const grpc::string& authorization_token,
diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc
new file mode 100644
index 0000000..e706c6c
--- /dev/null
+++ b/src/cpp/common/auth_property_iterator.cc
@@ -0,0 +1,87 @@
+/*
+ *
+ * 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 <grpc++/auth_property_iterator.h>
+
+#include <grpc/grpc_security.h>
+
+namespace grpc {
+
+AuthPropertyIterator::AuthPropertyIterator()
+    : property_(nullptr), ctx_(nullptr), index_(0), name_(nullptr) {}
+
+AuthPropertyIterator::AuthPropertyIterator(
+    const grpc_auth_property* property, const grpc_auth_property_iterator* iter)
+    : property_(property),
+      ctx_(iter->ctx),
+      index_(iter->index),
+      name_(iter->name) {}
+
+AuthPropertyIterator::~AuthPropertyIterator() {}
+
+AuthPropertyIterator& AuthPropertyIterator::operator++() {
+  grpc_auth_property_iterator iter = {ctx_, index_, name_};
+  property_ = grpc_auth_property_iterator_next(&iter);
+  ctx_ = iter.ctx;
+  index_ = iter.index;
+  name_ = iter.name;
+  return *this;
+}
+
+AuthPropertyIterator AuthPropertyIterator::operator++(int) {
+  AuthPropertyIterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+bool AuthPropertyIterator::operator==(
+    const AuthPropertyIterator& rhs) const {
+  if (property_ == nullptr || rhs.property_ == nullptr) {
+    return property_ == rhs.property_;
+  } else {
+    return index_ == rhs.index_;
+  }
+}
+
+bool AuthPropertyIterator::operator!=(
+    const AuthPropertyIterator& rhs) const {
+  return !operator==(rhs);
+}
+
+const AuthProperty AuthPropertyIterator::operator*() {
+  return std::make_pair<grpc::string, grpc::string>(
+      grpc::string(property_->name),
+      grpc::string(property_->value, property_->value_length));
+}
+
+}  // namespace grpc
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
index edce639..0a5c976 100644
--- a/src/cpp/common/call.cc
+++ b/src/cpp/common/call.cc
@@ -39,114 +39,9 @@
 #include <grpc++/channel_interface.h>
 
 #include "src/core/profiling/timers.h"
-#include "src/cpp/proto/proto_utils.h"
 
 namespace grpc {
 
-CallOpBuffer::CallOpBuffer()
-    : return_tag_(this),
-      send_initial_metadata_(false),
-      initial_metadata_count_(0),
-      initial_metadata_(nullptr),
-      recv_initial_metadata_(nullptr),
-      send_message_(nullptr),
-      send_message_buffer_(nullptr),
-      send_buf_(nullptr),
-      recv_message_(nullptr),
-      recv_message_buffer_(nullptr),
-      recv_buf_(nullptr),
-      max_message_size_(-1),
-      client_send_close_(false),
-      recv_trailing_metadata_(nullptr),
-      recv_status_(nullptr),
-      status_code_(GRPC_STATUS_OK),
-      status_details_(nullptr),
-      status_details_capacity_(0),
-      send_status_available_(false),
-      send_status_code_(GRPC_STATUS_OK),
-      trailing_metadata_count_(0),
-      trailing_metadata_(nullptr),
-      cancelled_buf_(0),
-      recv_closed_(nullptr) {
-  memset(&recv_trailing_metadata_arr_, 0, sizeof(recv_trailing_metadata_arr_));
-  memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
-  recv_trailing_metadata_arr_.metadata = nullptr;
-  recv_initial_metadata_arr_.metadata = nullptr;
-}
-
-void CallOpBuffer::Reset(void* next_return_tag) {
-  return_tag_ = next_return_tag;
-
-  send_initial_metadata_ = false;
-  initial_metadata_count_ = 0;
-  gpr_free(initial_metadata_);
-
-  recv_initial_metadata_ = nullptr;
-  recv_initial_metadata_arr_.count = 0;
-
-  if (send_buf_ && send_message_) {
-    grpc_byte_buffer_destroy(send_buf_);
-  }
-  send_message_ = nullptr;
-  send_message_buffer_ = nullptr;
-  send_buf_ = nullptr;
-
-  got_message = false;
-  if (recv_buf_ && recv_message_) {
-    grpc_byte_buffer_destroy(recv_buf_);
-  }
-  recv_message_ = nullptr;
-  recv_message_buffer_ = nullptr;
-  recv_buf_ = nullptr;
-
-  client_send_close_ = false;
-
-  recv_trailing_metadata_ = nullptr;
-  recv_status_ = nullptr;
-  recv_trailing_metadata_arr_.count = 0;
-
-  status_code_ = GRPC_STATUS_OK;
-
-  send_status_available_ = false;
-  send_status_code_ = GRPC_STATUS_OK;
-  send_status_details_.clear();
-  trailing_metadata_count_ = 0;
-  trailing_metadata_ = nullptr;
-
-  recv_closed_ = nullptr;
-}
-
-CallOpBuffer::~CallOpBuffer() {
-  gpr_free(status_details_);
-  gpr_free(recv_initial_metadata_arr_.metadata);
-  gpr_free(recv_trailing_metadata_arr_.metadata);
-  if (recv_buf_ && recv_message_) {
-    grpc_byte_buffer_destroy(recv_buf_);
-  }
-  if (send_buf_ && send_message_) {
-    grpc_byte_buffer_destroy(send_buf_);
-  }
-}
-
-namespace {
-// TODO(yangg) if the map is changed before we send, the pointers will be a
-// mess. Make sure it does not happen.
-grpc_metadata* FillMetadataArray(
-    std::multimap<grpc::string, grpc::string>* metadata) {
-  if (metadata->empty()) {
-    return nullptr;
-  }
-  grpc_metadata* metadata_array =
-      (grpc_metadata*)gpr_malloc(metadata->size() * sizeof(grpc_metadata));
-  size_t i = 0;
-  for (auto iter = metadata->cbegin(); iter != metadata->cend(); ++iter, ++i) {
-    metadata_array[i].key = iter->first.c_str();
-    metadata_array[i].value = iter->second.c_str();
-    metadata_array[i].value_length = iter->second.size();
-  }
-  return metadata_array;
-}
-
 void FillMetadataMap(grpc_metadata_array* arr,
                      std::multimap<grpc::string, grpc::string>* metadata) {
   for (size_t i = 0; i < arr->count; i++) {
@@ -158,193 +53,23 @@
   grpc_metadata_array_destroy(arr);
   grpc_metadata_array_init(arr);
 }
-}  // namespace
 
-void CallOpBuffer::AddSendInitialMetadata(
-    std::multimap<grpc::string, grpc::string>* metadata) {
-  send_initial_metadata_ = true;
-  initial_metadata_count_ = metadata->size();
-  initial_metadata_ = FillMetadataArray(metadata);
-}
-
-void CallOpBuffer::AddRecvInitialMetadata(ClientContext* ctx) {
-  ctx->initial_metadata_received_ = true;
-  recv_initial_metadata_ = &ctx->recv_initial_metadata_;
-}
-
-void CallOpBuffer::AddSendInitialMetadata(ClientContext* ctx) {
-  AddSendInitialMetadata(&ctx->send_initial_metadata_);
-}
-
-void CallOpBuffer::AddSendMessage(const grpc::protobuf::Message& message) {
-  send_message_ = &message;
-}
-
-void CallOpBuffer::AddSendMessage(const ByteBuffer& message) {
-  send_message_buffer_ = &message;
-}
-
-void CallOpBuffer::AddRecvMessage(grpc::protobuf::Message* message) {
-  recv_message_ = message;
-  recv_message_->Clear();
-}
-
-void CallOpBuffer::AddRecvMessage(ByteBuffer* message) {
-  recv_message_buffer_ = message;
-  recv_message_buffer_->Clear();
-}
-
-void CallOpBuffer::AddClientSendClose() { client_send_close_ = true; }
-
-void CallOpBuffer::AddServerRecvClose(bool* cancelled) {
-  recv_closed_ = cancelled;
-}
-
-void CallOpBuffer::AddClientRecvStatus(ClientContext* context, Status* status) {
-  recv_trailing_metadata_ = &context->trailing_metadata_;
-  recv_status_ = status;
-}
-
-void CallOpBuffer::AddServerSendStatus(
-    std::multimap<grpc::string, grpc::string>* metadata, const Status& status) {
-  if (metadata != NULL) {
-    trailing_metadata_count_ = metadata->size();
-    trailing_metadata_ = FillMetadataArray(metadata);
-  } else {
-    trailing_metadata_count_ = 0;
+// TODO(yangg) if the map is changed before we send, the pointers will be a
+// mess. Make sure it does not happen.
+grpc_metadata* FillMetadataArray(
+    const std::multimap<grpc::string, grpc::string>& metadata) {
+  if (metadata.empty()) {
+    return nullptr;
   }
-  send_status_available_ = true;
-  send_status_code_ = static_cast<grpc_status_code>(status.error_code());
-  send_status_details_ = status.error_message();
-}
-
-void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
-  *nops = 0;
-  if (send_initial_metadata_) {
-    ops[*nops].op = GRPC_OP_SEND_INITIAL_METADATA;
-    ops[*nops].data.send_initial_metadata.count = initial_metadata_count_;
-    ops[*nops].data.send_initial_metadata.metadata = initial_metadata_;
-    ops[*nops].flags = 0;
-    (*nops)++;
+  grpc_metadata* metadata_array =
+      (grpc_metadata*)gpr_malloc(metadata.size() * sizeof(grpc_metadata));
+  size_t i = 0;
+  for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
+    metadata_array[i].key = iter->first.c_str();
+    metadata_array[i].value = iter->second.c_str();
+    metadata_array[i].value_length = iter->second.size();
   }
-  if (recv_initial_metadata_) {
-    ops[*nops].op = GRPC_OP_RECV_INITIAL_METADATA;
-    ops[*nops].data.recv_initial_metadata = &recv_initial_metadata_arr_;
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-  if (send_message_ || send_message_buffer_) {
-    if (send_message_) {
-      GRPC_TIMER_BEGIN(GRPC_PTAG_PROTO_SERIALIZE, 0);
-      bool success = SerializeProto(*send_message_, &send_buf_);
-      if (!success) {
-        abort();
-        // TODO handle parse failure
-      }
-      GRPC_TIMER_END(GRPC_PTAG_PROTO_SERIALIZE, 0);
-    } else {
-      send_buf_ = send_message_buffer_->buffer();
-    }
-    ops[*nops].op = GRPC_OP_SEND_MESSAGE;
-    ops[*nops].data.send_message = send_buf_;
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-  if (recv_message_ || recv_message_buffer_) {
-    ops[*nops].op = GRPC_OP_RECV_MESSAGE;
-    ops[*nops].data.recv_message = &recv_buf_;
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-  if (client_send_close_) {
-    ops[*nops].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-  if (recv_status_) {
-    ops[*nops].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
-    ops[*nops].data.recv_status_on_client.trailing_metadata =
-        &recv_trailing_metadata_arr_;
-    ops[*nops].data.recv_status_on_client.status = &status_code_;
-    ops[*nops].data.recv_status_on_client.status_details = &status_details_;
-    ops[*nops].data.recv_status_on_client.status_details_capacity =
-        &status_details_capacity_;
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-  if (send_status_available_) {
-    ops[*nops].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
-    ops[*nops].data.send_status_from_server.trailing_metadata_count =
-        trailing_metadata_count_;
-    ops[*nops].data.send_status_from_server.trailing_metadata =
-        trailing_metadata_;
-    ops[*nops].data.send_status_from_server.status = send_status_code_;
-    ops[*nops].data.send_status_from_server.status_details =
-        send_status_details_.empty() ? nullptr : send_status_details_.c_str();
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-  if (recv_closed_) {
-    ops[*nops].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
-    ops[*nops].data.recv_close_on_server.cancelled = &cancelled_buf_;
-    ops[*nops].flags = 0;
-    (*nops)++;
-  }
-}
-
-bool CallOpBuffer::FinalizeResult(void** tag, bool* status) {
-  // Release send buffers.
-  if (send_buf_ && send_message_) {
-    if (send_message_) {
-      grpc_byte_buffer_destroy(send_buf_);
-    }
-    send_buf_ = nullptr;
-  }
-  if (initial_metadata_) {
-    gpr_free(initial_metadata_);
-    initial_metadata_ = nullptr;
-  }
-  if (trailing_metadata_count_) {
-    gpr_free(trailing_metadata_);
-    trailing_metadata_ = nullptr;
-  }
-  // Set user-facing tag.
-  *tag = return_tag_;
-  // Process received initial metadata
-  if (recv_initial_metadata_) {
-    FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
-  }
-  // Parse received message if any.
-  if (recv_message_ || recv_message_buffer_) {
-    if (recv_buf_) {
-      got_message = *status;
-      if (recv_message_) {
-        GRPC_TIMER_BEGIN(GRPC_PTAG_PROTO_DESERIALIZE, 0);
-        *status = *status &&
-                  DeserializeProto(recv_buf_, recv_message_, max_message_size_);
-        grpc_byte_buffer_destroy(recv_buf_);
-        GRPC_TIMER_END(GRPC_PTAG_PROTO_DESERIALIZE, 0);
-      } else {
-        recv_message_buffer_->set_buffer(recv_buf_);
-      }
-      recv_buf_ = nullptr;
-    } else {
-      // Read failed
-      got_message = false;
-      *status = false;
-    }
-  }
-  // Parse received status.
-  if (recv_status_) {
-    FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
-    *recv_status_ = Status(
-        static_cast<StatusCode>(status_code_),
-        status_details_ ? grpc::string(status_details_) : grpc::string());
-  }
-  if (recv_closed_) {
-    *recv_closed_ = cancelled_buf_ != 0;
-  }
-  return true;
+  return metadata_array;
 }
 
 Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
@@ -357,11 +82,11 @@
       call_(call),
       max_message_size_(max_message_size) {}
 
-void Call::PerformOps(CallOpBuffer* buffer) {
+void Call::PerformOps(CallOpSetInterface* ops) {
   if (max_message_size_ > 0) {
-    buffer->set_max_message_size(max_message_size_);
+    ops->set_max_message_size(max_message_size_);
   }
-  call_hook_->PerformOpsOnCall(buffer, this);
+  call_hook_->PerformOpsOnCall(ops, this);
 }
 
 }  // namespace grpc
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index b2dd1ac..593963f 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -70,7 +70,8 @@
 }
 
 bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
-  auto ev = grpc_completion_queue_pluck(cq_, tag, gpr_inf_future);
+  auto ev =
+      grpc_completion_queue_pluck(cq_, tag, gpr_inf_future(GPR_CLOCK_REALTIME));
   bool ok = ev.success != 0;
   void* ignored = tag;
   GPR_ASSERT(tag->FinalizeResult(&ignored, &ok));
@@ -80,7 +81,8 @@
 }
 
 void CompletionQueue::TryPluck(CompletionQueueTag* tag) {
-  auto ev = grpc_completion_queue_pluck(cq_, tag, gpr_time_0);
+  auto ev =
+      grpc_completion_queue_pluck(cq_, tag, gpr_time_0(GPR_CLOCK_REALTIME));
   if (ev.type == GRPC_QUEUE_TIMEOUT) return;
   bool ok = ev.success != 0;
   void* ignored = tag;
diff --git a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h b/src/cpp/common/create_auth_context.h
similarity index 88%
copy from src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
copy to src/cpp/common/create_auth_context.h
index 28c7374..9082a90 100644
--- a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
+++ b/src/cpp/common/create_auth_context.h
@@ -30,11 +30,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+#include <memory>
 
-#import <Foundation/Foundation.h>
+#include <grpc/grpc.h>
+#include <grpc++/auth_context.h>
 
-#import "GRPCMethodName.h"
+namespace grpc {
 
-@interface GRPCMethodName (HTTP2Encoding)
-- (NSString *)HTTP2Path;
-@end
+std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call);
+
+}  // namespace grpc
diff --git a/src/core/surface/client.h b/src/cpp/common/insecure_create_auth_context.cc
similarity index 85%
rename from src/core/surface/client.h
rename to src/cpp/common/insecure_create_auth_context.cc
index 9db2ccf..07fc0bd 100644
--- a/src/core/surface/client.h
+++ b/src/cpp/common/insecure_create_auth_context.cc
@@ -30,12 +30,16 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+#include <memory>
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include <grpc/grpc.h>
+#include <grpc++/auth_context.h>
 
-#include "src/core/channel/channel_stack.h"
+namespace grpc {
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call) {
+  (void)call;
+  return std::shared_ptr<const AuthContext>();
+}
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+}  // namespace grpc
diff --git a/src/cpp/common/secure_auth_context.cc b/src/cpp/common/secure_auth_context.cc
new file mode 100644
index 0000000..87d7bab
--- /dev/null
+++ b/src/cpp/common/secure_auth_context.cc
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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/cpp/common/secure_auth_context.h"
+
+#include <grpc/grpc_security.h>
+
+namespace grpc {
+
+SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx) : ctx_(ctx) {}
+
+SecureAuthContext::~SecureAuthContext() { grpc_auth_context_release(ctx_); }
+
+std::vector<grpc::string> SecureAuthContext::GetPeerIdentity() const {
+  if (!ctx_) {
+    return std::vector<grpc::string>();
+  }
+  grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_);
+  std::vector<grpc::string> identity;
+  const grpc_auth_property* property = nullptr;
+  while ((property = grpc_auth_property_iterator_next(&iter))) {
+    identity.push_back(grpc::string(property->value, property->value_length));
+  }
+  return identity;
+}
+
+grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const {
+  if (!ctx_) {
+    return "";
+  }
+  const char* name = grpc_auth_context_peer_identity_property_name(ctx_);
+  return name == nullptr ? "" : name;
+}
+
+std::vector<grpc::string> SecureAuthContext::FindPropertyValues(
+    const grpc::string& name) const {
+  if (!ctx_) {
+    return std::vector<grpc::string>();
+  }
+  grpc_auth_property_iterator iter =
+      grpc_auth_context_find_properties_by_name(ctx_, name.c_str());
+  const grpc_auth_property* property = nullptr;
+  std::vector<grpc::string> values;
+  while ((property = grpc_auth_property_iterator_next(&iter))) {
+    values.push_back(grpc::string(property->value, property->value_length));
+  }
+  return values;
+}
+
+AuthPropertyIterator SecureAuthContext::begin() const {
+  if (ctx_) {
+    grpc_auth_property_iterator iter =
+        grpc_auth_context_property_iterator(ctx_);
+    const grpc_auth_property* property =
+        grpc_auth_property_iterator_next(&iter);
+    return AuthPropertyIterator(property, &iter);
+  } else {
+    return end();
+  }
+}
+
+AuthPropertyIterator SecureAuthContext::end() const {
+  return AuthPropertyIterator();
+}
+
+}  // namespace grpc
diff --git a/src/cpp/server/thread_pool.h b/src/cpp/common/secure_auth_context.h
similarity index 68%
copy from src/cpp/server/thread_pool.h
copy to src/cpp/common/secure_auth_context.h
index 3b70249..264ed62 100644
--- a/src/cpp/server/thread_pool.h
+++ b/src/cpp/common/secure_auth_context.h
@@ -31,39 +31,36 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
-#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#ifndef GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
+#define GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
 
-#include <grpc++/config.h>
+#include <grpc++/auth_context.h>
 
-#include <grpc++/impl/sync.h>
-#include <grpc++/impl/thd.h>
-#include <grpc++/thread_pool_interface.h>
-
-#include <queue>
-#include <vector>
+struct grpc_auth_context;
 
 namespace grpc {
 
-class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
+class SecureAuthContext GRPC_FINAL : public AuthContext {
  public:
-  explicit ThreadPool(int num_threads);
-  ~ThreadPool();
+  SecureAuthContext(grpc_auth_context* ctx);
 
-  void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
+  ~SecureAuthContext() GRPC_OVERRIDE;
+
+  std::vector<grpc::string> GetPeerIdentity() const GRPC_OVERRIDE;
+
+  grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE;
+
+  std::vector<grpc::string> FindPropertyValues(const grpc::string& name) const
+      GRPC_OVERRIDE;
+
+  AuthPropertyIterator begin() const GRPC_OVERRIDE;
+
+  AuthPropertyIterator end() const GRPC_OVERRIDE;
 
  private:
-  grpc::mutex mu_;
-  grpc::condition_variable cv_;
-  bool shutdown_;
-  std::queue<std::function<void()>> callbacks_;
-  std::vector<grpc::thread*> threads_;
-
-  void ThreadFunc();
+  grpc_auth_context* ctx_;
 };
 
-ThreadPoolInterface* CreateDefaultThreadPool();
-
 }  // namespace grpc
 
-#endif  // GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
+#endif  // GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
diff --git a/src/core/surface/client.h b/src/cpp/common/secure_create_auth_context.cc
similarity index 77%
copy from src/core/surface/client.h
copy to src/cpp/common/secure_create_auth_context.cc
index 9db2ccf..d81f4bb 100644
--- a/src/core/surface/client.h
+++ b/src/cpp/common/secure_create_auth_context.cc
@@ -30,12 +30,21 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+#include <memory>
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc++/auth_context.h>
+#include "src/cpp/common/secure_auth_context.h"
 
-#include "src/core/channel/channel_stack.h"
+namespace grpc {
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call) {
+  if (call == nullptr) {
+    return std::shared_ptr<const AuthContext>();
+  }
+  return std::shared_ptr<const AuthContext>(
+      new SecureAuthContext(grpc_call_auth_context(call)));
+}
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+}  // namespace grpc
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
index f4cf5cf..63f4a3a 100644
--- a/src/cpp/proto/proto_utils.cc
+++ b/src/cpp/proto/proto_utils.cc
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/cpp/proto/proto_utils.h"
+#include <grpc++/impl/proto_utils.h>
 #include <grpc++/config.h>
 
 #include <grpc/grpc.h>
@@ -67,7 +67,7 @@
       slice_ = gpr_slice_malloc(block_size_);
     }
     *data = GPR_SLICE_START_PTR(slice_);
-    byte_count_ += *size = GPR_SLICE_LENGTH(slice_);
+    byte_count_ += * size = GPR_SLICE_LENGTH(slice_);
     gpr_slice_buffer_add(slice_buffer_, slice_);
     return true;
   }
@@ -103,7 +103,9 @@
       : byte_count_(0), backup_count_(0) {
     grpc_byte_buffer_reader_init(&reader_, buffer);
   }
-  ~GrpcBufferReader() GRPC_OVERRIDE {}
+  ~GrpcBufferReader() GRPC_OVERRIDE {
+    grpc_byte_buffer_reader_destroy(&reader_);
+  }
 
   bool Next(const void** data, int* size) GRPC_OVERRIDE {
     if (backup_count_ > 0) {
@@ -118,7 +120,7 @@
     }
     gpr_slice_unref(slice_);
     *data = GPR_SLICE_START_PTR(slice_);
-    byte_count_ += *size = GPR_SLICE_LENGTH(slice_);
+    byte_count_ += * size = GPR_SLICE_LENGTH(slice_);
     return true;
   }
 
@@ -152,20 +154,32 @@
 
 namespace grpc {
 
-bool SerializeProto(const grpc::protobuf::Message& msg, grpc_byte_buffer** bp) {
+Status SerializeProto(const grpc::protobuf::Message& msg, grpc_byte_buffer** bp) {
   GrpcBufferWriter writer(bp);
-  return msg.SerializeToZeroCopyStream(&writer);
+  return msg.SerializeToZeroCopyStream(&writer)
+             ? Status::OK
+             : Status(StatusCode::INVALID_ARGUMENT,
+                      "Failed to serialize message");
 }
 
-bool DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
-                      int max_message_size) {
-  if (!buffer) return false;
+Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
+                        int max_message_size) {
+  if (!buffer) {
+    return Status(StatusCode::INVALID_ARGUMENT, "No payload");
+  }
   GrpcBufferReader reader(buffer);
   ::grpc::protobuf::io::CodedInputStream decoder(&reader);
   if (max_message_size > 0) {
     decoder.SetTotalBytesLimit(max_message_size, max_message_size);
   }
-  return msg->ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
+  if (!msg->ParseFromCodedStream(&decoder)) {
+    return Status(StatusCode::INVALID_ARGUMENT,
+                  msg->InitializationErrorString());
+  }
+  if (!decoder.ConsumedEntireMessage()) {
+    return Status(StatusCode::INVALID_ARGUMENT, "Did not read entire message");
+  }
+  return Status::OK;
 }
 
 }  // namespace grpc
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
deleted file mode 100644
index e1f2945..0000000
--- a/src/cpp/server/async_server_context.cc
+++ /dev/null
@@ -1,99 +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.
- *
- */
-
-#include <grpc++/async_server_context.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include "src/cpp/proto/proto_utils.h"
-#include <grpc++/config.h>
-#include <grpc++/status.h>
-
-namespace grpc {
-
-AsyncServerContext::AsyncServerContext(
-    grpc_call* call, const grpc::string& method, const grpc::string& host,
-    system_clock::time_point absolute_deadline)
-    : method_(method),
-      host_(host),
-      absolute_deadline_(absolute_deadline),
-      request_(nullptr),
-      call_(call) {}
-
-AsyncServerContext::~AsyncServerContext() { grpc_call_destroy(call_); }
-
-void AsyncServerContext::Accept(grpc_completion_queue* cq) {
-  GPR_ASSERT(grpc_call_server_accept_old(call_, cq, this) == GRPC_CALL_OK);
-  GPR_ASSERT(grpc_call_server_end_initial_metadata_old(
-                 call_, GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
-}
-
-bool AsyncServerContext::StartRead(grpc::protobuf::Message* request) {
-  GPR_ASSERT(request);
-  request_ = request;
-  grpc_call_error err = grpc_call_start_read_old(call_, this);
-  return err == GRPC_CALL_OK;
-}
-
-bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response,
-                                    int flags) {
-  grpc_byte_buffer* buffer = nullptr;
-  GRPC_TIMER_MARK(SER_PROTO_BEGIN, call_->call());
-  if (!SerializeProto(response, &buffer)) {
-    return false;
-  }
-  GRPC_TIMER_MARK(SER_PROTO_END, call_->call());
-  grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags);
-  grpc_byte_buffer_destroy(buffer);
-  return err == GRPC_CALL_OK;
-}
-
-bool AsyncServerContext::StartWriteStatus(const Status& status) {
-  grpc_call_error err = grpc_call_start_write_status_old(
-      call_, static_cast<grpc_status_code>(status.code()),
-      status.details().empty() ? nullptr
-                               : const_cast<char*>(status.details().c_str()),
-      this);
-  return err == GRPC_CALL_OK;
-}
-
-bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
-  GPR_ASSERT(request_);
-  GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_->call());
-  bool success = DeserializeProto(read_buffer, request_);
-  GRPC_TIMER_MARK(DESER_PROTO_END, call_->call());
-  request_ = nullptr;
-  return success;
-}
-
-}  // namespace grpc
diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc
index 89c1d7e..cc182f5 100644
--- a/src/cpp/server/create_default_thread_pool.cc
+++ b/src/cpp/server/create_default_thread_pool.cc
@@ -32,7 +32,7 @@
  */
 
 #include <grpc/support/cpu.h>
-#include "src/cpp/server/thread_pool.h"
+#include <grpc++/fixed_size_thread_pool.h>
 
 #ifndef GRPC_CUSTOM_DEFAULT_THREAD_POOL
 
@@ -41,7 +41,7 @@
 ThreadPoolInterface* CreateDefaultThreadPool() {
    int cores = gpr_cpu_num_cores();
    if (!cores) cores = 4;
-   return new ThreadPool(cores);
+   return new FixedSizeThreadPool(cores);
 }
 
 }  // namespace grpc
diff --git a/src/cpp/server/thread_pool.cc b/src/cpp/server/fixed_size_thread_pool.cc
similarity index 86%
rename from src/cpp/server/thread_pool.cc
rename to src/cpp/server/fixed_size_thread_pool.cc
index 118cabc..bafbc58 100644
--- a/src/cpp/server/thread_pool.cc
+++ b/src/cpp/server/fixed_size_thread_pool.cc
@@ -33,12 +33,11 @@
 
 #include <grpc++/impl/sync.h>
 #include <grpc++/impl/thd.h>
-
-#include "src/cpp/server/thread_pool.h"
+#include <grpc++/fixed_size_thread_pool.h>
 
 namespace grpc {
 
-void ThreadPool::ThreadFunc() {
+void FixedSizeThreadPool::ThreadFunc() {
   for (;;) {
     // Wait until work is available or we are shutting down.
     grpc::unique_lock<grpc::mutex> lock(mu_);
@@ -58,13 +57,14 @@
   }
 }
 
-ThreadPool::ThreadPool(int num_threads) : shutdown_(false) {
+FixedSizeThreadPool::FixedSizeThreadPool(int num_threads) : shutdown_(false) {
   for (int i = 0; i < num_threads; i++) {
-    threads_.push_back(new grpc::thread(&ThreadPool::ThreadFunc, this));
+    threads_.push_back(
+        new grpc::thread(&FixedSizeThreadPool::ThreadFunc, this));
   }
 }
 
-ThreadPool::~ThreadPool() {
+FixedSizeThreadPool::~FixedSizeThreadPool() {
   {
     grpc::lock_guard<grpc::mutex> lock(mu_);
     shutdown_ = true;
@@ -76,7 +76,7 @@
   }
 }
 
-void ThreadPool::ScheduleCallback(const std::function<void()>& callback) {
+void FixedSizeThreadPool::Add(const std::function<void()>& callback) {
   grpc::lock_guard<grpc::mutex> lock(mu_);
   callbacks_.push(callback);
   cv_.notify_one();
diff --git a/src/cpp/server/insecure_server_credentials.cc b/src/cpp/server/insecure_server_credentials.cc
index 55dd90d..aca3568 100644
--- a/src/cpp/server/insecure_server_credentials.cc
+++ b/src/cpp/server/insecure_server_credentials.cc
@@ -31,9 +31,10 @@
  *
  */
 
-#include <grpc/grpc_security.h>
 #include <grpc++/server_credentials.h>
 
+#include <grpc/grpc.h>
+
 namespace grpc {
 namespace {
 class InsecureServerCredentialsImpl GRPC_FINAL : public ServerCredentials {
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index dbd88c5..ab87b22 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -35,7 +35,6 @@
 #include <utility>
 
 #include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc++/completion_queue.h>
@@ -48,7 +47,6 @@
 #include <grpc++/time.h>
 
 #include "src/core/profiling/timers.h"
-#include "src/cpp/proto/proto_utils.h"
 
 namespace grpc {
 
@@ -69,15 +67,11 @@
         has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
                              method->method_type() ==
                                  RpcMethod::SERVER_STREAMING),
-        has_response_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
-                              method->method_type() ==
-                                  RpcMethod::CLIENT_STREAMING) {
+        cq_(nullptr) {
     grpc_metadata_array_init(&request_metadata_);
   }
 
-  ~SyncRequest() {
-    grpc_metadata_array_destroy(&request_metadata_);
-  }
+  ~SyncRequest() { grpc_metadata_array_destroy(&request_metadata_); }
 
   static SyncRequest* Wait(CompletionQueue* cq, bool* ok) {
     void* tag = nullptr;
@@ -90,10 +84,16 @@
     return mrd;
   }
 
+  void SetupRequest() { cq_ = grpc_completion_queue_create(); }
+
+  void TeardownRequest() {
+    grpc_completion_queue_destroy(cq_);
+    cq_ = nullptr;
+  }
+
   void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
-    GPR_ASSERT(!in_flight_);
+    GPR_ASSERT(cq_ && !in_flight_);
     in_flight_ = true;
-    cq_ = grpc_completion_queue_create();
     GPR_ASSERT(GRPC_CALL_OK ==
                grpc_server_request_registered_call(
                    server, tag_, &call_, &deadline_, &request_metadata_,
@@ -116,10 +116,9 @@
           ctx_(mrd->deadline_, mrd->request_metadata_.metadata,
                mrd->request_metadata_.count),
           has_request_payload_(mrd->has_request_payload_),
-          has_response_payload_(mrd->has_response_payload_),
           request_payload_(mrd->request_payload_),
           method_(mrd->method_) {
-      ctx_.call_ = mrd->call_;
+      ctx_.set_call(mrd->call_);
       ctx_.cq_ = &cq_;
       GPR_ASSERT(mrd->in_flight_);
       mrd->in_flight_ = false;
@@ -133,35 +132,10 @@
     }
 
     void Run() {
-      std::unique_ptr<grpc::protobuf::Message> req;
-      std::unique_ptr<grpc::protobuf::Message> res;
-      if (has_request_payload_) {
-        GRPC_TIMER_BEGIN(GRPC_PTAG_PROTO_DESERIALIZE, call_.call());
-        req.reset(method_->AllocateRequestProto());
-        if (!DeserializeProto(request_payload_, req.get(),
-                              call_.max_message_size())) {
-          // FIXME(yangg) deal with deserialization failure
-          cq_.Shutdown();
-          return;
-        }
-        GRPC_TIMER_END(GRPC_PTAG_PROTO_DESERIALIZE, call_.call());
-      }
-      if (has_response_payload_) {
-        res.reset(method_->AllocateResponseProto());
-      }
       ctx_.BeginCompletionOp(&call_);
-      auto status = method_->handler()->RunHandler(
-          MethodHandler::HandlerParameter(&call_, &ctx_, req.get(), res.get()));
-      CallOpBuffer buf;
-      if (!ctx_.sent_initial_metadata_) {
-        buf.AddSendInitialMetadata(&ctx_.initial_metadata_);
-      }
-      if (has_response_payload_) {
-        buf.AddSendMessage(*res);
-      }
-      buf.AddServerSendStatus(&ctx_.trailing_metadata_, status);
-      call_.PerformOps(&buf);
-      cq_.Pluck(&buf);  /* status ignored */
+      method_->handler()->RunHandler(MethodHandler::HandlerParameter(
+          &call_, &ctx_, request_payload_, call_.max_message_size()));
+      request_payload_ = nullptr;
       void* ignored_tag;
       bool ignored_ok;
       cq_.Shutdown();
@@ -173,7 +147,6 @@
     Call call_;
     ServerContext ctx_;
     const bool has_request_payload_;
-    const bool has_response_payload_;
     grpc_byte_buffer* request_payload_;
     RpcServiceMethod* const method_;
   };
@@ -183,7 +156,6 @@
   void* const tag_;
   bool in_flight_;
   const bool has_request_payload_;
-  const bool has_response_payload_;
   grpc_call* call_;
   gpr_timespec deadline_;
   grpc_metadata_array request_metadata_;
@@ -235,10 +207,11 @@
   delete sync_methods_;
 }
 
-bool Server::RegisterService(RpcService* service) {
+bool Server::RegisterService(const grpc::string *host, RpcService* service) {
   for (int i = 0; i < service->GetMethodCount(); ++i) {
     RpcServiceMethod* method = service->GetMethod(i);
-    void* tag = grpc_server_register_method(server_, method->name(), nullptr);
+    void* tag = grpc_server_register_method(
+        server_, method->name(), host ? host->c_str() : nullptr);
     if (!tag) {
       gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
               method->name());
@@ -250,14 +223,14 @@
   return true;
 }
 
-bool Server::RegisterAsyncService(AsynchronousService* service) {
-  GPR_ASSERT(service->dispatch_impl_ == nullptr &&
+bool Server::RegisterAsyncService(const grpc::string *host, AsynchronousService* service) {
+  GPR_ASSERT(service->server_ == nullptr &&
              "Can only register an asynchronous service against one server.");
-  service->dispatch_impl_ = this;
+  service->server_ = this;
   service->request_args_ = new void*[service->method_count_];
   for (size_t i = 0; i < service->method_count_; ++i) {
     void* tag = grpc_server_register_method(server_, service->method_names_[i],
-                                            nullptr);
+                                            host ? host->c_str() : nullptr);
     if (!tag) {
       gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
               service->method_names_[i]);
@@ -288,6 +261,7 @@
   // Start processing rpcs.
   if (!sync_methods_->empty()) {
     for (auto m = sync_methods_->begin(); m != sync_methods_->end(); m++) {
+      m->SetupRequest();
       m->Request(server_, cq_.cq());
     }
 
@@ -318,141 +292,90 @@
   }
 }
 
-void Server::PerformOpsOnCall(CallOpBuffer* buf, Call* call) {
+void Server::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) {
   static const size_t MAX_OPS = 8;
-  size_t nops = MAX_OPS;
-  grpc_op ops[MAX_OPS];
-  buf->FillOps(ops, &nops);
+  size_t nops = 0;
+  grpc_op cops[MAX_OPS];
+  ops->FillOps(cops, &nops);
   GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_call_start_batch(call->call(), ops, nops, buf));
+             grpc_call_start_batch(call->call(), cops, nops, ops));
 }
 
-class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
- public:
-  AsyncRequest(Server* server, void* registered_method, ServerContext* ctx,
-               grpc::protobuf::Message* request,
-               ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
-               ServerCompletionQueue* notification_cq, void* tag)
-      : tag_(tag),
-        request_(request),
-        stream_(stream),
-        call_cq_(call_cq),
-        ctx_(ctx),
-        generic_ctx_(nullptr),
-        server_(server),
-        call_(nullptr),
-        payload_(nullptr) {
-    memset(&array_, 0, sizeof(array_));
-    grpc_call_details_init(&call_details_);
-    GPR_ASSERT(notification_cq);
-    GPR_ASSERT(call_cq);
-    grpc_server_request_registered_call(
-        server->server_, registered_method, &call_, &call_details_.deadline,
-        &array_, request ? &payload_ : nullptr, call_cq->cq(),
-        notification_cq->cq(), this);
-  }
-
-  AsyncRequest(Server* server, GenericServerContext* ctx,
-               ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
-               ServerCompletionQueue* notification_cq, void* tag)
-      : tag_(tag),
-        request_(nullptr),
-        stream_(stream),
-        call_cq_(call_cq),
-        ctx_(nullptr),
-        generic_ctx_(ctx),
-        server_(server),
-        call_(nullptr),
-        payload_(nullptr) {
-    memset(&array_, 0, sizeof(array_));
-    grpc_call_details_init(&call_details_);
-    GPR_ASSERT(notification_cq);
-    GPR_ASSERT(call_cq);
-    grpc_server_request_call(server->server_, &call_, &call_details_, &array_,
-                             call_cq->cq(), notification_cq->cq(), this);
-  }
-
-  ~AsyncRequest() {
-    if (payload_) {
-      grpc_byte_buffer_destroy(payload_);
-    }
-    grpc_metadata_array_destroy(&array_);
-  }
-
-  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
-    *tag = tag_;
-    bool orig_status = *status;
-    if (*status && request_) {
-      if (payload_) {
-        GRPC_TIMER_BEGIN(GRPC_PTAG_PROTO_DESERIALIZE, call_);
-        *status =
-            DeserializeProto(payload_, request_, server_->max_message_size_);
-        GRPC_TIMER_END(GRPC_PTAG_PROTO_DESERIALIZE, call_);
-      } else {
-        *status = false;
-      }
-    }
-    ServerContext* ctx = ctx_ ? ctx_ : generic_ctx_;
-    GPR_ASSERT(ctx);
-    if (*status) {
-      ctx->deadline_ = call_details_.deadline;
-      for (size_t i = 0; i < array_.count; i++) {
-        ctx->client_metadata_.insert(std::make_pair(
-            grpc::string(array_.metadata[i].key),
-            grpc::string(
-                array_.metadata[i].value,
-                array_.metadata[i].value + array_.metadata[i].value_length)));
-      }
-      if (generic_ctx_) {
-        // TODO(yangg) remove the copy here.
-        generic_ctx_->method_ = call_details_.method;
-        generic_ctx_->host_ = call_details_.host;
-        gpr_free(call_details_.method);
-        gpr_free(call_details_.host);
-      }
-    }
-    ctx->call_ = call_;
-    ctx->cq_ = call_cq_;
-    Call call(call_, server_, call_cq_, server_->max_message_size_);
-    if (orig_status && call_) {
-      ctx->BeginCompletionOp(&call);
-    }
-    // just the pointers inside call are copied here
-    stream_->BindCall(&call);
-    delete this;
-    return true;
-  }
-
- private:
-  void* const tag_;
-  grpc::protobuf::Message* const request_;
-  ServerAsyncStreamingInterface* const stream_;
-  CompletionQueue* const call_cq_;
-  ServerContext* const ctx_;
-  GenericServerContext* const generic_ctx_;
-  Server* const server_;
-  grpc_call* call_;
-  grpc_call_details call_details_;
-  grpc_metadata_array array_;
-  grpc_byte_buffer* payload_;
-};
-
-void Server::RequestAsyncCall(void* registered_method, ServerContext* context,
-                              grpc::protobuf::Message* request,
-                              ServerAsyncStreamingInterface* stream,
-                              CompletionQueue* call_cq,
-                              ServerCompletionQueue* notification_cq,
-                              void* tag) {
-  new AsyncRequest(this, registered_method, context, request, stream, call_cq,
-                   notification_cq, tag);
+Server::BaseAsyncRequest::BaseAsyncRequest(
+    Server* server, ServerContext* context,
+    ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag)
+    : server_(server),
+      context_(context),
+      stream_(stream),
+      call_cq_(call_cq),
+      tag_(tag),
+      call_(nullptr) {
+  memset(&initial_metadata_array_, 0, sizeof(initial_metadata_array_));
 }
 
-void Server::RequestAsyncGenericCall(GenericServerContext* context,
-                                     ServerAsyncStreamingInterface* stream,
-                                     CompletionQueue* call_cq,
-                                     ServerCompletionQueue* notification_cq,
-                                     void* tag) {
-  new AsyncRequest(this, context, stream, call_cq, notification_cq, tag);
+Server::BaseAsyncRequest::~BaseAsyncRequest() {}
+
+bool Server::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) {
+  if (*status) {
+    for (size_t i = 0; i < initial_metadata_array_.count; i++) {
+      context_->client_metadata_.insert(std::make_pair(
+          grpc::string(initial_metadata_array_.metadata[i].key),
+          grpc::string(initial_metadata_array_.metadata[i].value,
+                       initial_metadata_array_.metadata[i].value +
+                           initial_metadata_array_.metadata[i].value_length)));
+    }
+  }
+  grpc_metadata_array_destroy(&initial_metadata_array_);
+  context_->set_call(call_);
+  context_->cq_ = call_cq_;
+  Call call(call_, server_, call_cq_, server_->max_message_size_);
+  if (*status && call_) {
+    context_->BeginCompletionOp(&call);
+  }
+  // just the pointers inside call are copied here
+  stream_->BindCall(&call);
+  *tag = tag_;
+  delete this;
+  return true;
+}
+
+Server::RegisteredAsyncRequest::RegisteredAsyncRequest(
+    Server* server, ServerContext* context,
+    ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag)
+    : BaseAsyncRequest(server, context, stream, call_cq, tag) {}
+
+void Server::RegisteredAsyncRequest::IssueRequest(
+    void* registered_method, grpc_byte_buffer** payload,
+    ServerCompletionQueue* notification_cq) {
+  grpc_server_request_registered_call(
+      server_->server_, registered_method, &call_, &context_->deadline_,
+      &initial_metadata_array_, payload, call_cq_->cq(), notification_cq->cq(),
+      this);
+}
+
+Server::GenericAsyncRequest::GenericAsyncRequest(
+    Server* server, GenericServerContext* context,
+    ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
+    ServerCompletionQueue* notification_cq, void* tag)
+    : BaseAsyncRequest(server, context, stream, call_cq, tag) {
+  grpc_call_details_init(&call_details_);
+  GPR_ASSERT(notification_cq);
+  GPR_ASSERT(call_cq);
+  grpc_server_request_call(server->server_, &call_, &call_details_,
+                           &initial_metadata_array_, call_cq->cq(),
+                           notification_cq->cq(), this);
+}
+
+bool Server::GenericAsyncRequest::FinalizeResult(void** tag, bool* status) {
+  // TODO(yangg) remove the copy here.
+  if (*status) {
+    static_cast<GenericServerContext*>(context_)->method_ =
+        call_details_.method;
+    static_cast<GenericServerContext*>(context_)->host_ = call_details_.host;
+  }
+  gpr_free(call_details_.method);
+  gpr_free(call_details_.host);
+  return BaseAsyncRequest::FinalizeResult(tag, status);
 }
 
 void Server::ScheduleCallback() {
@@ -460,7 +383,7 @@
     grpc::unique_lock<grpc::mutex> lock(mu_);
     num_running_cb_++;
   }
-  thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this));
+  thread_pool_->Add(std::bind(&Server::RunRpc, this));
 }
 
 void Server::RunRpc() {
@@ -472,9 +395,13 @@
     if (ok) {
       SyncRequest::CallData cd(this, mrd);
       {
+        mrd->SetupRequest();
         grpc::unique_lock<grpc::mutex> lock(mu_);
         if (!shutdown_) {
           mrd->Request(server_, cq_.cq());
+        } else {
+          // destroy the structure that was created
+          mrd->TeardownRequest();
         }
       }
       cd.Run();
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 3ee1d54..f723d46 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -37,7 +37,7 @@
 #include <grpc/support/log.h>
 #include <grpc++/impl/service_type.h>
 #include <grpc++/server.h>
-#include "src/cpp/server/thread_pool.h"
+#include <grpc++/thread_pool_interface.h>
 
 namespace grpc {
 
@@ -51,11 +51,21 @@
 }
 
 void ServerBuilder::RegisterService(SynchronousService* service) {
-  services_.push_back(service->service());
+  services_.emplace_back(new NamedService<RpcService>(service->service()));
 }
 
 void ServerBuilder::RegisterAsyncService(AsynchronousService* service) {
-  async_services_.push_back(service);
+  async_services_.emplace_back(new NamedService<AsynchronousService>(service));
+}
+
+void ServerBuilder::RegisterService(
+    const grpc::string& addr, SynchronousService* service) {
+  services_.emplace_back(new NamedService<RpcService>(addr, service->service()));
+}
+
+void ServerBuilder::RegisterAsyncService(
+    const grpc::string& addr, AsynchronousService* service) {
+  async_services_.emplace_back(new NamedService<AsynchronousService>(addr, service));
 }
 
 void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) {
@@ -97,13 +107,13 @@
   }
   for (auto service = services_.begin(); service != services_.end();
        service++) {
-    if (!server->RegisterService(*service)) {
+    if (!server->RegisterService((*service)->host.get(), (*service)->service)) {
       return nullptr;
     }
   }
   for (auto service = async_services_.begin();
        service != async_services_.end(); service++) {
-    if (!server->RegisterAsyncService(*service)) {
+    if (!server->RegisterAsyncService((*service)->host.get(), (*service)->service)) {
       return nullptr;
     }
   }
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 6b5e41d..bf7a4ba 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -39,16 +39,19 @@
 #include <grpc++/impl/sync.h>
 #include <grpc++/time.h>
 
+#include "src/core/channel/compress_filter.h"
+#include "src/cpp/common/create_auth_context.h"
+
 namespace grpc {
 
 // CompletionOp
 
-class ServerContext::CompletionOp GRPC_FINAL : public CallOpBuffer {
+class ServerContext::CompletionOp GRPC_FINAL : public CallOpSetInterface {
  public:
   // initial refs: one in the server context, one in the cq
-  CompletionOp() : refs_(2), finalized_(false), cancelled_(false) {
-    AddServerRecvClose(&cancelled_);
-  }
+  CompletionOp() : refs_(2), finalized_(false), cancelled_(0) {}
+
+  void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE;
   bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
 
   bool CheckCancelled(CompletionQueue* cq);
@@ -59,7 +62,7 @@
   grpc::mutex mu_;
   int refs_;
   bool finalized_;
-  bool cancelled_;
+  int cancelled_;
 };
 
 void ServerContext::CompletionOp::Unref() {
@@ -73,14 +76,20 @@
 bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) {
   cq->TryPluck(this);
   grpc::lock_guard<grpc::mutex> g(mu_);
-  return finalized_ ? cancelled_ : false;
+  return finalized_ ? cancelled_ != 0 : false;
+}
+
+void ServerContext::CompletionOp::FillOps(grpc_op* ops, size_t* nops) {
+  ops->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  ops->data.recv_close_on_server.cancelled = &cancelled_;
+  ops->flags = 0;
+  *nops = 1;
 }
 
 bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
-  GPR_ASSERT(CallOpBuffer::FinalizeResult(tag, status));
   grpc::unique_lock<grpc::mutex> lock(mu_);
   finalized_ = true;
-  if (!*status) cancelled_ = true;
+  if (!*status) cancelled_ = 1;
   if (--refs_ == 0) {
     lock.unlock();
     delete this;
@@ -136,8 +145,38 @@
   trailing_metadata_.insert(std::make_pair(key, value));
 }
 
-bool ServerContext::IsCancelled() {
+bool ServerContext::IsCancelled() const {
   return completion_op_ && completion_op_->CheckCancelled(cq_);
 }
 
+void ServerContext::set_compression_level(grpc_compression_level level) {
+  const grpc_compression_algorithm algorithm_for_level =
+      grpc_compression_algorithm_for_level(level);
+  set_compression_algorithm(algorithm_for_level);
+}
+
+void ServerContext::set_compression_algorithm(
+    grpc_compression_algorithm algorithm) {
+  char* algorithm_name = NULL;
+  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);
+  AddInitialMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
+}
+
+void ServerContext::set_call(grpc_call* call) {
+  call_ = call;
+  auth_context_ = CreateAuthContext(call);
+}
+
+std::shared_ptr<const AuthContext> ServerContext::auth_context() const {
+  if (auth_context_.get() == nullptr) {
+    auth_context_ = CreateAuthContext(call_);
+  }
+  return auth_context_;
+}
+
 }  // namespace grpc
diff --git a/src/cpp/server/server_credentials.cc b/src/cpp/server/server_credentials.cc
index 6bdb465..be3a742 100644
--- a/src/cpp/server/server_credentials.cc
+++ b/src/cpp/server/server_credentials.cc
@@ -31,8 +31,6 @@
  *
  */
 
-#include <grpc/grpc_security.h>
-
 #include <grpc++/server_credentials.h>
 
 namespace grpc {
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index a78e422..a66c92c 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -36,7 +36,7 @@
 
 namespace grpc {
 
-ByteBuffer::ByteBuffer(Slice* slices, size_t nslices) {
+ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) {
   // TODO(yangg) maybe expose some core API to simplify this
   std::vector<gpr_slice> c_slices(nslices);
   for (size_t i = 0; i < nslices; i++) {
@@ -52,20 +52,20 @@
   }
 }
 
-void ByteBuffer::Dump(std::vector<Slice>* slices) {
+void ByteBuffer::Dump(std::vector<Slice>* slices) const {
   slices->clear();
   if (!buffer_) {
     return;
   }
   grpc_byte_buffer_reader reader;
-  grpc_byte_buffer_reader_init(&reader,buffer_);
+  grpc_byte_buffer_reader_init(&reader, buffer_);
   gpr_slice s;
   while (grpc_byte_buffer_reader_next(&reader, &s)) {
     slices->push_back(Slice(s, Slice::STEAL_REF));
   }
 }
 
-size_t ByteBuffer::Length() {
+size_t ByteBuffer::Length() const {
   if (buffer_) {
     return grpc_byte_buffer_length(buffer_);
   } else {
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index fd94d00..a814cad 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -51,13 +51,15 @@
   system_clock::duration deadline = from.time_since_epoch();
   seconds secs = duration_cast<seconds>(deadline);
   if (from == system_clock::time_point::max() ||
-      secs.count() >= gpr_inf_future.tv_sec || secs.count() < 0) {
-    *to = gpr_inf_future;
+      secs.count() >= gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec ||
+      secs.count() < 0) {
+    *to = gpr_inf_future(GPR_CLOCK_REALTIME);
     return;
   }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
   to->tv_sec = secs.count();
   to->tv_nsec = nsecs.count();
+  to->clock_type = GPR_CLOCK_REALTIME;
 }
 
 void TimepointHR2Timespec(const high_resolution_clock::time_point& from,
@@ -65,17 +67,19 @@
   high_resolution_clock::duration deadline = from.time_since_epoch();
   seconds secs = duration_cast<seconds>(deadline);
   if (from == high_resolution_clock::time_point::max() ||
-      secs.count() >= gpr_inf_future.tv_sec || secs.count() < 0) {
-    *to = gpr_inf_future;
+      secs.count() >= gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec ||
+      secs.count() < 0) {
+    *to = gpr_inf_future(GPR_CLOCK_REALTIME);
     return;
   }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
   to->tv_sec = secs.count();
   to->tv_nsec = nsecs.count();
+  to->clock_type = GPR_CLOCK_REALTIME;
 }
 
 system_clock::time_point Timespec2Timepoint(gpr_timespec t) {
-  if (gpr_time_cmp(t, gpr_inf_future) == 0) {
+  if (gpr_time_cmp(t, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) {
     return system_clock::time_point::max();
   }
   system_clock::time_point tp;
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index e6abbbf..fdec2e7 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -68,6 +68,9 @@
     <Reference Include="System.Net.Http.WebRequest" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="GoogleCredential.cs" />
     <Compile Include="OAuth2InterceptorFactory.cs" />
@@ -81,6 +84,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />
+    <None Include="Grpc.Auth.nuspec" />
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index e7a538b..1262bdb 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -5,19 +5,19 @@
     <title>gRPC C# Auth</title>
     <summary>Auth library for C# implementation of gRPC - an RPC library and framework</summary>
     <description>Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
+    <releaseNotes>Release $version$ of gRPC C#</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
 	<dependencies>
 	  <dependency id="BouncyCastle" version="1.7.0" />
 	  <dependency id="Google.Apis.Auth" version="1.9.1" />
-	  <dependency id="Grpc.Core" version="0.5.1" />
+	  <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
   <files>
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
index ca384d1..420c4cb 100644
--- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
+++ b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
@@ -52,10 +52,10 @@
         /// <summary>
         /// Creates OAuth2 interceptor.
         /// </summary>
-        public static HeaderInterceptorDelegate Create(GoogleCredential googleCredential)
+        public static MetadataInterceptorDelegate Create(GoogleCredential googleCredential)
         {
             var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
-            return new HeaderInterceptorDelegate(interceptor.InterceptHeaders);
+            return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
         }
 
         /// <summary>
@@ -94,10 +94,10 @@
                 return credential.Token.AccessToken;
             }
 
-            public void InterceptHeaders(Metadata.Builder headerBuilder)
+            public void InterceptHeaders(Metadata metadata)
             {
                 var accessToken = GetAccessToken(CancellationToken.None);
-                headerBuilder.Add(new Metadata.MetadataEntry(AuthorizationHeader, Schema + " " + accessToken));
+                metadata.Add(new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken));
             }
         }
     }
diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
index c442ccc..70cb32d 100644
--- a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
@@ -9,6 +9,5 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
 
 [assembly: InternalsVisibleTo("Grpc.Auth.Tests")]
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index c09d0b1..e797dd8 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -73,12 +73,6 @@
         Server server;
         Channel channel;
 
-        [TestFixtureSetUp]
-        public void InitClass()
-        {
-            GrpcEnvironment.Initialize();
-        }
-
         [SetUp]
         public void Init()
         {
@@ -204,23 +198,21 @@
             BenchmarkUtil.RunBenchmark(100, 100,
                                        () => { Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)); });
         }
-
-//        TODO(jtattermusch): temporarily commented out for #1731
-//                            to be uncommented along with PR #1577
-//        [Test]
-//        public void UnknownMethodHandler()
-//        {
-//            var call = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
-//            try
-//            {
-//                Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken));
-//                Assert.Fail();
-//            }
-//            catch (RpcException e)
-//            {
-//                Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode);
-//            }
-//        }
+            
+        [Test]
+        public void UnknownMethodHandler()
+        {
+            var call = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
+            try
+            {
+                Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken));
+                Assert.Fail();
+            }
+            catch (RpcException e)
+            {
+                Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode);
+            }
+        }
 
         private static async Task<string> EchoHandler(ServerCallContext context, string request)
         {
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 92e28b7..927954c 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -37,6 +37,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ClientServerTest.cs" />
     <Compile Include="ServerTest.cs" />
@@ -63,4 +66,4 @@
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
   <ItemGroup />
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index 6a132a5..9ae1277 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -43,16 +43,17 @@
         [Test]
         public void InitializeAndShutdownGrpcEnvironment()
         {
-            GrpcEnvironment.Initialize();
-            Assert.IsNotNull(GrpcEnvironment.ThreadPool.CompletionQueue);
+            var env = GrpcEnvironment.GetInstance();
+            Assert.IsNotNull(env.CompletionQueue);
             GrpcEnvironment.Shutdown();
         }
 
         [Test]
         public void SubsequentInvocations()
         {
-            GrpcEnvironment.Initialize();
-            GrpcEnvironment.Initialize();
+            var env1 = GrpcEnvironment.GetInstance();
+            var env2 = GrpcEnvironment.GetInstance();
+            Assert.IsTrue(object.ReferenceEquals(env1, env2));
             GrpcEnvironment.Shutdown();
             GrpcEnvironment.Shutdown();
         }
@@ -60,15 +61,13 @@
         [Test]
         public void InitializeAfterShutdown()
         {
-            GrpcEnvironment.Initialize();
-            var tp1 = GrpcEnvironment.ThreadPool;
+            var env1 = GrpcEnvironment.GetInstance();
             GrpcEnvironment.Shutdown();
 
-            GrpcEnvironment.Initialize();
-            var tp2 = GrpcEnvironment.ThreadPool;
+            var env2 = GrpcEnvironment.GetInstance();
             GrpcEnvironment.Shutdown();
 
-            Assert.IsFalse(object.ReferenceEquals(tp1, tp2));
+            Assert.IsFalse(object.ReferenceEquals(env1, env2));
         }
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
index 2f60134..320423b 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
@@ -44,17 +44,17 @@
         [Test]
         public void CreateEmptyAndDestroy()
         {
-            var metadata = Metadata.CreateBuilder().Build();
-            var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
+            var nativeMetadata = MetadataArraySafeHandle.Create(new Metadata());
             nativeMetadata.Dispose();
         }
 
         [Test]
         public void CreateAndDestroy()
         {
-            var metadata = Metadata.CreateBuilder()
-                .Add(new Metadata.MetadataEntry("host", "somehost"))
-                .Add(new Metadata.MetadataEntry("header2", "header value")).Build();
+            var metadata = new Metadata {
+                new Metadata.Entry("host", "somehost"),
+                new Metadata.Entry("header2", "header value"),
+            };
             var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
             nativeMetadata.Dispose();
         }
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index 8b3c910..714c2f7 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -53,18 +53,6 @@
         [DllImport("grpc_csharp_ext.dll")]
         static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
 
-        [TestFixtureSetUp]
-        public void Init()
-        {
-            GrpcEnvironment.Initialize();
-        }
-
-        [TestFixtureTearDown]
-        public void Cleanup()
-        {
-            GrpcEnvironment.Shutdown();
-        }
-
         /// <summary>
         /// (~1.26us .NET Windows)
         /// </summary>
diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
index 7f6133a..c2e5e81 100644
--- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index 02c773c..1119aa3 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -44,13 +44,10 @@
         [Test]
         public void StartAndShutdownServer()
         {
-            GrpcEnvironment.Initialize();
-
             Server server = new Server();
             server.AddListeningPort("localhost", Server.PickUnusedPort);
             server.Start();
             server.ShutdownAsync().Wait();
-
             GrpcEnvironment.Shutdown();
         }
     }
diff --git a/src/csharp/Grpc.Core.Tests/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/TimespecTest.cs
index f5bae6d..5831121 100644
--- a/src/csharp/Grpc.Core.Tests/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/TimespecTest.cs
@@ -61,28 +61,28 @@
         [Test]
         public void Add()
         {
-            var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = new IntPtr(123456789) };
+            var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 };
             var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10));
             Assert.AreEqual(result.tv_sec, new IntPtr(12355));
-            Assert.AreEqual(result.tv_nsec, new IntPtr(123456789));
+            Assert.AreEqual(result.tv_nsec, 123456789);
         }
 
         [Test]
         public void Add_Nanos()
         {
-            var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = new IntPtr(123456789) };
+            var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 };
             var result = t.Add(TimeSpan.FromTicks(10));
             Assert.AreEqual(result.tv_sec, new IntPtr(12345));
-            Assert.AreEqual(result.tv_nsec, new IntPtr(123456789 + 1000));
+            Assert.AreEqual(result.tv_nsec, 123456789 + 1000);
         }
 
         [Test]
         public void Add_NanosOverflow()
         {
-            var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = new IntPtr(999999999) };
+            var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 999999999 };
             var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10 + 10));
             Assert.AreEqual(result.tv_sec, new IntPtr(12356));
-            Assert.AreEqual(result.tv_nsec, new IntPtr(999));
+            Assert.AreEqual(result.tv_nsec, 999);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index 9f8baac..9e95182 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -39,7 +39,7 @@
 namespace Grpc.Core
 {
     /// <summary>
-    /// Helper methods for generated client stubs to make RPC calls.
+    /// Helper methods for generated clients to make RPC calls.
     /// </summary>
     public static class Calls
     {
@@ -58,7 +58,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             return await asyncResult;
@@ -69,7 +69,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             asyncCall.StartServerStreamingCall(req, call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
@@ -81,7 +81,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@@ -93,7 +93,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             asyncCall.StartDuplexStreamingCall(call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@@ -108,13 +108,5 @@
                 token.Register(() => asyncCall.Cancel());
             }
         }
-
-        /// <summary>
-        /// Gets shared completion queue used for async calls.
-        /// </summary>
-        private static CompletionQueueSafeHandle GetCompletionQueue()
-        {
-            return GrpcEnvironment.ThreadPool.CompletionQueue;
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index d6bfbb7..5baf260 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -42,8 +42,10 @@
     /// </summary>
     public class Channel : IDisposable
     {
+        readonly GrpcEnvironment environment;
         readonly ChannelSafeHandle handle;
         readonly string target;
+        bool disposed;
 
         /// <summary>
         /// Creates a channel that connects to a specific host.
@@ -54,6 +56,7 @@
         /// <param name="options">Channel options.</param>
         public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
         {
+            this.environment = GrpcEnvironment.GetInstance();
             using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options))
             {
                 if (credentials != null)
@@ -105,10 +108,35 @@
             }
         }
 
+        internal CompletionQueueSafeHandle CompletionQueue
+        {
+            get
+            {
+                return this.environment.CompletionQueue;
+            }
+        }
+
+        internal CompletionRegistry CompletionRegistry
+        {
+            get
+            {
+                return this.environment.CompletionRegistry;
+            }
+        }
+
+        internal GrpcEnvironment Environment
+        {
+            get
+            {
+                return this.environment;
+            }
+        }
+
         protected virtual void Dispose(bool disposing)
         {
-            if (handle != null && !handle.IsInvalid)
+            if (disposing && handle != null && !disposed)
             {
+                disposed = true;
                 handle.Dispose();
             }
         }
diff --git a/src/csharp/Grpc.Core/Stub/AbstractStub.cs b/src/csharp/Grpc.Core/ClientBase.cs
similarity index 69%
rename from src/csharp/Grpc.Core/Stub/AbstractStub.cs
rename to src/csharp/Grpc.Core/ClientBase.cs
index 4a8b254..a099f96 100644
--- a/src/csharp/Grpc.Core/Stub/AbstractStub.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -32,26 +32,39 @@
 #endregion
 
 using System;
+using System.Collections.Generic;
+
 using Grpc.Core.Internal;
 
 namespace Grpc.Core
 {
-    // TODO: support adding timeout to methods.
+    public delegate void MetadataInterceptorDelegate(Metadata metadata);
+
     /// <summary>
-    /// Base for client-side stubs.
+    /// Base class for client-side stubs.
     /// </summary>
-    public abstract class AbstractStub<TStub, TConfig>
-        where TConfig : StubConfiguration
+    public abstract class ClientBase
     {
         readonly Channel channel;
-        readonly TConfig config;
 
-        public AbstractStub(Channel channel, TConfig config)
+        public ClientBase(Channel channel)
         {
             this.channel = channel;
-            this.config = config;
         }
 
+        /// <summary>
+        /// Can be used to register a custom header (initial metadata) interceptor.
+        /// The delegate each time before a new call on this client is started.
+        /// </summary>
+        public MetadataInterceptorDelegate HeaderInterceptor
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Channel associated with this client.
+        /// </summary>
         public Channel Channel
         {
             get
@@ -63,13 +76,19 @@
         /// <summary>
         /// Creates a new call to given method.
         /// </summary>
-        protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method)
+        protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata)
             where TRequest : class
             where TResponse : class
         {
-            var headerBuilder = Metadata.CreateBuilder();
-            config.HeaderInterceptor(headerBuilder);
-            return new Call<TRequest, TResponse>(serviceName, method, channel, headerBuilder.Build());
+            var interceptor = HeaderInterceptor;
+            if (interceptor != null)
+            {
+                metadata = metadata ?? new Metadata();
+                interceptor(metadata);
+                metadata.Freeze();
+            }
+            metadata = metadata ?? Metadata.Empty;
+            return new Call<TRequest, TResponse>(serviceName, method, channel, metadata);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index a36a6a5..a227fe5 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -33,8 +33,9 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="System.Collections.Immutable">
-      <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+    <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
     </Reference>
     <Reference Include="System.Interactive.Async">
       <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
@@ -48,6 +49,7 @@
     <Compile Include="IAsyncStreamWriter.cs" />
     <Compile Include="IAsyncStreamReader.cs" />
     <Compile Include="Internal\GrpcLog.cs" />
+    <Compile Include="Version.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RpcException.cs" />
     <Compile Include="Calls.cs" />
@@ -86,8 +88,7 @@
     <Compile Include="ServerCredentials.cs" />
     <Compile Include="Metadata.cs" />
     <Compile Include="Internal\MetadataArraySafeHandle.cs" />
-    <Compile Include="Stub\AbstractStub.cs" />
-    <Compile Include="Stub\StubConfiguration.cs" />
+    <Compile Include="ClientBase.cs" />
     <Compile Include="Internal\ServerCalls.cs" />
     <Compile Include="ServerMethods.cs" />
     <Compile Include="Internal\ClientRequestStream.cs" />
@@ -103,6 +104,7 @@
     <Compile Include="ChannelOptions.cs" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.Core.nuspec" />
     <None Include="packages.config" />
   </ItemGroup>
   <Choose>
@@ -130,4 +132,4 @@
   </Target>
   <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
   <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 629b978..5ace6dc 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -5,19 +5,19 @@
     <title>gRPC C# Core</title>
     <summary>Core C# implementation of gRPC - an RPC library and framework</summary>
     <description>Core C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
+    <releaseNotes>Release $version$ of gRPC C#</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
 	<dependencies>
-	  <dependency id="Microsoft.Bcl.Immutable" version="1.0.34" />
+	  <dependency id="System.Collections.Immutable" version="1.1.36" />
 	  <dependency id="Ix-Async" version="1.2.3" />
-	  <dependency id="grpc.native.csharp_ext" version="0.9.1" />
+	  <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
     </dependencies>
   </metadata>
   <files>
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 30ff289..47d1651 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -33,7 +33,9 @@
 
 using System;
 using System.Runtime.InteropServices;
+using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
@@ -51,20 +53,18 @@
         static extern void grpcsharp_shutdown();
 
         static object staticLock = new object();
-        static volatile GrpcEnvironment instance;
+        static GrpcEnvironment instance;
 
         readonly GrpcThreadPool threadPool;
         readonly CompletionRegistry completionRegistry;
+        readonly DebugStats debugStats = new DebugStats();
         bool isClosed;
 
         /// <summary>
-        /// Makes sure GRPC environment is initialized. Subsequent invocations don't have any
-        /// effect unless you call Shutdown first.
-        /// Although normal use cases assume you will call this just once in your application's
-        /// lifetime (and call Shutdown once you're done), for the sake of easier testing it's
-        /// allowed to initialize the environment again after it has been successfully shutdown.
+        /// Returns an instance of initialized gRPC environment.
+        /// Subsequent invocations return the same instance unless Shutdown has been called first.
         /// </summary>
-        public static void Initialize()
+        internal static GrpcEnvironment GetInstance()
         {
             lock (staticLock)
             {
@@ -72,12 +72,13 @@
                 {
                     instance = new GrpcEnvironment();
                 }
+                return instance;
             }
         }
 
         /// <summary>
-        /// Shuts down the GRPC environment if it was initialized before.
-        /// Repeated invocations have no effect.
+        /// Shuts down the gRPC environment if it was initialized before.
+        /// Blocks until the environment has been fully shutdown.
         /// </summary>
         public static void Shutdown()
         {
@@ -87,38 +88,10 @@
                 {
                     instance.Close();
                     instance = null;
-
-                    CheckDebugStats();
                 }
             }
         }
 
-        internal static GrpcThreadPool ThreadPool
-        {
-            get
-            {
-                var inst = instance;
-                if (inst == null)
-                {
-                    throw new InvalidOperationException("GRPC environment not initialized");
-                }
-                return inst.threadPool;
-            }
-        }
-
-        internal static CompletionRegistry CompletionRegistry
-        {
-            get
-            {
-                var inst = instance;
-                if (inst == null)
-                {
-                    throw new InvalidOperationException("GRPC environment not initialized");
-                }
-                return inst.completionRegistry;
-            }
-        }
-
         /// <summary>
         /// Creates gRPC environment.
         /// </summary>
@@ -126,14 +99,47 @@
         {
             GrpcLog.RedirectNativeLogs(Console.Error);
             grpcsharp_init();
-            completionRegistry = new CompletionRegistry();
-            threadPool = new GrpcThreadPool(THREAD_POOL_SIZE);
+            completionRegistry = new CompletionRegistry(this);
+            threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
             threadPool.Start();
             // TODO: use proper logging here
             Console.WriteLine("GRPC initialized.");
         }
 
         /// <summary>
+        /// Gets the completion registry used by this gRPC environment.
+        /// </summary>
+        internal CompletionRegistry CompletionRegistry
+        {
+            get
+            {
+                return this.completionRegistry;
+            }
+        }
+
+        /// <summary>
+        /// Gets the completion queue used by this gRPC environment.
+        /// </summary>
+        internal CompletionQueueSafeHandle CompletionQueue
+        {
+            get
+            {
+                return this.threadPool.CompletionQueue;
+            }
+        }
+
+        /// <summary>
+        /// Gets the completion queue used by this gRPC environment.
+        /// </summary>
+        internal DebugStats DebugStats
+        {
+            get
+            {
+                return this.debugStats;
+            }
+        }
+
+        /// <summary>
         /// Shuts down this environment.
         /// </summary>
         private void Close()
@@ -146,32 +152,28 @@
             grpcsharp_shutdown();
             isClosed = true;
 
+            debugStats.CheckOK();
+
             // TODO: use proper logging here
             Console.WriteLine("GRPC shutdown.");
         }
 
-        private static void CheckDebugStats()
+        /// <summary>
+        /// Shuts down this environment asynchronously.
+        /// </summary>
+        private Task CloseAsync()
         {
-            var remainingClientCalls = DebugStats.ActiveClientCalls.Count;
-            if (remainingClientCalls != 0)
-            {                
-                DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
-            }
-            var remainingServerCalls = DebugStats.ActiveServerCalls.Count;
-            if (remainingServerCalls != 0)
+            return Task.Run(() =>
             {
-                DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
-            }
-            var pendingBatchCompletions = DebugStats.PendingBatchCompletions.Count;
-            if (pendingBatchCompletions != 0)
-            {
-                DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
-            }
-        }
-
-        private static void DebugWarning(string message)
-        {
-            throw new Exception("Shutdown check: " + message);
+                try
+                {
+                    Close();
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e);
+                }
+            });
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index d350f45..24b75d1 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -47,6 +47,8 @@
     /// </summary>
     internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
     {
+        Channel channel;
+
         // Completion of a pending unary response if not null.
         TaskCompletionSource<TResponse> unaryResponseTcs;
 
@@ -61,8 +63,9 @@
 
         public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
         {
-            var call = CallSafeHandle.Create(channel.Handle, cq, methodName, channel.Target, Timespec.InfFuture);
-            DebugStats.ActiveClientCalls.Increment();
+            this.channel = channel;
+            var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture);
+            channel.Environment.DebugStats.ActiveClientCalls.Increment();
             InitializeInternal(call);
         }
 
@@ -277,7 +280,7 @@
 
         protected override void OnReleaseResources()
         {
-            DebugStats.ActiveClientCalls.Decrement();
+            channel.Environment.DebugStats.ActiveClientCalls.Decrement();
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index db1b869..309067e 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -48,14 +48,17 @@
     internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
     {
         readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
+        readonly GrpcEnvironment environment;
 
-        public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer) : base(serializer, deserializer)
+        public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
         {
+            this.environment = Preconditions.CheckNotNull(environment);
         }
 
         public void Initialize(CallSafeHandle call)
         {
-            DebugStats.ActiveServerCalls.Increment();
+            call.SetCompletionRegistry(environment.CompletionRegistry);
+            environment.DebugStats.ActiveServerCalls.Increment();
             InitializeInternal(call);
         }
 
@@ -107,13 +110,14 @@
 
                 call.StartSendStatusFromServer(status, HandleHalfclosed);
                 halfcloseRequested = true;
+                readingDone = true;
                 sendCompletionDelegate = completionDelegate;
             }
         }
 
         protected override void OnReleaseResources()
         {
-            DebugStats.ActiveServerCalls.Decrement();
+            environment.DebugStats.ActiveServerCalls.Decrement();
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index ef92b44..3b246ac 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -43,6 +43,7 @@
     internal class CallSafeHandle : SafeHandleZeroIsInvalid
     {
         const uint GRPC_WRITE_BUFFER_HINT = 1;
+        CompletionRegistry completionRegistry;
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
@@ -97,15 +98,22 @@
         {
         }
 
-        public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
+        public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
         {
-            return grpcsharp_channel_create_call(channel, cq, method, host, deadline);
+            var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline);
+            result.SetCompletionRegistry(registry);
+            return result;
+        }
+
+        public void SetCompletionRegistry(CompletionRegistry completionRegistry)
+        {
+            this.completionRegistry = completionRegistry;
         }
 
         public void StartUnary(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray)
                 .CheckOk();
         }
@@ -119,56 +127,56 @@
         public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
         }
 
         public void StartServerStreaming(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray).CheckOk();
         }
 
         public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
         }
 
         public void StartSendMessage(byte[] payload, BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length)).CheckOk();
         }
 
         public void StartSendCloseFromClient(BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
         }
 
         public void StartSendStatusFromServer(Status status, BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail).CheckOk();
         }
 
         public void StartReceiveMessage(BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_recv_message(this, ctx).CheckOk();
         }
 
         public void StartServerSide(BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_serverside(this, ctx).CheckOk();
         }
 
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index 80f006a..f6d8aa0 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -45,11 +45,17 @@
 
     internal class CompletionRegistry
     {
-        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();  
+        readonly GrpcEnvironment environment;
+        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
+
+        public CompletionRegistry(GrpcEnvironment environment)
+        {
+            this.environment = environment;
+        }
 
         public void Register(IntPtr key, OpCompletionDelegate callback)
         {
-            DebugStats.PendingBatchCompletions.Increment();
+            environment.DebugStats.PendingBatchCompletions.Increment();
             Preconditions.CheckState(dict.TryAdd(key, callback));
         }
 
@@ -63,7 +69,7 @@
         {
             OpCompletionDelegate value;
             Preconditions.CheckState(dict.TryRemove(key, out value));
-            DebugStats.PendingBatchCompletions.Decrement();
+            environment.DebugStats.PendingBatchCompletions.Decrement();
             return value;
         }
 
diff --git a/src/csharp/Grpc.Core/Internal/DebugStats.cs b/src/csharp/Grpc.Core/Internal/DebugStats.cs
index ef9d9af..8793450 100644
--- a/src/csharp/Grpc.Core/Internal/DebugStats.cs
+++ b/src/csharp/Grpc.Core/Internal/DebugStats.cs
@@ -36,12 +36,39 @@
 
 namespace Grpc.Core.Internal
 {
-    internal static class DebugStats
+    internal class DebugStats
     {
-        public static readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
+        public readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
 
-        public static readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
+        public readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
 
-        public static readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
+        public readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
+
+        /// <summary>
+        /// Checks the debug stats and take action for any inconsistency found.
+        /// </summary>
+        public void CheckOK()
+        {
+            var remainingClientCalls = ActiveClientCalls.Count;
+            if (remainingClientCalls != 0)
+            {                
+                DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
+            }
+            var remainingServerCalls = ActiveServerCalls.Count;
+            if (remainingServerCalls != 0)
+            {
+                DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
+            }
+            var pendingBatchCompletions = PendingBatchCompletions.Count;
+            if (pendingBatchCompletions != 0)
+            {
+                DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
+            }
+        }
+
+        private void DebugWarning(string message)
+        {
+            throw new Exception("Shutdown check: " + message);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/Enums.cs b/src/csharp/Grpc.Core/Internal/Enums.cs
index af11b5b..1850981 100644
--- a/src/csharp/Grpc.Core/Internal/Enums.cs
+++ b/src/csharp/Grpc.Core/Internal/Enums.cs
@@ -90,4 +90,19 @@
         /* operation completion */
         OpComplete
     }
+
+    /// <summary>
+    /// gpr_clock_type from grpc/support/time.h
+    /// </summary>
+    internal enum GPRClockType
+    {
+        /* Monotonic clock */
+        Monotonic,
+
+        /* Realtime clock */
+        Realtime,
+
+        /* Timespan - the distance between two time points */
+        Timespan
+    }
 }
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 89b44a4..b77e893 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -45,14 +45,16 @@
     /// </summary>
     internal class GrpcThreadPool
     {
+        readonly GrpcEnvironment environment;
         readonly object myLock = new object();
         readonly List<Thread> threads = new List<Thread>();
         readonly int poolSize;
 
         CompletionQueueSafeHandle cq;
 
-        public GrpcThreadPool(int poolSize)
+        public GrpcThreadPool(GrpcEnvironment environment, int poolSize)
         {
+            this.environment = environment;
             this.poolSize = poolSize;
         }
 
@@ -80,7 +82,7 @@
             {
                 cq.Shutdown();
 
-                Console.WriteLine("Waiting for GPRC threads to finish.");
+                Console.WriteLine("Waiting for GRPC threads to finish.");
                 foreach (var thread in threads)
                 {
                     thread.Join();
@@ -122,7 +124,7 @@
                     IntPtr tag = ev.tag;
                     try
                     {
-                        var callback = GrpcEnvironment.CompletionRegistry.Extract(tag);
+                        var callback = environment.CompletionRegistry.Extract(tag);
                         callback(success);
                     }
                     catch (Exception e)
diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
index c9c4d95..80aa7f5 100644
--- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
@@ -54,11 +54,11 @@
 
         public static MetadataArraySafeHandle Create(Metadata metadata)
         {
-            var entries = metadata.Entries;
-            var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)entries.Count));
-            for (int i = 0; i < entries.Count; i++)
+            // TODO(jtattermusch): we might wanna check that the metadata is readonly 
+            var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count));
+            for (int i = 0; i < metadata.Count; i++)
             {
-                grpcsharp_metadata_array_add(metadataArray, entries[i].Key, entries[i].ValueBytes, new UIntPtr((ulong)entries[i].ValueBytes.Length));
+                grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, metadata[i].ValueBytes, new UIntPtr((ulong)metadata[i].ValueBytes.Length));
             }
             return metadataArray;
         }
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index f494d9e..594e46b 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -42,7 +42,7 @@
 {
     internal interface IServerCallHandler
     {
-        Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq);
+        Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment);
     }
 
     internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -58,11 +58,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -110,11 +111,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -163,11 +165,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -219,11 +222,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -255,11 +259,11 @@
 
     internal class NoSuchMethodCallHandler : IServerCallHandler
     {
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             // We don't care about the payload type here.
             var asyncCall = new AsyncCallServer<byte[], byte[]>(
-                (payload) => payload, (payload) => payload);
+                (payload) => payload, (payload) => payload, environment);
             
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -267,8 +271,6 @@
             var responseStream = new ServerResponseStream<byte[], byte[]>(asyncCall);
 
             await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, "No such method."));
-            // TODO(jtattermusch): if we don't read what client has sent, the server call never gets disposed.
-            await requestStream.ToList();
             await finishedTask;
         }
     }
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 83dbb91..9e1170e 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -91,19 +91,19 @@
         {
             grpcsharp_server_start(this);
         }
-            
-        public void ShutdownAndNotify(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
+    
+        public void ShutdownAndNotify(BatchCompletionDelegate callback, GrpcEnvironment environment)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
-            grpcsharp_server_shutdown_and_notify_callback(this, cq, ctx);
+            environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            grpcsharp_server_shutdown_and_notify_callback(this, environment.CompletionQueue, ctx);
         }
 
-        public void RequestCall(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
+        public void RequestCall(BatchCompletionDelegate callback, GrpcEnvironment environment)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
-            grpcsharp_server_request_call(this, cq, ctx).CheckOk();
+            environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            grpcsharp_server_request_call(this, environment.CompletionQueue, ctx).CheckOk();
         }
 
         protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index 775af27..de783f5 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -55,7 +55,8 @@
         // NOTE: on linux 64bit  sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
         // so IntPtr seems to have the right size to work on both.
         public System.IntPtr tv_sec;
-        public System.IntPtr tv_nsec;
+        public int tv_nsec;
+        public GPRClockType clock_type;
 
         /// <summary>
         /// Timespec a long time in the future.
@@ -99,12 +100,13 @@
 
         public Timespec Add(TimeSpan timeSpan)
         {
-            long nanos = tv_nsec.ToInt64() + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanosPerTick;
+            long nanos = (long)tv_nsec + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanosPerTick;
             long overflow_sec = (nanos > NanosPerSecond) ? 1 : 0;
 
             Timespec result;
-            result.tv_nsec = new IntPtr(nanos % NanosPerSecond);
+            result.tv_nsec = (int)(nanos % NanosPerSecond);
             result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec);
+            result.clock_type = GPRClockType.Realtime;
             return result;
         }
     }
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index eccec26..4552d39 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -30,55 +30,163 @@
 #endregion
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Immutable;
+using System.Collections.Specialized;
 using System.Runtime.InteropServices;
 using System.Text;
 
+using Grpc.Core.Utils;
+
 namespace Grpc.Core
 {
     /// <summary>
-    /// gRPC call metadata.
+    /// Provides access to read and write metadata values to be exchanged during a call.
     /// </summary>
-    public class Metadata
+    public sealed class Metadata : IList<Metadata.Entry>
     {
-        public static readonly Metadata Empty = new Metadata(ImmutableList<MetadataEntry>.Empty);
+        /// <summary>
+        /// An read-only instance of metadata containing no entries.
+        /// </summary>
+        public static readonly Metadata Empty = new Metadata().Freeze();
 
-        readonly ImmutableList<MetadataEntry> entries;
+        readonly List<Entry> entries;
+        bool readOnly;
 
-        public Metadata(ImmutableList<MetadataEntry> entries)
+        public Metadata()
         {
-            this.entries = entries;
+            this.entries = new List<Entry>();
         }
 
-        public ImmutableList<MetadataEntry> Entries
+        public Metadata(ICollection<Entry> entries)
+        {
+            this.entries = new List<Entry>(entries);
+        }
+
+        /// <summary>
+        /// Makes this object read-only.
+        /// </summary>
+        /// <returns>this object</returns>
+        public Metadata Freeze()
+        {
+            this.readOnly = true;
+            return this;
+        }
+
+        // TODO: add support for access by key
+
+        #region IList members
+
+        public int IndexOf(Metadata.Entry item)
+        {
+            return entries.IndexOf(item);
+        }
+
+        public void Insert(int index, Metadata.Entry item)
+        {
+            CheckWriteable();
+            entries.Insert(index, item);
+        }
+
+        public void RemoveAt(int index)
+        {
+            CheckWriteable();
+            entries.RemoveAt(index);
+        }
+
+        public Metadata.Entry this[int index]
         {
             get
             {
-                return this.entries;
+                return entries[index];
+            }
+
+            set
+            {
+                CheckWriteable();
+                entries[index] = value;
             }
         }
 
-        public static Builder CreateBuilder()
+        public void Add(Metadata.Entry item)
         {
-            return new Builder();
+            CheckWriteable();
+            entries.Add(item);
         }
-       
-        public struct MetadataEntry
+
+        public void Clear()
         {
+            CheckWriteable();
+            entries.Clear();
+        }
+
+        public bool Contains(Metadata.Entry item)
+        {
+            return entries.Contains(item);
+        }
+
+        public void CopyTo(Metadata.Entry[] array, int arrayIndex)
+        {
+            entries.CopyTo(array, arrayIndex);
+        }
+
+        public int Count
+        {
+            get { return entries.Count; }
+        }
+
+        public bool IsReadOnly
+        {
+            get { return readOnly; }
+        }
+
+        public bool Remove(Metadata.Entry item)
+        {
+            CheckWriteable();
+            return entries.Remove(item);
+        }
+
+        public IEnumerator<Metadata.Entry> GetEnumerator()
+        {
+            return entries.GetEnumerator();
+        }
+
+        IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            return entries.GetEnumerator();
+        }
+
+        private void CheckWriteable()
+        {
+            Preconditions.CheckState(!readOnly, "Object is read only");
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Metadata entry
+        /// </summary>
+        public struct Entry
+        {
+            private static readonly Encoding Encoding = Encoding.ASCII;
+
             readonly string key;
-            readonly byte[] valueBytes;
+            string value;
+            byte[] valueBytes;
 
-            public MetadataEntry(string key, byte[] valueBytes)
+            public Entry(string key, byte[] valueBytes)
             {
-                this.key = key;
-                this.valueBytes = valueBytes;
+                this.key = Preconditions.CheckNotNull(key);
+                this.value = null;
+                this.valueBytes = Preconditions.CheckNotNull(valueBytes);
             }
 
-            public MetadataEntry(string key, string value)
+            public Entry(string key, string value)
             {
-                this.key = key;
-                this.valueBytes = Encoding.ASCII.GetBytes(value);
+                this.key = Preconditions.CheckNotNull(key);
+                this.value = Preconditions.CheckNotNull(value);
+                this.valueBytes = null;
             }
 
             public string Key
@@ -89,38 +197,29 @@
                 }
             }
 
-            // TODO: using ByteString would guarantee immutability.
             public byte[] ValueBytes
             {
                 get
                 {
-                    return this.valueBytes;
+                    if (valueBytes == null)
+                    {
+                        valueBytes = Encoding.GetBytes(value);
+                    }
+                    return valueBytes;
                 }
             }
-        }
 
-        public class Builder
-        {
-            readonly List<Metadata.MetadataEntry> entries = new List<Metadata.MetadataEntry>();
-
-            public List<MetadataEntry> Entries
+            public string Value
             {
                 get
                 {
-                    return entries;
+                    if (value == null)
+                    {
+                        value = Encoding.GetString(valueBytes);
+                    }
+                    return value;
                 }
             }
-
-            public Builder Add(MetadataEntry entry)
-            {
-                entries.Add(entry);
-                return this;
-            }
-
-            public Metadata Build()
-            {
-                return new Metadata(entries.ToImmutableList());
-            }
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 03b6821..2b3d753 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -9,6 +9,5 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
 
 [assembly: InternalsVisibleTo("Grpc.Core.Tests")]
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 8e81888..cbf7719 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -52,6 +52,7 @@
         /// </summary>
         public const int PickUnusedPort = 0;
 
+        readonly GrpcEnvironment environment;
         readonly ServerSafeHandle handle;
         readonly object myLock = new object();
 
@@ -67,9 +68,10 @@
         /// <param name="options">Channel options.</param>
         public Server(IEnumerable<ChannelOption> options = null)
         {
+            this.environment = GrpcEnvironment.GetInstance();
             using (var channelArgs = ChannelOptions.CreateChannelArgs(options))
             {
-                this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), channelArgs);
+                this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
             }
         }
 
@@ -144,7 +146,7 @@
                 shutdownRequested = true;
             }
 
-            handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
+            handle.ShutdownAndNotify(HandleServerShutdown, environment);
             await shutdownTcs.Task;
             handle.Dispose();
         }
@@ -173,7 +175,7 @@
                 shutdownRequested = true;
             }
 
-            handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
+            handle.ShutdownAndNotify(HandleServerShutdown, environment);
             handle.CancelAllCalls();
             await shutdownTcs.Task;
             handle.Dispose();
@@ -208,7 +210,7 @@
             {
                 if (!shutdownRequested)
                 {
-                    handle.RequestCall(GetCompletionQueue(), HandleNewServerRpc);
+                    handle.RequestCall(HandleNewServerRpc, environment);
                 }
             }
         }
@@ -225,7 +227,7 @@
                 {
                     callHandler = new NoSuchMethodCallHandler();
                 }
-                await callHandler.HandleCall(method, call, GetCompletionQueue());
+                await callHandler.HandleCall(method, call, environment);
             }
             catch (Exception e)
             {
@@ -259,10 +261,5 @@
         {
             shutdownTcs.SetResult(null);
         }
-
-        private static CompletionQueueSafeHandle GetCompletionQueue()
-        {
-            return GrpcEnvironment.ThreadPool.CompletionQueue;
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
new file mode 100644
index 0000000..f1db1f6
--- /dev/null
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -0,0 +1,5 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// The current version of gRPC C#.
+[assembly: AssemblyVersion("0.6.0.*")]
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
index fb7eaae..6cdcdf2 100644
--- a/src/csharp/Grpc.Core/packages.config
+++ b/src/csharp/Grpc.Core/packages.config
@@ -3,5 +3,5 @@
   <package id="grpc.dependencies.openssl.redist" version="1.0.2.2" targetFramework="net45" />
   <package id="grpc.dependencies.zlib.redist" version="1.2.8.9" targetFramework="net45" />
   <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
+  <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 19bb434..5d54015 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -35,6 +35,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MathClient.cs" />
   </ItemGroup>
@@ -49,4 +52,4 @@
       <Name>Grpc.Examples</Name>
     </ProjectReference>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index 360fe92..cfe2a06 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -39,22 +39,20 @@
     {
         public static void Main(string[] args)
         {
-            GrpcEnvironment.Initialize();
-
             using (Channel channel = new Channel("127.0.0.1", 23456))
             {
-                Math.IMathClient stub = new Math.MathClient(channel);
-                MathExamples.DivExample(stub);
+                Math.IMathClient client = new Math.MathClient(channel);
+                MathExamples.DivExample(client);
 
-                MathExamples.DivAsyncExample(stub).Wait();
+                MathExamples.DivAsyncExample(client).Wait();
 
-                MathExamples.FibExample(stub).Wait();
+                MathExamples.FibExample(client).Wait();
 
-                MathExamples.SumExample(stub).Wait();
+                MathExamples.SumExample(client).Wait();
 
-                MathExamples.DivManyExample(stub).Wait();
+                MathExamples.DivManyExample(client).Wait();
 
-                MathExamples.DependendRequestsExample(stub).Wait();
+                MathExamples.DependendRequestsExample(client).Wait();
             }
 
             GrpcEnvironment.Shutdown();
diff --git a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
index 4b77472..0fb0dbd 100644
--- a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index ba6586e..677d87d 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -35,6 +35,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MathServer.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
index d05e3f2..f440985 100644
--- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -42,8 +42,6 @@
         {
             string host = "0.0.0.0";
 
-            GrpcEnvironment.Initialize();
-
             Server server = new Server();
             server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
             int port = server.AddListeningPort(host, 23456);
diff --git a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
index c18fc25..63035b6 100644
--- a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 6e84add..d59d751 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -43,6 +43,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MathClientServerTests.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index aadd49f..e7c4b33 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -49,33 +49,30 @@
         string host = "localhost";
         Server server;
         Channel channel;
-        Math.IMathClient client;
+        Math.MathClient client;
 
         [TestFixtureSetUp]
         public void Init()
         {
-            GrpcEnvironment.Initialize();
-
             server = new Server();
             server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
             int port = server.AddListeningPort(host, Server.PickUnusedPort);
             server.Start();
             channel = new Channel(host, port);
+            client = Math.NewClient(channel);
 
             // TODO(jtattermusch): get rid of the custom header here once we have dedicated tests
             // for header support.
-            var stubConfig = new StubConfiguration((headerBuilder) =>
+            client.HeaderInterceptor = (metadata) =>
             {
-                headerBuilder.Add(new Metadata.MetadataEntry("customHeader", "abcdef"));
-            });
-            client = Math.NewStub(channel, stubConfig);
+                metadata.Add(new Metadata.Entry("customHeader", "abcdef"));
+            };
         }
 
         [TestFixtureTearDown]
         public void Cleanup()
         {
             channel.Dispose();
-
             server.ShutdownAsync().Wait();
             GrpcEnvironment.Shutdown();
         }
diff --git a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
index c1ba396..846afb4 100644
--- a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 5ce490f..eaf24a2 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -40,6 +40,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Math.cs" />
     <Compile Include="MathGrpc.cs" />
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index d2cfbee..7deb651 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -38,29 +38,29 @@
 {
     public static class MathExamples
     {
-        public static void DivExample(Math.IMathClient stub)
+        public static void DivExample(Math.IMathClient client)
         {
-            DivReply result = stub.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+            DivReply result = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
             Console.WriteLine("Div Result: " + result);
         }
 
-        public static async Task DivAsyncExample(Math.IMathClient stub)
+        public static async Task DivAsyncExample(Math.IMathClient client)
         {
-            Task<DivReply> resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+            Task<DivReply> resultTask = client.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
             DivReply result = await resultTask;
             Console.WriteLine("DivAsync Result: " + result);
         }
 
-        public static async Task FibExample(Math.IMathClient stub)
+        public static async Task FibExample(Math.IMathClient client)
         {
-            using (var call = stub.Fib(new FibArgs.Builder { Limit = 5 }.Build()))
+            using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build()))
             {
                 List<Num> result = await call.ResponseStream.ToList();
                 Console.WriteLine("Fib Result: " + string.Join("|", result));
             }
         }
 
-        public static async Task SumExample(Math.IMathClient stub)
+        public static async Task SumExample(Math.IMathClient client)
         {
             var numbers = new List<Num>
             {
@@ -69,14 +69,14 @@
                 new Num.Builder { Num_ = 3 }.Build()
             };
 
-            using (var call = stub.Sum())
+            using (var call = client.Sum())
             {
                 await call.RequestStream.WriteAll(numbers);
                 Console.WriteLine("Sum Result: " + await call.Result);
             }
         }
 
-        public static async Task DivManyExample(Math.IMathClient stub)
+        public static async Task DivManyExample(Math.IMathClient client)
         {
             var divArgsList = new List<DivArgs>
             {
@@ -84,14 +84,14 @@
                 new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
                 new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
             };
-            using (var call = stub.DivMany())
+            using (var call = client.DivMany())
             { 
                 await call.RequestStream.WriteAll(divArgsList);
                 Console.WriteLine("DivMany Result: " + string.Join("|", await call.ResponseStream.ToList()));
             }
         }
 
-        public static async Task DependendRequestsExample(Math.IMathClient stub)
+        public static async Task DependendRequestsExample(Math.IMathClient client)
         {
             var numbers = new List<Num>
             {
@@ -101,13 +101,13 @@
             };
 
             Num sum;
-            using (var sumCall = stub.Sum())
+            using (var sumCall = client.Sum())
             {
                 await sumCall.RequestStream.WriteAll(numbers);
                 sum = await sumCall.Result;
             }
 
-            DivReply result = await stub.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build());
+            DivReply result = await client.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build());
             Console.WriteLine("Avg Result: " + result);
         }
     }
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index b9efc44..1805972 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -41,14 +41,14 @@
         __Marshaller_Num,
         __Marshaller_Num);
 
-    // client-side stub interface
+    // client interface
     public interface IMathClient
     {
-      global::math.DivReply Div(global::math.DivArgs request, CancellationToken token = default(CancellationToken));
-      Task<global::math.DivReply> DivAsync(global::math.DivArgs request, CancellationToken token = default(CancellationToken));
-      AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CancellationToken token = default(CancellationToken));
-      AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CancellationToken token = default(CancellationToken));
-      AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CancellationToken token = default(CancellationToken));
+      global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      Task<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
     }
 
     // server-side interface
@@ -61,38 +61,35 @@
     }
 
     // client stub
-    public class MathClient : AbstractStub<MathClient, StubConfiguration>, IMathClient
+    public class MathClient : ClientBase, IMathClient
     {
-      public MathClient(Channel channel) : this(channel, StubConfiguration.Default)
+      public MathClient(Channel channel) : base(channel)
       {
       }
-      public MathClient(Channel channel, StubConfiguration config) : base(channel, config)
+      public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
+        var call = CreateCall(__ServiceName, __Method_Div, headers);
+        return Calls.BlockingUnaryCall(call, request, cancellationToken);
       }
-      public global::math.DivReply Div(global::math.DivArgs request, CancellationToken token = default(CancellationToken))
+      public Task<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_Div);
-        return Calls.BlockingUnaryCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_Div, headers);
+        return Calls.AsyncUnaryCall(call, request, cancellationToken);
       }
-      public Task<global::math.DivReply> DivAsync(global::math.DivArgs request, CancellationToken token = default(CancellationToken))
+      public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_Div);
-        return Calls.AsyncUnaryCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_DivMany, headers);
+        return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
       }
-      public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CancellationToken token = default(CancellationToken))
+      public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_DivMany);
-        return Calls.AsyncDuplexStreamingCall(call, token);
+        var call = CreateCall(__ServiceName, __Method_Fib, headers);
+        return Calls.AsyncServerStreamingCall(call, request, cancellationToken);
       }
-      public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CancellationToken token = default(CancellationToken))
+      public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_Fib);
-        return Calls.AsyncServerStreamingCall(call, request, token);
-      }
-      public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CancellationToken token = default(CancellationToken))
-      {
-        var call = CreateCall(__ServiceName, __Method_Sum);
-        return Calls.AsyncClientStreamingCall(call, token);
+        var call = CreateCall(__ServiceName, __Method_Sum, headers);
+        return Calls.AsyncClientStreamingCall(call, cancellationToken);
       }
     }
 
@@ -106,17 +103,12 @@
           .AddMethod(__Method_Sum, serviceImpl.Sum).Build();
     }
 
-    // creates a new client stub
-    public static IMathClient NewStub(Channel channel)
+    // creates a new client
+    public static MathClient NewClient(Channel channel)
     {
       return new MathClient(channel);
     }
 
-    // creates a new client stub
-    public static IMathClient NewStub(Channel channel, StubConfiguration config)
-    {
-      return new MathClient(channel, config);
-    }
   }
 }
 #endregion
diff --git a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
index a63e05d..9211138 100644
--- a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.HealthCheck.Tests/.gitignore b/src/csharp/Grpc.HealthCheck.Tests/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
new file mode 100644
index 0000000..72e1103
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
+    <AssemblyName>Grpc.HealthCheck.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers.Serialization">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="nunit.framework">
+      <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
+    <Compile Include="HealthServiceImplTest.cs" />
+    <Compile Include="HealthClientServerTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Grpc.HealthCheck\Grpc.HealthCheck.csproj">
+      <Project>{aa5e328a-8835-49d7-98ed-c29f2b3049f0}</Project>
+      <Name>Grpc.HealthCheck</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
new file mode 100644
index 0000000..73ff0e7
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -0,0 +1,97 @@
+#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 System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Health.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.HealthCheck.Tests
+{
+    /// <summary>
+    /// Health client talks to health server.
+    /// </summary>
+    public class HealthClientServerTest
+    {
+        const string Host = "localhost";
+        Server server;
+        Channel channel;
+        Grpc.Health.V1Alpha.Health.IHealthClient client;
+        Grpc.HealthCheck.HealthServiceImpl serviceImpl;
+
+        [TestFixtureSetUp]
+        public void Init()
+        {
+            serviceImpl = new HealthServiceImpl();
+
+            server = new Server();
+            server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
+            int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+            server.Start();
+            channel = new Channel(Host, port);
+
+            client = Grpc.Health.V1Alpha.Health.NewClient(channel);
+        }
+
+        [TestFixtureTearDown]
+        public void Cleanup()
+        {
+            channel.Dispose();
+
+            server.ShutdownAsync().Wait();
+            GrpcEnvironment.Shutdown();
+        }
+
+        [Test]
+        public void ServiceIsRunning()
+        {
+            serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+
+            var response = client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("").Build());
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status);
+        }
+
+        [Test]
+        public void ServiceDoesntExist()
+        {
+            // TODO(jtattermusch): currently, this returns wrong status code, because we don't enable sending arbitrary status code from
+            // server handlers yet.
+            Assert.Throws(typeof(RpcException), () => client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("nonexistent.service").Build()));
+        }
+
+        // TODO(jtattermusch): add test with timeout once timeouts are supported
+    }
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
new file mode 100644
index 0000000..9b7c4f2
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -0,0 +1,107 @@
+#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 System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Health.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.HealthCheck.Tests
+{
+    /// <summary>
+    /// Tests for HealthCheckServiceImpl
+    /// </summary>
+    public class HealthServiceImplTest
+    {
+        [Test]
+        public void SetStatus()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "", ""));
+
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.NOT_SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, "", ""));
+
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", ""));
+
+            impl.SetStatus("virtual-host", "grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "virtual-host", "grpc.test.TestService"));
+        }
+
+        [Test]
+        public void ClearStatus()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+
+            impl.ClearStatus("", "");
+
+            Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, "", ""));
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", ""));
+        }
+
+        [Test]
+        public void ClearAll()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+
+            impl.ClearAll();
+            Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "", ""));
+            Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "virtual-host", ""));
+        }
+
+        [Test]
+        public void NullsRejected()
+        {
+            var impl = new HealthServiceImpl();
+            Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING));
+            Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
+
+            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus(null, ""));
+            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null));
+        }
+
+        private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)
+        {
+            return impl.Check(null, HealthCheckRequest.CreateBuilder().SetHost(host).SetService(service).Build()).Result.Status;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d566030
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.HealthCheck.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config
new file mode 100644
index 0000000..050c4ea
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+  <package id="NUnit" version="2.6.4" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/.gitignore b/src/csharp/Grpc.HealthCheck/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
new file mode 100644
index 0000000..4ebb644
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.HealthCheck</RootNamespace>
+    <AssemblyName>Grpc.HealthCheck</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <DocumentationFile>bin\$(Configuration)\Grpc.HealthCheck.Xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers.Serialization">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Interactive.Async">
+      <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
+    <Compile Include="HealthServiceImpl.cs" />
+    <Compile Include="Health.cs" />
+    <Compile Include="HealthGrpc.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Grpc.HealthCheck.nuspec" />
+    <None Include="packages.config" />
+    <None Include="proto\health.proto" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
new file mode 100644
index 0000000..ca35b36
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Grpc.HealthCheck</id>
+    <title>gRPC C# Healthchecking</title>
+    <summary>Implementation of gRPC health service</summary>
+    <description>Example implementation of grpc.health.v1alpha service that can be used for health-checking.</description>
+    <version>$version$</version>
+    <authors>Google Inc.</authors>
+    <owners>grpc-packages</owners>
+    <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/grpc/grpc</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <copyright>Copyright 2015, Google Inc.</copyright>
+    <tags>gRPC health check</tags>
+	<dependencies>
+	  <dependency id="Google.ProtocolBuffers" version="2.4.1.555" />
+	  <dependency id="Grpc.Core" version="$version$" />
+	  <dependency id="Ix-Async" version="1.2.3" />
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" />
+	<file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" />
+	<file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" />
+	<file src="**\*.cs" target="src" />
+  </files>
+</package>
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
new file mode 100644
index 0000000..361382d
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -0,0 +1,687 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: health.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.ProtocolBuffers;
+using pbc = global::Google.ProtocolBuffers.Collections;
+using pbd = global::Google.ProtocolBuffers.Descriptors;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Health.V1Alpha {
+
+  namespace Proto {
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Health {
+
+      #region Extension registration
+      public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
+      }
+      #endregion
+      #region Static variables
+      internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder> internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable;
+      internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder> internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable;
+      #endregion
+      #region Descriptor
+      public static pbd::FileDescriptor Descriptor {
+        get { return descriptor; }
+      }
+      private static pbd::FileDescriptor descriptor;
+
+      static Health() {
+        byte[] descriptorData = global::System.Convert.FromBase64String(
+            string.Concat(
+              "CgxoZWFsdGgucHJvdG8SE2dycGMuaGVhbHRoLnYxYWxwaGEiMwoSSGVhbHRo", 
+              "Q2hlY2tSZXF1ZXN0EgwKBGhvc3QYASABKAkSDwoHc2VydmljZRgCIAEoCSKZ", 
+              "AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRJGCgZzdGF0dXMYASABKA4yNi5ncnBj", 
+              "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0", 
+              "YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5H", 
+              "EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", 
+              "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", 
+              "bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", 
+            "dGguVjFBbHBoYQ=="));
+        pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
+          descriptor = root;
+          internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor = Descriptor.MessageTypes[0];
+          internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder>(internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor,
+                  new string[] { "Host", "Service", });
+          internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor = Descriptor.MessageTypes[1];
+          internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder>(internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor,
+                  new string[] { "Status", });
+          pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();
+          RegisterAllExtensions(registry);
+          return registry;
+        };
+        pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+            new pbd::FileDescriptor[] {
+            }, assigner);
+      }
+      #endregion
+
+    }
+  }
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HealthCheckRequest : pb::GeneratedMessage<HealthCheckRequest, HealthCheckRequest.Builder> {
+    private HealthCheckRequest() { }
+    private static readonly HealthCheckRequest defaultInstance = new HealthCheckRequest().MakeReadOnly();
+    private static readonly string[] _healthCheckRequestFieldNames = new string[] { "host", "service" };
+    private static readonly uint[] _healthCheckRequestFieldTags = new uint[] { 10, 18 };
+    public static HealthCheckRequest DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override HealthCheckRequest DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override HealthCheckRequest ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<HealthCheckRequest, HealthCheckRequest.Builder> InternalFieldAccessors {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; }
+    }
+
+    public const int HostFieldNumber = 1;
+    private bool hasHost;
+    private string host_ = "";
+    public bool HasHost {
+      get { return hasHost; }
+    }
+    public string Host {
+      get { return host_; }
+    }
+
+    public const int ServiceFieldNumber = 2;
+    private bool hasService;
+    private string service_ = "";
+    public bool HasService {
+      get { return hasService; }
+    }
+    public string Service {
+      get { return service_; }
+    }
+
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _healthCheckRequestFieldNames;
+      if (hasHost) {
+        output.WriteString(1, field_names[0], Host);
+      }
+      if (hasService) {
+        output.WriteString(2, field_names[1], Service);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (hasHost) {
+        size += pb::CodedOutputStream.ComputeStringSize(1, Host);
+      }
+      if (hasService) {
+        size += pb::CodedOutputStream.ComputeStringSize(2, Service);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static HealthCheckRequest ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private HealthCheckRequest MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(HealthCheckRequest prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckRequest, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(HealthCheckRequest cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private HealthCheckRequest result;
+
+      private HealthCheckRequest PrepareBuilder() {
+        if (resultIsReadOnly) {
+          HealthCheckRequest original = result;
+          result = new HealthCheckRequest();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override HealthCheckRequest MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.Descriptor; }
+      }
+
+      public override HealthCheckRequest DefaultInstanceForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance; }
+      }
+
+      public override HealthCheckRequest BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is HealthCheckRequest) {
+          return MergeFrom((HealthCheckRequest) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(HealthCheckRequest other) {
+        if (other == global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.HasHost) {
+          Host = other.Host;
+        }
+        if (other.HasService) {
+          Service = other.Service;
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_healthCheckRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _healthCheckRequestFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 10: {
+              result.hasHost = input.ReadString(ref result.host_);
+              break;
+            }
+            case 18: {
+              result.hasService = input.ReadString(ref result.service_);
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public bool HasHost {
+        get { return result.hasHost; }
+      }
+      public string Host {
+        get { return result.Host; }
+        set { SetHost(value); }
+      }
+      public Builder SetHost(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasHost = true;
+        result.host_ = value;
+        return this;
+      }
+      public Builder ClearHost() {
+        PrepareBuilder();
+        result.hasHost = false;
+        result.host_ = "";
+        return this;
+      }
+
+      public bool HasService {
+        get { return result.hasService; }
+      }
+      public string Service {
+        get { return result.Service; }
+        set { SetService(value); }
+      }
+      public Builder SetService(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasService = true;
+        result.service_ = value;
+        return this;
+      }
+      public Builder ClearService() {
+        PrepareBuilder();
+        result.hasService = false;
+        result.service_ = "";
+        return this;
+      }
+    }
+    static HealthCheckRequest() {
+      object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
+    }
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HealthCheckResponse : pb::GeneratedMessage<HealthCheckResponse, HealthCheckResponse.Builder> {
+    private HealthCheckResponse() { }
+    private static readonly HealthCheckResponse defaultInstance = new HealthCheckResponse().MakeReadOnly();
+    private static readonly string[] _healthCheckResponseFieldNames = new string[] { "status" };
+    private static readonly uint[] _healthCheckResponseFieldTags = new uint[] { 8 };
+    public static HealthCheckResponse DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override HealthCheckResponse DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override HealthCheckResponse ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<HealthCheckResponse, HealthCheckResponse.Builder> InternalFieldAccessors {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; }
+    }
+
+    #region Nested types
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum ServingStatus {
+        UNKNOWN = 0,
+        SERVING = 1,
+        NOT_SERVING = 2,
+      }
+
+    }
+    #endregion
+
+    public const int StatusFieldNumber = 1;
+    private bool hasStatus;
+    private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+    public bool HasStatus {
+      get { return hasStatus; }
+    }
+    public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
+      get { return status_; }
+    }
+
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _healthCheckResponseFieldNames;
+      if (hasStatus) {
+        output.WriteEnum(1, field_names[0], (int) Status, Status);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (hasStatus) {
+        size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Status);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static HealthCheckResponse ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private HealthCheckResponse MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(HealthCheckResponse prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckResponse, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(HealthCheckResponse cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private HealthCheckResponse result;
+
+      private HealthCheckResponse PrepareBuilder() {
+        if (resultIsReadOnly) {
+          HealthCheckResponse original = result;
+          result = new HealthCheckResponse();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override HealthCheckResponse MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.Descriptor; }
+      }
+
+      public override HealthCheckResponse DefaultInstanceForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance; }
+      }
+
+      public override HealthCheckResponse BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is HealthCheckResponse) {
+          return MergeFrom((HealthCheckResponse) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(HealthCheckResponse other) {
+        if (other == global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.HasStatus) {
+          Status = other.Status;
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_healthCheckResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _healthCheckResponseFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 8: {
+              object unknown;
+              if(input.ReadEnum(ref result.status_, out unknown)) {
+                result.hasStatus = true;
+              } else if(unknown is int) {
+                if (unknownFields == null) {
+                  unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+                }
+                unknownFields.MergeVarintField(1, (ulong)(int)unknown);
+              }
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public bool HasStatus {
+       get { return result.hasStatus; }
+      }
+      public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
+        get { return result.Status; }
+        set { SetStatus(value); }
+      }
+      public Builder SetStatus(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus value) {
+        PrepareBuilder();
+        result.hasStatus = true;
+        result.status_ = value;
+        return this;
+      }
+      public Builder ClearStatus() {
+        PrepareBuilder();
+        result.hasStatus = false;
+        result.status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+        return this;
+      }
+    }
+    static HealthCheckResponse() {
+      object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
+    }
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
new file mode 100644
index 0000000..3aebdcb
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -0,0 +1,70 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: health.proto
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Health.V1Alpha {
+  public static class Health
+  {
+    static readonly string __ServiceName = "grpc.health.v1alpha.Health";
+
+    static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckRequest.ParseFrom);
+    static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckResponse.ParseFrom);
+
+    static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>(
+        MethodType.Unary,
+        "Check",
+        __Marshaller_HealthCheckRequest,
+        __Marshaller_HealthCheckResponse);
+
+    // client interface
+    public interface IHealthClient
+    {
+      global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+    }
+
+    // server-side interface
+    public interface IHealth
+    {
+      Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> Check(ServerCallContext context, global::Grpc.Health.V1Alpha.HealthCheckRequest request);
+    }
+
+    // client stub
+    public class HealthClient : ClientBase, IHealthClient
+    {
+      public HealthClient(Channel channel) : base(channel)
+      {
+      }
+      public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+      {
+        var call = CreateCall(__ServiceName, __Method_Check, headers);
+        return Calls.BlockingUnaryCall(call, request, cancellationToken);
+      }
+      public Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
+      {
+        var call = CreateCall(__ServiceName, __Method_Check, headers);
+        return Calls.AsyncUnaryCall(call, request, cancellationToken);
+      }
+    }
+
+    // creates service definition that can be registered with a server
+    public static ServerServiceDefinition BindService(IHealth serviceImpl)
+    {
+      return ServerServiceDefinition.CreateBuilder(__ServiceName)
+          .AddMethod(__Method_Check, serviceImpl.Check).Build();
+    }
+
+    // creates a new client
+    public static HealthClient NewClient(Channel channel)
+    {
+      return new HealthClient(channel);
+    }
+
+  }
+}
+#endregion
diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
new file mode 100644
index 0000000..db3a2a0
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
@@ -0,0 +1,132 @@
+#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 System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Health.V1Alpha;
+
+namespace Grpc.HealthCheck
+{
+    /// <summary>
+    /// Implementation of a simple Health service. Useful for health checking.
+    /// 
+    /// Registering service with a server:
+    /// <code>
+    /// var serviceImpl = new HealthServiceImpl();
+    /// server = new Server();
+    /// server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
+    /// </code>
+    /// </summary>
+    public class HealthServiceImpl : Grpc.Health.V1Alpha.Health.IHealth
+    {
+        private readonly object myLock = new object();
+        private readonly Dictionary<Key, HealthCheckResponse.Types.ServingStatus> statusMap = 
+            new Dictionary<Key, HealthCheckResponse.Types.ServingStatus>();
+
+        /// <summary>
+        /// Sets the health status for given host and service.
+        /// </summary>
+        /// <param name="host">The host. Cannot be null.</param>
+        /// <param name="service">The service. Cannot be null.</param>
+        /// <param name="status">the health status</param>
+        public void SetStatus(string host, string service, HealthCheckResponse.Types.ServingStatus status)
+        {
+            lock (myLock)
+            {
+                statusMap[CreateKey(host, service)] = status;
+            }
+        }
+
+        /// <summary>
+        /// Clears health status for given host and service.
+        /// </summary>
+        /// <param name="host">The host. Cannot be null.</param>
+        /// <param name="service">The service. Cannot be null.</param>
+        public void ClearStatus(string host, string service)
+        {
+            lock (myLock)
+            {
+                statusMap.Remove(CreateKey(host, service));
+            }
+        }
+        
+        /// <summary>
+        /// Clears statuses for all hosts and services.
+        /// </summary>
+        public void ClearAll()
+        {
+            lock (myLock)
+            {
+                statusMap.Clear();
+            }
+        }
+
+        public Task<HealthCheckResponse> Check(ServerCallContext context, HealthCheckRequest request)
+        {
+            lock (myLock)
+            {
+                var host = request.HasHost ? request.Host : "";
+                var service = request.HasService ? request.Service : "";
+
+                HealthCheckResponse.Types.ServingStatus status;
+                if (!statusMap.TryGetValue(CreateKey(host, service), out status))
+                {
+                    // TODO(jtattermusch): returning specific status from server handler is not supported yet.
+                    throw new RpcException(new Status(StatusCode.NotFound, ""));
+                }
+                return Task.FromResult(HealthCheckResponse.CreateBuilder().SetStatus(status).Build());
+            }
+        }
+
+        private static Key CreateKey(string host, string service)
+        {
+            return new Key(host, service);
+        }
+
+        private struct Key
+        {
+            public Key(string host, string service)
+            {
+                this.Host = Preconditions.CheckNotNull(host);
+                this.Service = Preconditions.CheckNotNull(service);
+            }
+
+            readonly string Host;
+            readonly string Service;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..41a54a9
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.HealthCheck")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
new file mode 100644
index 0000000..094a309
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+  <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs b/src/csharp/Grpc.HealthCheck/proto/health.proto
similarity index 63%
rename from src/csharp/Grpc.Core/Stub/StubConfiguration.cs
rename to src/csharp/Grpc.HealthCheck/proto/health.proto
index 5bcb5b4..08df7e1 100644
--- a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
+++ b/src/csharp/Grpc.HealthCheck/proto/health.proto
@@ -1,5 +1,3 @@
-#region Copyright notice and license
-
 // Copyright 2015, Google Inc.
 // All rights reserved.
 //
@@ -29,36 +27,26 @@
 // (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
+// TODO(jtattermusch): switch to proto3 once C# supports that.
+syntax = "proto2";
 
-using System;
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+package grpc.health.v1alpha;
+option csharp_namespace = "Grpc.Health.V1Alpha";
 
-namespace Grpc.Core
-{
-    public delegate void HeaderInterceptorDelegate(Metadata.Builder headerBuilder);
-
-    public class StubConfiguration
-    {
-        /// <summary>
-        /// The default stub configuration.
-        /// </summary>
-        public static readonly StubConfiguration Default = new StubConfiguration((headerBuilder) => { });
-
-        readonly HeaderInterceptorDelegate headerInterceptor;
-
-        public StubConfiguration(HeaderInterceptorDelegate headerInterceptor)
-        {
-            this.headerInterceptor = Preconditions.CheckNotNull(headerInterceptor);
-        }
-
-        public HeaderInterceptorDelegate HeaderInterceptor
-        {
-            get
-            {
-                return headerInterceptor;
-            }
-        }
-    }
+message HealthCheckRequest {
+  optional string host = 1;
+  optional string service = 2;
 }
+
+message HealthCheckResponse {
+  enum ServingStatus {
+    UNKNOWN = 0;
+    SERVING = 1;
+    NOT_SERVING = 2;
+  }
+  optional ServingStatus status = 1;
+}
+
+service Health {
+  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index df05c53..328acb5 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -36,6 +36,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
index 26c0dcc..f51f279 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 235897c..ae184c1 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -36,6 +36,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
index 2d518d7..f68d9a3 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index b3a0a29..af4a75a 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -54,6 +54,10 @@
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
     </Reference>
+    <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+    </Reference>
     <Reference Include="System.Interactive.Async">
       <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
     </Reference>
@@ -69,11 +73,11 @@
     <Reference Include="Newtonsoft.Json">
       <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
     </Reference>
-    <Reference Include="System.Collections.Immutable">
-      <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Empty.cs" />
     <Compile Include="Messages.cs" />
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index f0be522..05e732d 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -102,8 +102,6 @@
 
         private void Run()
         {
-            GrpcEnvironment.Initialize();
-
             Credentials credentials = null;
             if (options.useTls)
             {
@@ -121,7 +119,7 @@
 
             using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions))
             {
-                var stubConfig = StubConfiguration.Default;
+                TestService.TestServiceClient client = new TestService.TestServiceClient(channel);
                 if (options.testCase == "service_account_creds" || options.testCase == "compute_engine_creds")
                 {
                     var credential = GoogleCredential.GetApplicationDefault();
@@ -129,13 +127,11 @@
                     {
                         credential = credential.CreateScoped(new[] { AuthScope });
                     }
-                    stubConfig = new StubConfiguration(OAuth2InterceptorFactory.Create(credential));
+                    client.HeaderInterceptor = OAuth2InterceptorFactory.Create(credential);
                 }
 
-                TestService.ITestServiceClient client = new TestService.TestServiceClient(channel, stubConfig);
                 RunTestCase(options.testCase, client);
             }
-
             GrpcEnvironment.Shutdown();
         }
 
@@ -366,7 +362,7 @@
                 Console.WriteLine("running cancel_after_begin");
 
                 var cts = new CancellationTokenSource();
-                using (var call = client.StreamingInputCall(cts.Token))
+                using (var call = client.StreamingInputCall(cancellationToken: cts.Token))
                 {
                     // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
                     await Task.Delay(1000);
@@ -393,7 +389,7 @@
                 Console.WriteLine("running cancel_after_first_response");
 
                 var cts = new CancellationTokenSource();
-                using (var call = client.FullDuplexCall(cts.Token))
+                using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
                 {
                     await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
                         .SetResponseType(PayloadType.COMPRESSABLE)
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 1a73345..f306289 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -55,8 +55,6 @@
         [TestFixtureSetUp]
         public void Init()
         {
-            GrpcEnvironment.Initialize();
-
             server = new Server();
             server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
             int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
@@ -67,14 +65,13 @@
                 new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
             };
             channel = new Channel(host, port, TestCredentials.CreateTestClientCredentials(true), options);
-            client = TestService.NewStub(channel);
+            client = TestService.NewClient(channel);
         }
 
         [TestFixtureTearDown]
         public void Cleanup()
         {
             channel.Dispose();
-
             server.ShutdownAsync().Wait();
             GrpcEnvironment.Shutdown();
         }
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 87c3cbe..9475e66 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -88,8 +88,6 @@
 
         private void Run()
         {
-            GrpcEnvironment.Initialize();
-
             var server = new Server();
             server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
 
diff --git a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
index f73575e..1beb0bb 100644
--- a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index ee077f9..96d9b23 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -56,17 +56,17 @@
         __Marshaller_StreamingOutputCallRequest,
         __Marshaller_StreamingOutputCallResponse);
 
-    // client-side stub interface
+    // client interface
     public interface ITestServiceClient
     {
-      global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CancellationToken token = default(CancellationToken));
-      Task<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CancellationToken token = default(CancellationToken));
-      global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CancellationToken token = default(CancellationToken));
-      Task<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CancellationToken token = default(CancellationToken));
-      AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CancellationToken token = default(CancellationToken));
-      AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken));
-      AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CancellationToken token = default(CancellationToken));
-      AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CancellationToken token = default(CancellationToken));
+      global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      Task<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      Task<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
+      AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));
     }
 
     // server-side interface
@@ -81,53 +81,50 @@
     }
 
     // client stub
-    public class TestServiceClient : AbstractStub<TestServiceClient, StubConfiguration>, ITestServiceClient
+    public class TestServiceClient : ClientBase, ITestServiceClient
     {
-      public TestServiceClient(Channel channel) : this(channel, StubConfiguration.Default)
+      public TestServiceClient(Channel channel) : base(channel)
       {
       }
-      public TestServiceClient(Channel channel, StubConfiguration config) : base(channel, config)
+      public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
+        var call = CreateCall(__ServiceName, __Method_EmptyCall, headers);
+        return Calls.BlockingUnaryCall(call, request, cancellationToken);
       }
-      public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CancellationToken token = default(CancellationToken))
+      public Task<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_EmptyCall);
-        return Calls.BlockingUnaryCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_EmptyCall, headers);
+        return Calls.AsyncUnaryCall(call, request, cancellationToken);
       }
-      public Task<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CancellationToken token = default(CancellationToken))
+      public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_EmptyCall);
-        return Calls.AsyncUnaryCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_UnaryCall, headers);
+        return Calls.BlockingUnaryCall(call, request, cancellationToken);
       }
-      public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CancellationToken token = default(CancellationToken))
+      public Task<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_UnaryCall);
-        return Calls.BlockingUnaryCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_UnaryCall, headers);
+        return Calls.AsyncUnaryCall(call, request, cancellationToken);
       }
-      public Task<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CancellationToken token = default(CancellationToken))
+      public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_UnaryCall);
-        return Calls.AsyncUnaryCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers);
+        return Calls.AsyncServerStreamingCall(call, request, cancellationToken);
       }
-      public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CancellationToken token = default(CancellationToken))
+      public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_StreamingOutputCall);
-        return Calls.AsyncServerStreamingCall(call, request, token);
+        var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers);
+        return Calls.AsyncClientStreamingCall(call, cancellationToken);
       }
-      public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken))
+      public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_StreamingInputCall);
-        return Calls.AsyncClientStreamingCall(call, token);
+        var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers);
+        return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
       }
-      public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CancellationToken token = default(CancellationToken))
+      public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))
       {
-        var call = CreateCall(__ServiceName, __Method_FullDuplexCall);
-        return Calls.AsyncDuplexStreamingCall(call, token);
-      }
-      public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CancellationToken token = default(CancellationToken))
-      {
-        var call = CreateCall(__ServiceName, __Method_HalfDuplexCall);
-        return Calls.AsyncDuplexStreamingCall(call, token);
+        var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers);
+        return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
       }
     }
 
@@ -143,17 +140,12 @@
           .AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
     }
 
-    // creates a new client stub
-    public static ITestServiceClient NewStub(Channel channel)
+    // creates a new client
+    public static TestServiceClient NewClient(Channel channel)
     {
       return new TestServiceClient(channel);
     }
 
-    // creates a new client stub
-    public static ITestServiceClient NewStub(Channel channel, StubConfiguration config)
-    {
-      return new TestServiceClient(channel, config);
-    }
   }
 }
 #endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 291b7b8..c74ac75 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -7,8 +7,8 @@
   <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
   <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
   <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
   <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
   <package id="NUnit" version="2.6.4" targetFramework="net45" />
+  <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
index 913d4c8..eabf5dc 100644
--- a/src/csharp/Grpc.Tools.nuspec
+++ b/src/csharp/Grpc.Tools.nuspec
@@ -5,13 +5,13 @@
     <title>gRPC C# Tools</title>
     <summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
     <description>Precompiled Windows binaries for generating protocol buffer messages and gRPC client/server code</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version 0.5.1</releaseNotes>
+    <releaseNotes>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
   </metadata>
diff --git a/src/csharp/Grpc.nuspec b/src/csharp/Grpc.nuspec
index cf4c74f..7fbd861 100644
--- a/src/csharp/Grpc.nuspec
+++ b/src/csharp/Grpc.nuspec
@@ -5,17 +5,17 @@
     <title>gRPC C#</title>
     <summary>C# implementation of gRPC - an RPC library and framework</summary>
     <description>C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
+    <releaseNotes>Release $version$ of gRPC C#</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
     <dependencies>
-      <dependency id="Grpc.Core" version="0.5.1" />
+      <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
   <files/>
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 978739f..705e4fb 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -28,57 +28,68 @@
 		.nuget\packages.config = .nuget\packages.config

 	EndProjectSection

 EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.csproj", "{AA5E328A-8835-49D7-98ED-C29F2B3049F0}"

+EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"

+EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

 		Debug|x86 = Debug|x86

 		Release|x86 = Release|x86

 	EndGlobalSection

 	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.Build.0 = Debug|Any CPU

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.ActiveCfg = Release|Any CPU

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.Build.0 = Release|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.Build.0 = Debug|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.ActiveCfg = Release|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.Build.0 = Release|Any CPU

+	EndGlobalSection

+	GlobalSection(NestedProjects) = preSolution

 	EndGlobalSection

 	GlobalSection(SolutionProperties) = preSolution

 		HideSolutionNode = FALSE

 	EndGlobalSection

-	GlobalSection(MonoDevelopProperties) = preSolution

-		StartupItem = Grpc.Examples\Grpc.Examples.csproj

-	EndGlobalSection

 EndGlobal

diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 3412129..c3e5fe8 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,5 +1,9 @@
 @rem Builds gRPC NuGet packages
 
+@rem Current package versions
+set VERSION=0.6.0
+set CORE_VERSION=0.10.0
+
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
 
@@ -10,11 +14,12 @@
 
 @call buildall.bat || goto :error
 
-%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec || goto :error
-%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols || goto :error
-%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols || goto :error
-%NUGET% pack Grpc.Tools.nuspec || goto :error
-%NUGET% pack Grpc.nuspec || goto :error
+%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
+%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
+%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error
+%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% || goto :error
+%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
+%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
 
 goto :EOF
 
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index ec125db..7dd1959 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -302,12 +302,13 @@
 
 GPR_EXPORT grpc_event GPR_CALLTYPE
 grpcsharp_completion_queue_next(grpc_completion_queue *cq) {
-  return grpc_completion_queue_next(cq, gpr_inf_future);
+  return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
 }
 
 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);
+  return grpc_completion_queue_pluck(cq, tag,
+                                     gpr_inf_future(GPR_CLOCK_REALTIME));
 }
 
 /* Channel */
@@ -379,10 +380,10 @@
 
 /* Timespec */
 
-GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(); }
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(GPR_CLOCK_REALTIME); }
 
 GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(void) {
-  return gpr_inf_future;
+  return gpr_inf_future(GPR_CLOCK_REALTIME);
 }
 
 GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) {
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index f980787..7c3ba70 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -32,12 +32,17 @@
 set +e
 cd $(dirname $0)
 
+PROTOC=../../bins/opt/protobuf/protoc
 PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
 EXAMPLES_DIR=Grpc.Examples
 INTEROP_DIR=Grpc.IntegrationTesting
+HEALTHCHECK_DIR=Grpc.HealthCheck
 
-protoc --plugin=$PLUGIN --grpc_out=$EXAMPLES_DIR \
+$PROTOC --plugin=$PLUGIN --grpc_out=$EXAMPLES_DIR \
     -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
 
-protoc --plugin=$PLUGIN --grpc_out=$INTEROP_DIR \
+$PROTOC --plugin=$PLUGIN --grpc_out=$INTEROP_DIR \
     -I $INTEROP_DIR/proto $INTEROP_DIR/proto/test.proto
+
+$PROTOC --plugin=$PLUGIN --grpc_out=$HEALTHCHECK_DIR \
+    -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
diff --git a/src/node/README.md b/src/node/README.md
index 2f4c490..78781da 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -54,10 +54,10 @@
 Returns the same structure that `load` returns, but takes a reflection object from `ProtoBuf.js` instead of a file name.
 
 ```javascript
-function buildServer(serviceArray)
+function Server([serverOpions])
 ```
 
-Takes an array of service objects and returns a constructor for a server that handles requests to all of those services.
+Constructs a server to which service/implementation pairs can be added.
 
 
 ```javascript
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
index 83f72fa..6ba2333 100644
--- a/src/node/binding.gyp
+++ b/src/node/binding.gyp
@@ -10,20 +10,54 @@
         '-pthread',
         '-pedantic',
         '-g',
-        '-zdefs'
+        '-zdefs',
         '-Werror'
       ],
       'ldflags': [
         '-g'
       ],
-      'link_settings': {
-        'libraries': [
-          '-lpthread',
-          '-lgrpc',
-          '-lgpr'
-        ]
-      },
       "conditions": [
+        ['OS != "win"', {
+          'variables': {
+            'pkg_config_grpc': '<!(pkg-config --exists grpc >/dev/null 2>&1 && echo true || echo false)'
+          },
+          'conditions': [
+            ['pkg_config_grpc == "true"', {
+              'link_settings': {
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l --static grpc)'
+                ]
+              },
+              'cflags': [
+                '<!@(pkg-config --cflags grpc)'
+              ],
+              'libraries': [
+                '<!@(pkg-config --libs-only-L --static grpc)'
+              ],
+              'ldflags': [
+                '<!@(pkg-config --libs-only-other --static grpc)'
+              ]
+              }, {
+                'link_settings': {
+                  'libraries': [
+                    '-lpthread',
+                    '-lgrpc',
+                    '-lgpr'
+                  ],
+                },
+                'conditions':[
+                  ['OS != "mac"', {
+                    'link_settings': {
+                      'libraries': [
+                        '-lrt'
+                      ]
+                    }
+                  }]
+                ]
+              }
+           ]
+          ]
+        }],
         ['OS == "mac"', {
           'xcode_settings': {
             'MACOSX_DEPLOYMENT_TARGET': '10.9',
@@ -32,13 +66,6 @@
               '-stdlib=libc++'
             ]
           }
-        }],
-        ['OS != "mac"', {
-          'link_settings': {
-            'libraries': [
-              '-lrt'
-            ]
-          }
         }]
       ],
       "target_name": "grpc",
diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js
index 0a86e7e..b1f8a63 100644
--- a/src/node/examples/math_server.js
+++ b/src/node/examples/math_server.js
@@ -36,8 +36,6 @@
 var grpc = require('..');
 var math = grpc.load(__dirname + '/math.proto').math;
 
-var Server = grpc.buildServer([math.Math.service]);
-
 /**
  * Server function for division. Provides the /Math/DivMany and /Math/Div
  * functions (Div is just DivMany with only one stream element). For each
@@ -108,19 +106,17 @@
     stream.end();
   });
 }
-
-var server = new Server({
-  'math.Math' : {
-    div: mathDiv,
-    fib: mathFib,
-    sum: mathSum,
-    divMany: mathDivMany
-  }
+var server = new grpc.Server();
+server.addProtoService(math.Math.service, {
+  div: mathDiv,
+  fib: mathFib,
+  sum: mathSum,
+  divMany: mathDivMany
 });
 
 if (require.main === module) {
   server.bind('0.0.0.0:50051');
-  server.listen();
+  server.start();
 }
 
 /**
diff --git a/src/node/examples/route_guide_server.js b/src/node/examples/route_guide_server.js
index c777eab..70044a3 100644
--- a/src/node/examples/route_guide_server.js
+++ b/src/node/examples/route_guide_server.js
@@ -40,8 +40,6 @@
 var grpc = require('..');
 var examples = grpc.load(__dirname + '/route_guide.proto').examples;
 
-var Server = grpc.buildServer([examples.RouteGuide.service]);
-
 var COORD_FACTOR = 1e7;
 
 /**
@@ -228,14 +226,14 @@
  * @return {Server} The new server object
  */
 function getServer() {
-  return new Server({
-    'examples.RouteGuide' : {
-      getFeature: getFeature,
-      listFeatures: listFeatures,
-      recordRoute: recordRoute,
-      routeChat: routeChat
-    }
+  var server = new grpc.Server();
+  server.addProtoService(examples.RouteGuide.service, {
+    getFeature: getFeature,
+    listFeatures: listFeatures,
+    recordRoute: recordRoute,
+    routeChat: routeChat
   });
+  return server;
 }
 
 if (require.main === module) {
diff --git a/src/node/examples/stock_server.js b/src/node/examples/stock_server.js
index caaf9f9..f2eb6ad 100644
--- a/src/node/examples/stock_server.js
+++ b/src/node/examples/stock_server.js
@@ -37,8 +37,6 @@
 var grpc = require('..');
 var examples = grpc.load(__dirname + '/stock.proto').examples;
 
-var StockServer = grpc.buildServer([examples.Stock.service]);
-
 function getLastTradePrice(call, callback) {
   callback(null, {symbol: call.request.symbol, price: 88});
 }
@@ -73,13 +71,12 @@
   });
 }
 
-var stockServer = new StockServer({
-  'examples.Stock' : {
-    getLastTradePrice: getLastTradePrice,
-    getLastTradePriceMultiple: getLastTradePriceMultiple,
-    watchFutureTrades: watchFutureTrades,
-    getHighestTradePrice: getHighestTradePrice
-  }
+var stockServer = new grpc.Server();
+stockServer.addProtoService(examples.Stock.service, {
+  getLastTradePrice: getLastTradePrice,
+  getLastTradePriceMultiple: getLastTradePriceMultiple,
+  watchFutureTrades: watchFutureTrades,
+  getHighestTradePrice: getHighestTradePrice
 });
 
 if (require.main === module) {
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index 4be208c..1215c97 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -62,7 +62,8 @@
 CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
 
 void CompletionQueueAsyncWorker::Execute() {
-  result = grpc_completion_queue_next(queue, gpr_inf_future);
+  result =
+      grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME));
   if (!result.success) {
     SetErrorMessage("The batch encountered an error");
   }
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 51c55ba..34cde9f 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -161,7 +161,8 @@
     grpc_server_shutdown_and_notify(this->wrapped_server,
                                     this->shutdown_queue,
                                     NULL);
-    grpc_completion_queue_pluck(this->shutdown_queue, NULL, gpr_inf_future);
+    grpc_completion_queue_pluck(this->shutdown_queue, NULL,
+                                gpr_inf_future(GPR_CLOCK_REALTIME));
     this->wrapped_server = NULL;
   }
 }
diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc
index bc3237f..60de4d8 100644
--- a/src/node/ext/timeval.cc
+++ b/src/node/ext/timeval.cc
@@ -42,18 +42,19 @@
 
 gpr_timespec MillisecondsToTimespec(double millis) {
   if (millis == std::numeric_limits<double>::infinity()) {
-    return gpr_inf_future;
+    return gpr_inf_future(GPR_CLOCK_REALTIME);
   } else if (millis == -std::numeric_limits<double>::infinity()) {
-    return gpr_inf_past;
+    return gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
-    return gpr_time_from_micros(static_cast<int64_t>(millis * 1000));
+    return gpr_time_from_micros(static_cast<int64_t>(millis * 1000),
+                                GPR_CLOCK_REALTIME);
   }
 }
 
 double TimespecToMilliseconds(gpr_timespec timespec) {
-  if (gpr_time_cmp(timespec, gpr_inf_future) == 0) {
+  if (gpr_time_cmp(timespec, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) {
     return std::numeric_limits<double>::infinity();
-  } else if (gpr_time_cmp(timespec, gpr_inf_past) == 0) {
+  } else if (gpr_time_cmp(timespec, gpr_inf_past(GPR_CLOCK_REALTIME)) == 0) {
     return -std::numeric_limits<double>::infinity();
   } else {
     return (static_cast<double>(timespec.tv_sec) * 1000 +
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.m b/src/node/health_check/health.js
similarity index 63%
copy from src/objective-c/GRPCClient/GRPCMethodName.m
copy to src/node/health_check/health.js
index 9672407..87e0019 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.m
+++ b/src/node/health_check/health.js
@@ -31,17 +31,40 @@
  *
  */
 
-#import "GRPCMethodName.h"
+'use strict';
 
-@implementation GRPCMethodName
-- (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
-                         method:(NSString *)method {
-  if ((self = [super init])) {
-    _package = [package copy];
-    _interface = [interface copy];
-    _method = [method copy];
-  }
-  return self;
+var grpc = require('../');
+
+var _ = require('lodash');
+
+var health_proto = grpc.load(__dirname + '/health.proto');
+
+var HealthClient = health_proto.grpc.health.v1alpha.Health;
+
+function HealthImplementation(statusMap) {
+  this.statusMap = _.clone(statusMap);
 }
-@end
+
+HealthImplementation.prototype.setStatus = function(host, service, status) {
+  if (!this.statusMap[host]) {
+    this.statusMap[host] = {};
+  }
+  this.statusMap[host][service] = status;
+};
+
+HealthImplementation.prototype.check = function(call, callback){
+  var host = call.request.host;
+  var service = call.request.service;
+  var status = _.get(this.statusMap, [host, service], null);
+  if (status === null) {
+    callback({code:grpc.status.NOT_FOUND});
+  } else {
+    callback(null, {status: status});
+  }
+};
+
+module.exports = {
+  Client: HealthClient,
+  service: HealthClient.service,
+  Implementation: HealthImplementation
+};
diff --git a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs b/src/node/health_check/health.proto
similarity index 63%
copy from src/csharp/Grpc.Core/Stub/StubConfiguration.cs
copy to src/node/health_check/health.proto
index 5bcb5b4..d31df1e 100644
--- a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
+++ b/src/node/health_check/health.proto
@@ -1,5 +1,3 @@
-#region Copyright notice and license
-
 // Copyright 2015, Google Inc.
 // All rights reserved.
 //
@@ -29,36 +27,24 @@
 // (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
+syntax = "proto3";
 
-using System;
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+package grpc.health.v1alpha;
 
-namespace Grpc.Core
-{
-    public delegate void HeaderInterceptorDelegate(Metadata.Builder headerBuilder);
-
-    public class StubConfiguration
-    {
-        /// <summary>
-        /// The default stub configuration.
-        /// </summary>
-        public static readonly StubConfiguration Default = new StubConfiguration((headerBuilder) => { });
-
-        readonly HeaderInterceptorDelegate headerInterceptor;
-
-        public StubConfiguration(HeaderInterceptorDelegate headerInterceptor)
-        {
-            this.headerInterceptor = Preconditions.CheckNotNull(headerInterceptor);
-        }
-
-        public HeaderInterceptorDelegate HeaderInterceptor
-        {
-            get
-            {
-                return headerInterceptor;
-            }
-        }
-    }
+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/node/index.js b/src/node/index.js
index b6a4e2d..d81e780 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -133,9 +133,9 @@
 exports.load = load;
 
 /**
- * See docs for server.makeServerConstructor
+ * See docs for Server
  */
-exports.buildServer = server.makeProtobufServerConstructor;
+exports.Server = server.Server;
 
 /**
  * Status name to code number mapping
@@ -159,5 +159,3 @@
 exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
 
 exports.makeGenericClientConstructor = client.makeClientConstructor;
-
-exports.makeGenericServerConstructor = server.makeServerConstructor;
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 0baa78a..505c6bb 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -38,7 +38,6 @@
 var _ = require('lodash');
 var grpc = require('..');
 var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
-var Server = grpc.buildServer([testProto.TestService.service]);
 
 /**
  * Create a buffer filled with size zeroes
@@ -173,16 +172,15 @@
                                                     key_data,
                                                     pem_data);
   }
-  var server = new Server({
-    'grpc.testing.TestService' : {
-      emptyCall: handleEmpty,
-      unaryCall: handleUnary,
-      streamingOutputCall: handleStreamingOutput,
-      streamingInputCall: handleStreamingInput,
-      fullDuplexCall: handleFullDuplex,
-      halfDuplexCall: handleHalfDuplex
-    }
-  }, null, options);
+  var server = new grpc.Server(options);
+  server.addProtoService(testProto.TestService.service, {
+    emptyCall: handleEmpty,
+    unaryCall: handleUnary,
+    streamingOutputCall: handleStreamingOutput,
+    streamingInputCall: handleStreamingInput,
+    fullDuplexCall: handleFullDuplex,
+    halfDuplexCall: handleHalfDuplex
+  });
   var port_num = server.bind('0.0.0.0:' + port, server_creds);
   return {server: server, port: port_num};
 }
diff --git a/src/node/package.json b/src/node/package.json
index 7d4a493..1caf158 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "0.9.1",
+  "version": "0.10.0",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
@@ -27,7 +27,7 @@
     "bindings": "^1.2.0",
     "lodash": "^3.9.3",
     "nan": "^1.5.0",
-    "protobufjs": "dcodeIO/ProtoBuf.js"
+    "protobufjs": "^4.0.0"
   },
   "devDependencies": {
     "async": "^0.9.0",
diff --git a/src/node/src/server.js b/src/node/src/server.js
index c6cf9e7..0a3a003 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -55,7 +55,7 @@
  */
 function handleError(call, error) {
   var status = {
-    code: grpc.status.INTERNAL,
+    code: grpc.status.UNKNOWN,
     details: 'Unknown Error',
     metadata: {}
   };
@@ -72,6 +72,9 @@
     status.metadata = error.metadata;
   }
   var error_batch = {};
+  if (!call.metadataSent) {
+    error_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+  }
   error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
   call.startBatch(error_batch, function(){});
 }
@@ -115,6 +118,10 @@
   if (metadata) {
     status.metadata = metadata;
   }
+  if (!call.metadataSent) {
+    end_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+    call.metadataSent = true;
+  }
   end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
   end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
   call.startBatch(end_batch, function (){});
@@ -136,18 +143,22 @@
   stream.serialize = common.wrapIgnoreNull(serialize);
   function sendStatus() {
     var batch = {};
+    if (!stream.call.metadataSent) {
+      stream.call.metadataSent = true;
+      batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+    }
     batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status;
     stream.call.startBatch(batch, function(){});
   }
   stream.on('finish', sendStatus);
   /**
    * Set the pending status to a given error status. If the error does not have
-   * code or details properties, the code will be set to grpc.status.INTERNAL
+   * code or details properties, the code will be set to grpc.status.UNKNOWN
    * and the details will be set to 'Unknown Error'.
    * @param {Error} err The error object
    */
   function setStatus(err) {
-    var code = grpc.status.INTERNAL;
+    var code = grpc.status.UNKNOWN;
     var details = 'Unknown Error';
     var metadata = {};
     if (err.hasOwnProperty('message')) {
@@ -239,6 +250,10 @@
 function _write(chunk, encoding, callback) {
   /* jshint validthis: true */
   var batch = {};
+  if (!this.call.metadataSent) {
+    batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+    this.call.metadataSent = true;
+  }
   batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
   this.call.startBatch(batch, function(err, value) {
     if (err) {
@@ -251,6 +266,23 @@
 
 ServerWritableStream.prototype._write = _write;
 
+function sendMetadata(responseMetadata) {
+  /* jshint validthis: true */
+  if (!this.call.metadataSent) {
+    this.call.metadataSent = true;
+    var batch = [];
+    batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata;
+    this.call.startBatch(batch, function(err) {
+      if (err) {
+        this.emit('error', err);
+        return;
+      }
+    });
+  }
+}
+
+ServerWritableStream.prototype.sendMetadata = sendMetadata;
+
 util.inherits(ServerReadableStream, Readable);
 
 /**
@@ -339,6 +371,7 @@
 
 ServerDuplexStream.prototype._read = _read;
 ServerDuplexStream.prototype._write = _write;
+ServerDuplexStream.prototype.sendMetadata = sendMetadata;
 
 /**
  * Fully handle a unary call
@@ -348,12 +381,20 @@
  */
 function handleUnary(call, handler, metadata) {
   var emitter = new EventEmitter();
+  emitter.sendMetadata = function(responseMetadata) {
+    if (!call.metadataSent) {
+      call.metadataSent = true;
+      var batch = {};
+      batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata;
+      call.startBatch(batch, function() {});
+    }
+  };
   emitter.on('error', function(error) {
     handleError(call, error);
   });
+  emitter.metadata = metadata;
   waitForCancel(call, emitter);
   var batch = {};
-  batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
   batch[grpc.opType.RECV_MESSAGE] = true;
   call.startBatch(batch, function(err, result) {
     if (err) {
@@ -392,8 +433,8 @@
 function handleServerStreaming(call, handler, metadata) {
   var stream = new ServerWritableStream(call, handler.serialize);
   waitForCancel(call, stream);
+  stream.metadata = metadata;
   var batch = {};
-  batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
   batch[grpc.opType.RECV_MESSAGE] = true;
   call.startBatch(batch, function(err, result) {
     if (err) {
@@ -419,13 +460,19 @@
  */
 function handleClientStreaming(call, handler, metadata) {
   var stream = new ServerReadableStream(call, handler.deserialize);
+  stream.sendMetadata = function(responseMetadata) {
+    if (!call.metadataSent) {
+      call.metadataSent = true;
+      var batch = {};
+      batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata;
+      call.startBatch(batch, function() {});
+    }
+  };
   stream.on('error', function(error) {
     handleError(call, error);
   });
   waitForCancel(call, stream);
-  var metadata_batch = {};
-  metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
-  call.startBatch(metadata_batch, function() {});
+  stream.metadata = metadata;
   handler.func(stream, function(err, value, trailer) {
     stream.terminate();
     if (err) {
@@ -449,9 +496,7 @@
   var stream = new ServerDuplexStream(call, handler.serialize,
                                       handler.deserialize);
   waitForCancel(call, stream);
-  var metadata_batch = {};
-  metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
-  call.startBatch(metadata_batch, function() {});
+  stream.metadata = metadata;
   handler.func(stream);
 }
 
@@ -466,29 +511,28 @@
  * Constructs a server object that stores request handlers and delegates
  * incoming requests to those handlers
  * @constructor
- * @param {function(string, Object<string, Array<Buffer>>):
-           Object<string, Array<Buffer|string>>=} getMetadata Callback that gets
- *     metatada for a given method
  * @param {Object=} options Options that should be passed to the internal server
  *     implementation
  */
-function Server(getMetadata, options) {
+function Server(options) {
   this.handlers = {};
   var handlers = this.handlers;
   var server = new grpc.Server(options);
   this._server = server;
+  this.started = false;
   /**
    * Start the server and begin handling requests
    * @this Server
    */
-  this.listen = function() {
+  this.start = function() {
+    if (this.started) {
+      throw new Error('Server is already running');
+    }
+    this.started = true;
     console.log('Server starting');
     _.each(handlers, function(handler, handler_name) {
       console.log('Serving', handler_name);
     });
-    if (this.started) {
-      throw 'Server is already running';
-    }
     server.start();
     /**
      * Handles the SERVER_RPC_NEW event. If there is a handler associated with
@@ -523,11 +567,7 @@
         call.startBatch(batch, function() {});
         return;
       }
-      var response_metadata = {};
-      if (getMetadata) {
-        response_metadata = getMetadata(method, metadata);
-      }
-      streamHandlers[handler.type](call, handler, response_metadata);
+      streamHandlers[handler.type](call, handler, metadata);
     }
     server.requestCall(handleNewCall);
   };
@@ -565,6 +605,47 @@
   return true;
 };
 
+Server.prototype.addService = function(service, implementation) {
+  if (this.started) {
+    throw new Error('Can\'t add a service to a started server.');
+  }
+  var self = this;
+  _.each(service, function(attrs, name) {
+    var method_type;
+    if (attrs.requestStream) {
+      if (attrs.responseStream) {
+        method_type = 'bidi';
+      } else {
+        method_type = 'client_stream';
+      }
+    } else {
+      if (attrs.responseStream) {
+        method_type = 'server_stream';
+      } else {
+        method_type = 'unary';
+      }
+    }
+    if (implementation[name] === undefined) {
+      throw new Error('Method handler for ' + attrs.path +
+          ' not provided.');
+    }
+    var serialize = attrs.responseSerialize;
+    var deserialize = attrs.requestDeserialize;
+    var register_success = self.register(attrs.path,
+                                         _.bind(implementation[name],
+                                                implementation),
+                                         serialize, deserialize, method_type);
+    if (!register_success) {
+      throw new Error('Method handler for ' + attrs.path +
+          ' already provided.');
+    }
+  });
+};
+
+Server.prototype.addProtoService = function(service, implementation) {
+  this.addService(common.getProtobufServiceAttrs(service), implementation);
+};
+
 /**
  * Binds the server to the given port, with SSL enabled if creds is given
  * @param {string} port The port that the server should bind on, in the format
@@ -573,6 +654,9 @@
  *     nothing for an insecure port
  */
 Server.prototype.bind = function(port, creds) {
+  if (this.started) {
+    throw new Error('Can\'t bind an already running server to an address');
+  }
   if (creds) {
     return this._server.addSecureHttp2Port(port, creds);
   } else {
@@ -581,130 +665,6 @@
 };
 
 /**
- * Create a constructor for servers with services defined by service_attr_map.
- * That is an object that maps (namespaced) service names to objects that in
- * turn map method names to objects with the following keys:
- * path: The path on the server for accessing the method. For example, for
- *     protocol buffers, we use "/service_name/method_name"
- * requestStream: bool indicating whether the client sends a stream
- * resonseStream: bool indicating whether the server sends a stream
- * requestDeserialize: function to deserialize request objects
- * responseSerialize: function to serialize response objects
- * @param {Object} service_attr_map An object mapping service names to method
- *     attribute map objects
- * @return {function(Object, function, Object=)} New server constructor
+ * See documentation for Server
  */
-function makeServerConstructor(service_attr_map) {
-  /**
-   * Create a server with the given handlers for all of the methods.
-   * @constructor
-   * @param {Object} service_handlers Map from service names to map from method
-   *     names to handlers
-   * @param {function(string, Object<string, Array<Buffer>>):
-             Object<string, Array<Buffer|string>>=} getMetadata Callback that
-   *     gets metatada for a given method
-   * @param {Object=} options Options to pass to the underlying server
-   */
-  function SurfaceServer(service_handlers, getMetadata, options) {
-    var server = new Server(getMetadata, options);
-    this.inner_server = server;
-    _.each(service_attr_map, function(service_attrs, service_name) {
-      if (service_handlers[service_name] === undefined) {
-        throw new Error('Handlers for service ' +
-            service_name + ' not provided.');
-      }
-      _.each(service_attrs, function(attrs, name) {
-        var method_type;
-        if (attrs.requestStream) {
-          if (attrs.responseStream) {
-            method_type = 'bidi';
-          } else {
-            method_type = 'client_stream';
-          }
-        } else {
-          if (attrs.responseStream) {
-            method_type = 'server_stream';
-          } else {
-            method_type = 'unary';
-          }
-        }
-        if (service_handlers[service_name][name] === undefined) {
-          throw new Error('Method handler for ' + attrs.path +
-              ' not provided.');
-        }
-        var serialize = attrs.responseSerialize;
-        var deserialize = attrs.requestDeserialize;
-        server.register(attrs.path, service_handlers[service_name][name],
-                        serialize, deserialize, method_type);
-      });
-    }, this);
-  }
-
-  /**
-   * Binds the server to the given port, with SSL enabled if creds is supplied
-   * @param {string} port The port that the server should bind on, in the format
-   *     "address:port"
-   * @param {boolean=} creds Credentials to use for SSL
-   * @return {SurfaceServer} this
-   */
-  SurfaceServer.prototype.bind = function(port, creds) {
-    return this.inner_server.bind(port, creds);
-  };
-
-  /**
-   * Starts the server listening on any bound ports
-   * @return {SurfaceServer} this
-   */
-  SurfaceServer.prototype.listen = function() {
-    this.inner_server.listen();
-    return this;
-  };
-
-  /**
-   * Shuts the server down; tells it to stop listening for new requests and to
-   * kill old requests.
-   */
-  SurfaceServer.prototype.shutdown = function() {
-    this.inner_server.shutdown();
-  };
-
-  return SurfaceServer;
-}
-
-/**
- * Create a constructor for servers that serve the given services.
- * @param {Array<ProtoBuf.Reflect.Service>} services The services that the
- *     servers will serve
- * @return {function(Object, function, Object=)} New server constructor
- */
-function makeProtobufServerConstructor(services) {
-  var qual_names = [];
-  var service_attr_map = {};
-  _.each(services, function(service) {
-    var service_name = common.fullyQualifiedName(service);
-    _.each(service.children, function(method) {
-      var name = common.fullyQualifiedName(method);
-      if (_.indexOf(qual_names, name) !== -1) {
-        throw new Error('Method ' + name + ' exposed by more than one service');
-      }
-      qual_names.push(name);
-    });
-    var method_attrs = common.getProtobufServiceAttrs(service);
-    if (!service_attr_map.hasOwnProperty(service_name)) {
-      service_attr_map[service_name] = {};
-    }
-    service_attr_map[service_name] = _.extend(service_attr_map[service_name],
-                                              method_attrs);
-  });
-  return makeServerConstructor(service_attr_map);
-}
-
-/**
- * See documentation for makeServerConstructor
- */
-exports.makeServerConstructor = makeServerConstructor;
-
-/**
- * See documentation for makeProtobufServerConstructor
- */
-exports.makeProtobufServerConstructor = makeProtobufServerConstructor;
+exports.Server = Server;
diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js
new file mode 100644
index 0000000..bb700cc
--- /dev/null
+++ b/src/node/test/health_test.js
@@ -0,0 +1,102 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+'use strict';
+
+var assert = require('assert');
+
+var health = require('../health_check/health.js');
+
+var grpc = require('../');
+
+describe('Health Checking', function() {
+  var statusMap = {
+    '': {
+      '': 'SERVING',
+      'grpc.test.TestService': 'NOT_SERVING',
+    },
+    virtual_host: {
+      'grpc.test.TestService': 'SERVING'
+    }
+  };
+  var healthServer = new grpc.Server();
+  healthServer.addProtoService(health.service,
+                               new health.Implementation(statusMap));
+  var healthClient;
+  before(function() {
+    var port_num = healthServer.bind('0.0.0.0:0');
+    healthServer.start();
+    healthClient = new health.Client('localhost:' + port_num);
+  });
+  after(function() {
+    healthServer.shutdown();
+  });
+  it('should say an enabled service is SERVING', function(done) {
+    healthClient.check({service: ''}, function(err, response) {
+      assert.ifError(err);
+      assert.strictEqual(response.status, 'SERVING');
+      done();
+    });
+  });
+  it('should say that a disabled service is NOT_SERVING', function(done) {
+    healthClient.check({service: 'grpc.test.TestService'},
+                       function(err, response) {
+                         assert.ifError(err);
+                         assert.strictEqual(response.status, 'NOT_SERVING');
+                         done();
+                       });
+  });
+  it('should say that a service on another host is SERVING', function(done) {
+    healthClient.check({host: 'virtual_host', service: 'grpc.test.TestService'},
+                       function(err, response) {
+                         assert.ifError(err);
+                         assert.strictEqual(response.status, 'SERVING');
+                         done();
+                       });
+  });
+  it('should get NOT_FOUND if the service is not registered', function(done) {
+    healthClient.check({service: 'not_registered'}, function(err, response) {
+      assert(err);
+      assert.strictEqual(err.code, grpc.status.NOT_FOUND);
+      done();
+    });
+  });
+  it('should get NOT_FOUND if the host is not registered', function(done) {
+    healthClient.check({host: 'wrong_host', service: 'grpc.test.TestService'},
+                       function(err, response) {
+                         assert(err);
+                         assert.strictEqual(err.code, grpc.status.NOT_FOUND);
+                         done();
+                       });
+  });
+});
diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js
index fcd8eb6..0a5eb29 100644
--- a/src/node/test/interop_sanity_test.js
+++ b/src/node/test/interop_sanity_test.js
@@ -46,7 +46,7 @@
   before(function(done) {
     var server_obj = interop_server.getServer(0, true);
     server = server_obj.server;
-    server.listen();
+    server.start();
     port = 'localhost:' + server_obj.port;
     done();
   });
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 3461922..f275185 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -52,7 +52,7 @@
 describe('Math client', function() {
   before(function(done) {
     var port_num = server.bind('0.0.0.0:0');
-    server.listen();
+    server.start();
     math_client = new math.Math('localhost:' + port_num);
     done();
   });
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 8d1f99a..18178e4 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -69,34 +69,45 @@
     });
   });
 });
-describe('Surface server constructor', function() {
-  it('Should fail with conflicting method names', function() {
-    assert.throws(function() {
-      grpc.buildServer([mathService, mathService]);
-    });
+describe('Server.prototype.addProtoService', function() {
+  var server;
+  var dummyImpls = {
+    'div': function() {},
+    'divMany': function() {},
+    'fib': function() {},
+    'sum': function() {}
+  };
+  beforeEach(function() {
+    server = new grpc.Server();
+  });
+  afterEach(function() {
+    server.shutdown();
   });
   it('Should succeed with a single service', function() {
     assert.doesNotThrow(function() {
-      grpc.buildServer([mathService]);
+      server.addProtoService(mathService, dummyImpls);
+    });
+  });
+  it('Should fail with conflicting method names', function() {
+    server.addProtoService(mathService, dummyImpls);
+    assert.throws(function() {
+      server.addProtoService(mathService, dummyImpls);
     });
   });
   it('Should fail with missing handlers', function() {
-    var Server = grpc.buildServer([mathService]);
     assert.throws(function() {
-      new Server({
-        'math.Math': {
-          'div': function() {},
-          'divMany': function() {},
-          'fib': function() {}
-        }
+      server.addProtoService(mathService, {
+        'div': function() {},
+        'divMany': function() {},
+        'fib': function() {}
       });
     }, /math.Math.Sum/);
   });
-  it('Should fail with no handlers for the service', function() {
-    var Server = grpc.buildServer([mathService]);
+  it('Should fail if the server has been started', function() {
+    server.start();
     assert.throws(function() {
-      new Server({});
-    }, /math.Math/);
+      server.addProtoService(mathService, dummyImpls);
+    });
   });
 });
 describe('Echo service', function() {
@@ -105,18 +116,16 @@
   before(function() {
     var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto');
     var echo_service = test_proto.lookup('EchoService');
-    var Server = grpc.buildServer([echo_service]);
-    server = new Server({
-      'EchoService': {
-        echo: function(call, callback) {
-          callback(null, call.request);
-        }
+    server = new grpc.Server();
+    server.addProtoService(echo_service, {
+      echo: function(call, callback) {
+        callback(null, call.request);
       }
     });
     var port = server.bind('localhost:0');
     var Client = surface_client.makeProtobufClientConstructor(echo_service);
     client = new Client('localhost:' + port);
-    server.listen();
+    server.start();
   });
   after(function() {
     server.shutdown();
@@ -151,18 +160,14 @@
     var client;
     var server;
     before(function() {
-      var Server = grpc.makeGenericServerConstructor({
-        string: string_service_attrs
-      });
-      server = new Server({
-        string: {
-          capitalize: function(call, callback) {
-            callback(null, _.capitalize(call.request));
-          }
+      server = new grpc.Server();
+      server.addService(string_service_attrs, {
+        capitalize: function(call, callback) {
+          callback(null, _.capitalize(call.request));
         }
       });
       var port = server.bind('localhost:0');
-      server.listen();
+      server.start();
       var Client = grpc.makeGenericClientConstructor(string_service_attrs);
       client = new Client('localhost:' + port);
     });
@@ -178,6 +183,82 @@
     });
   });
 });
+describe('Echo metadata', function() {
+  var client;
+  var server;
+  before(function() {
+    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_service = test_proto.lookup('TestService');
+    server = new grpc.Server();
+    server.addProtoService(test_service, {
+      unary: function(call, cb) {
+        call.sendMetadata(call.metadata);
+        cb(null, {});
+      },
+      clientStream: function(stream, cb){
+        stream.on('data', function(data) {});
+        stream.on('end', function() {
+          stream.sendMetadata(stream.metadata);
+          cb(null, {});
+        });
+      },
+      serverStream: function(stream) {
+        stream.sendMetadata(stream.metadata);
+        stream.end();
+      },
+      bidiStream: function(stream) {
+        stream.on('data', function(data) {});
+        stream.on('end', function() {
+          stream.sendMetadata(stream.metadata);
+          stream.end();
+        });
+      }
+    });
+    var port = server.bind('localhost:0');
+    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    client = new Client('localhost:' + port);
+    server.start();
+  });
+  after(function() {
+    server.shutdown();
+  });
+  it('with unary call', function(done) {
+    var call = client.unary({}, function(err, data) {
+      assert.ifError(err);
+    }, {key: ['value']});
+    call.on('metadata', function(metadata) {
+      assert.deepEqual(metadata.key, ['value']);
+      done();
+    });
+  });
+  it('with client stream call', function(done) {
+    var call = client.clientStream(function(err, data) {
+      assert.ifError(err);
+    }, {key: ['value']});
+    call.on('metadata', function(metadata) {
+      assert.deepEqual(metadata.key, ['value']);
+      done();
+    });
+    call.end();
+  });
+  it('with server stream call', function(done) {
+    var call = client.serverStream({}, {key: ['value']});
+    call.on('data', function() {});
+    call.on('metadata', function(metadata) {
+      assert.deepEqual(metadata.key, ['value']);
+      done();
+    });
+  });
+  it('with bidi stream call', function(done) {
+    var call = client.bidiStream({key: ['value']});
+    call.on('data', function() {});
+    call.on('metadata', function(metadata) {
+      assert.deepEqual(metadata.key, ['value']);
+      done();
+    });
+    call.end();
+  });
+});
 describe('Other conditions', function() {
   var client;
   var server;
@@ -185,72 +266,70 @@
   before(function() {
     var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
     var test_service = test_proto.lookup('TestService');
-    var Server = grpc.buildServer([test_service]);
-    server = new Server({
-      TestService: {
-        unary: function(call, cb) {
-          var req = call.request;
-          if (req.error) {
-            cb(new Error('Requested error'), null, {metadata: ['yes']});
+    server = new grpc.Server();
+    server.addProtoService(test_service, {
+      unary: function(call, cb) {
+        var req = call.request;
+        if (req.error) {
+          cb(new Error('Requested error'), null, {trailer_present: ['yes']});
+        } else {
+          cb(null, {count: 1}, {trailer_present: ['yes']});
+        }
+      },
+      clientStream: function(stream, cb){
+        var count = 0;
+        var errored;
+        stream.on('data', function(data) {
+          if (data.error) {
+            errored = true;
+            cb(new Error('Requested error'), null, {trailer_present: ['yes']});
           } else {
-            cb(null, {count: 1}, {metadata: ['yes']});
+            count += 1;
           }
-        },
-        clientStream: function(stream, cb){
-          var count = 0;
-          var errored;
-          stream.on('data', function(data) {
-            if (data.error) {
-              errored = true;
-              cb(new Error('Requested error'), null, {metadata: ['yes']});
-            } else {
-              count += 1;
-            }
-          });
-          stream.on('end', function() {
-            if (!errored) {
-              cb(null, {count: count}, {metadata: ['yes']});
-            }
-          });
-        },
-        serverStream: function(stream) {
-          var req = stream.request;
-          if (req.error) {
+        });
+        stream.on('end', function() {
+          if (!errored) {
+            cb(null, {count: count}, {trailer_present: ['yes']});
+          }
+        });
+      },
+      serverStream: function(stream) {
+        var req = stream.request;
+        if (req.error) {
+          var err = new Error('Requested error');
+          err.metadata = {trailer_present: ['yes']};
+          stream.emit('error', err);
+        } else {
+          for (var i = 0; i < 5; i++) {
+            stream.write({count: i});
+          }
+          stream.end({trailer_present: ['yes']});
+        }
+      },
+      bidiStream: function(stream) {
+        var count = 0;
+        stream.on('data', function(data) {
+          if (data.error) {
             var err = new Error('Requested error');
-            err.metadata = {metadata: ['yes']};
+            err.metadata = {
+              trailer_present: ['yes'],
+              count: ['' + count]
+            };
             stream.emit('error', err);
           } else {
-            for (var i = 0; i < 5; i++) {
-              stream.write({count: i});
-            }
-            stream.end({metadata: ['yes']});
+            stream.write({count: count});
+            count += 1;
           }
-        },
-        bidiStream: function(stream) {
-          var count = 0;
-          stream.on('data', function(data) {
-            if (data.error) {
-              var err = new Error('Requested error');
-              err.metadata = {
-                metadata: ['yes'],
-                count: ['' + count]
-              };
-              stream.emit('error', err);
-            } else {
-              stream.write({count: count});
-              count += 1;
-            }
-          });
-          stream.on('end', function() {
-            stream.end({metadata: ['yes']});
-          });
-        }
+        });
+        stream.on('end', function() {
+          stream.end({trailer_present: ['yes']});
+        });
       }
     });
     port = server.bind('localhost:0');
     var Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port);
-    server.listen();
+    server.start();
   });
   after(function() {
     server.shutdown();
@@ -340,7 +419,7 @@
         assert.ifError(err);
       });
       call.on('status', function(status) {
-        assert.deepEqual(status.metadata.metadata, ['yes']);
+        assert.deepEqual(status.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -349,7 +428,7 @@
         assert(err);
       });
       call.on('status', function(status) {
-        assert.deepEqual(status.metadata.metadata, ['yes']);
+        assert.deepEqual(status.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -361,7 +440,7 @@
       call.write({error: false});
       call.end();
       call.on('status', function(status) {
-        assert.deepEqual(status.metadata.metadata, ['yes']);
+        assert.deepEqual(status.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -373,7 +452,7 @@
       call.write({error: true});
       call.end();
       call.on('status', function(status) {
-        assert.deepEqual(status.metadata.metadata, ['yes']);
+        assert.deepEqual(status.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -382,7 +461,7 @@
       call.on('data', function(){});
       call.on('status', function(status) {
         assert.strictEqual(status.code, grpc.status.OK);
-        assert.deepEqual(status.metadata.metadata, ['yes']);
+        assert.deepEqual(status.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -390,7 +469,7 @@
       var call = client.serverStream({error: true});
       call.on('data', function(){});
       call.on('error', function(error) {
-        assert.deepEqual(error.metadata.metadata, ['yes']);
+        assert.deepEqual(error.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -402,7 +481,7 @@
       call.on('data', function(){});
       call.on('status', function(status) {
         assert.strictEqual(status.code, grpc.status.OK);
-        assert.deepEqual(status.metadata.metadata, ['yes']);
+        assert.deepEqual(status.metadata.trailer_present, ['yes']);
         done();
       });
     });
@@ -413,7 +492,49 @@
       call.end();
       call.on('data', function(){});
       call.on('error', function(error) {
-        assert.deepEqual(error.metadata.metadata, ['yes']);
+        assert.deepEqual(error.metadata.trailer_present, ['yes']);
+        done();
+      });
+    });
+  });
+  describe('Error object should contain the status', function() {
+    it('for a unary call', function(done) {
+      client.unary({error: true}, function(err, data) {
+        assert(err);
+        assert.strictEqual(err.code, grpc.status.UNKNOWN);
+        assert.strictEqual(err.message, 'Requested error');
+        done();
+      });
+    });
+    it('for a client stream call', function(done) {
+      var call = client.clientStream(function(err, data) {
+        assert(err);
+        assert.strictEqual(err.code, grpc.status.UNKNOWN);
+        assert.strictEqual(err.message, 'Requested error');
+        done();
+      });
+      call.write({error: false});
+      call.write({error: true});
+      call.end();
+    });
+    it('for a server stream call', function(done) {
+      var call = client.serverStream({error: true});
+      call.on('data', function(){});
+      call.on('error', function(error) {
+        assert.strictEqual(error.code, grpc.status.UNKNOWN);
+        assert.strictEqual(error.message, 'Requested error');
+        done();
+      });
+    });
+    it('for a bidi stream call', function(done) {
+      var call = client.bidiStream();
+      call.write({error: false});
+      call.write({error: true});
+      call.end();
+      call.on('data', function(){});
+      call.on('error', function(error) {
+        assert.strictEqual(error.code, grpc.status.UNKNOWN);
+        assert.strictEqual(error.message, 'Requested error');
         done();
       });
     });
@@ -423,18 +544,17 @@
   var client;
   var server;
   before(function() {
-    var Server = grpc.buildServer([mathService]);
-    server = new Server({
-      'math.Math': {
-        'div': function(stream) {},
-        'divMany': function(stream) {},
-        'fib': function(stream) {},
-        'sum': function(stream) {}
-      }
+    server = new grpc.Server();
+    server.addProtoService(mathService, {
+      'div': function(stream) {},
+      'divMany': function(stream) {},
+      'fib': function(stream) {},
+      'sum': function(stream) {}
     });
     var port = server.bind('localhost:0');
     var Client = surface_client.makeProtobufClientConstructor(mathService);
     client = new Client('localhost:' + port);
+    server.start();
   });
   after(function() {
     server.shutdown();
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 7b42498..4a8b7ff 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -46,15 +46,13 @@
 // transparently on the same TCP connection.
 
 #import <Foundation/Foundation.h>
-#import <gRPC/GRXWriter.h>
-
-@class GRPCMethodName;
+#import <RxLibrary/GRXWriter.h>
 
 // Key used in |NSError|'s |userInfo| dictionary to store the response metadata sent by the server.
 extern id const kGRPCStatusMetadataKey;
 
 // Represents a single gRPC remote call.
-@interface GRPCCall : NSObject<GRXWriter>
+@interface GRPCCall : GRXWriter
 
 // 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.
@@ -90,8 +88,8 @@
 // the specific remote method called).
 // To finish a call right away, invoke cancel.
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
-              requestsWriter:(id<GRXWriter>)requestsWriter NS_DESIGNATED_INITIALIZER;
+                        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
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index a9625a1..9435bf2 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -34,13 +34,11 @@
 #import "GRPCCall.h"
 
 #include <grpc/grpc.h>
-#include <grpc/support/grpc_time.h>
+#include <grpc/support/time.h>
+#import <RxLibrary/GRXConcurrentWriteable.h>
 
-#import "GRPCMethodName.h"
 #import "private/GRPCChannel.h"
 #import "private/GRPCCompletionQueue.h"
-#import "private/GRPCDelegateWrapper.h"
-#import "private/GRPCMethodName+HTTP2Encoding.h"
 #import "private/GRPCWrappedCall.h"
 #import "private/NSData+GRPC.h"
 #import "private/NSDictionary+GRPC.h"
@@ -80,8 +78,12 @@
   // do. Particularly, in the face of errors, there's no ordering guarantee at
   // all. This wrapper over our actual writeable ensures thread-safety and
   // correct ordering.
-  GRPCDelegateWrapper *_responseWriteable;
-  id<GRXWriter> _requestWriter;
+  GRXConcurrentWriteable *_responseWriteable;
+  GRXWriter *_requestWriter;
+
+  // To create a retain cycle when a call is started, up until it finishes. See
+  // |startWithWriteable:| and |finishWithError:|.
+  GRPCCall *_self;
 
   NSMutableDictionary *_requestMetadata;
   NSMutableDictionary *_responseMetadata;
@@ -90,14 +92,14 @@
 @synthesize state = _state;
 
 - (instancetype)init {
-  return [self initWithHost:nil method:nil requestsWriter:nil];
+  return [self initWithHost:nil path:nil requestsWriter:nil];
 }
 
 // Designated initializer
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
-              requestsWriter:(id<GRXWriter>)requestWriter {
-  if (!host || !method) {
+                        path:(NSString *)path
+              requestsWriter:(GRXWriter *)requestWriter {
+  if (!host || !path) {
     [NSException raise:NSInvalidArgumentException format:@"Neither host nor method can be nil."];
   }
   if (requestWriter.state != GRXWriterStateNotStarted) {
@@ -114,7 +116,7 @@
     _channel = [GRPCChannel channelToHost:host];
 
     _wrappedCall = [[GRPCWrappedCall alloc] initWithChannel:_channel
-                                                     method:method.HTTP2Path
+                                                       path:path
                                                        host:host];
 
     // Serial queue to invoke the non-reentrant methods of the grpc_call object.
@@ -145,8 +147,13 @@
 #pragma mark Finish
 
 - (void)finishWithError:(NSError *)errorOrNil {
+  // If the call isn't retained anywhere else, it can be deallocated now.
+  _self = nil;
+
+  // If there were still request messages coming, stop them.
   _requestWriter.state = GRXWriterStateFinished;
   _requestWriter = nil;
+
   if (errorOrNil) {
     [_responseWriteable cancelWithError:errorOrNil];
   } else {
@@ -193,7 +200,7 @@
     return;
   }
   __weak GRPCCall *weakSelf = self;
-  __weak GRPCDelegateWrapper *weakWriteable = _responseWriteable;
+  __weak GRXConcurrentWriteable *weakWriteable = _responseWriteable;
 
   dispatch_async(_callQueue, ^{
     [weakSelf startReadWithHandler:^(grpc_byte_buffer *message) {
@@ -218,7 +225,7 @@
         [weakSelf cancelCall];
         return;
       }
-      [weakWriteable enqueueMessage:data completionHandler:^{
+      [weakWriteable enqueueValue:data completionHandler:^{
         [weakSelf startNextRead];
       }];
     }];
@@ -278,6 +285,7 @@
 }
 
 - (void)writesFinishedWithError:(NSError *)errorOrNil {
+  _requestWriter = nil;
   if (errorOrNil) {
     [self cancel];
   } else {
@@ -337,12 +345,14 @@
 #pragma mark GRXWriter implementation
 
 - (void)startWithWriteable:(id<GRXWriteable>)writeable {
-  // The following produces a retain cycle self:_responseWriteable:self, which is only
-  // broken when writesFinishedWithError: is sent to the wrapped writeable.
-  // Care is taken not to retain self strongly in any of the blocks used in
-  // the implementation of GRPCCall, so that the life of the instance is
-  // determined by this retain cycle.
-  _responseWriteable = [[GRPCDelegateWrapper alloc] initWithWriteable:writeable writer:self];
+  // Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
+  // This makes RPCs in which the call isn't externally retained possible (as long as it is started
+  // before being autoreleased).
+  // Care is taken not to retain self strongly in any of the blocks used in this implementation, so
+  // that the life of the instance is determined by this retain cycle.
+  _self = self;
+
+  _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
   [self sendHeaders:_requestMetadata];
   [self invokeCall];
 }
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 36f4c0a..af43263 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -60,7 +60,7 @@
 }
 
 - (instancetype)initWithHost:(NSString *)host {
-  if (![host containsString:@"://"]) {
+  if (![host rangeOfString:@"://"].length) {
     // No scheme provided; assume https.
     host = [@"https://" stringByAppendingString:host];
   }
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index 40aade4..12535c9 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -65,7 +65,8 @@
     dispatch_async(gDefaultConcurrentQueue, ^{
       while (YES) {
         // The following call blocks until an event is available.
-        grpc_event event = grpc_completion_queue_next(unmanagedQueue, gpr_inf_future);
+        grpc_event event = grpc_completion_queue_next(unmanagedQueue,
+                                                      gpr_inf_future(GPR_CLOCK_REALTIME));
         GRPCQueueCompletionHandler handler;
         switch (event.type) {
           case GRPC_OP_COMPLETE:
diff --git a/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.h b/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.h
deleted file mode 100644
index 1ef245f..0000000
--- a/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.h
+++ /dev/null
@@ -1,80 +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.
- *
- */
-
-#import <Foundation/Foundation.h>
-
-@protocol GRXWriteable;
-@protocol GRXWriter;
-
-// This is a thread-safe wrapper over a GRXWriteable instance. It lets one
-// enqueue calls to a GRXWriteable instance for the main thread, guaranteeing
-// that writesFinishedWithError: is the last message sent to it (no matter what
-// messages are sent to the wrapper, in what order, nor from which thread). It
-// also guarantees that, if cancelWithError: is called from the main thread
-// (e.g. by the app cancelling the writes), no further messages are sent to the
-// writeable except writesFinishedWithError:.
-//
-// TODO(jcanizales): Let the user specify another queue for the writeable
-// callbacks.
-// TODO(jcanizales): Rename to GRXWriteableWrapper and move to the Rx library.
-@interface GRPCDelegateWrapper : NSObject
-
-// The GRXWriteable passed is the wrapped writeable.
-// Both the GRXWriter instance and the GRXWriteable instance are retained until
-// writesFinishedWithError: is sent to the writeable, and released after that.
-// This is used to create a retain cycle that keeps both objects alive until the
-// writing is explicitly finished.
-- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable writer:(id<GRXWriter>)writer
-    NS_DESIGNATED_INITIALIZER;
-
-// Enqueues writeValue: to be sent to the writeable in the main thread.
-// The passed handler is invoked from the main thread after writeValue: returns.
-- (void)enqueueMessage:(NSData *)message completionHandler:(void (^)())handler;
-
-// Enqueues writesFinishedWithError:nil to be sent to the writeable in the main
-// thread. After that message is sent to the writeable, all other methods of
-// this object are effectively noops.
-- (void)enqueueSuccessfulCompletion;
-
-// If the writeable has not yet received a writesFinishedWithError: message, this
-// will enqueue one to be sent to it in the main thread, and cancel all other
-// pending messages to the writeable enqueued by this object (both past and
-// future).
-// The error argument cannot be nil.
-- (void)cancelWithError:(NSError *)error;
-
-// Cancels all pending messages to the writeable enqueued by this object (both
-// past and future). Because the writeable won't receive writesFinishedWithError:,
-// this also releases the writeable and the writer.
-- (void)cancelSilently;
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m b/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m
deleted file mode 100644
index 3ad757f..0000000
--- a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m
+++ /dev/null
@@ -1,44 +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.
- *
- */
-
-#import "GRPCMethodName+HTTP2Encoding.h"
-
-@implementation GRPCMethodName (HTTP2Encoding)
-- (NSString *)HTTP2Path {
-  if (self.package) {
-    return [NSString stringWithFormat:@"/%@.%@/%@", self.package, self.interface, self.method];
-  } else {
-    return [NSString stringWithFormat:@"/%@/%@", self.interface, self.method];
-  }
-}
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
index 2cbc6e0..43a8bd5 100644
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
@@ -38,13 +38,17 @@
 @implementation GRPCSecureChannel
 
 - (instancetype)initWithHost:(NSString *)host {
-  static const grpc_credentials *kCredentials;
+  static grpc_credentials *kCredentials;
   static dispatch_once_t loading;
   dispatch_once(&loading, ^{
     // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
     NSBundle *bundle = [NSBundle bundleForClass:self.class];
-    NSString *certsPath = [bundle pathForResource:@"gRPC.bundle/roots" ofType:@"pem"];
+    NSString *certsPath = [bundle pathForResource:@"gRPCCertificates.bundle/roots" ofType:@"pem"];
+    NSAssert(certsPath.length,
+             @"gRPCCertificates.bundle/roots.pem not found under %@. This file, with the root "
+             "certificates, is needed to establish TLS (HTTPS) connections.", bundle.bundlePath);
     NSData *certsData = [NSData dataWithContentsOfFile:certsPath];
+    NSAssert(certsData.length, @"No data read from %@", certsPath);
     NSString *certsString = [[NSString alloc] initWithData:certsData encoding:NSUTF8StringEncoding];
     kCredentials = grpc_ssl_credentials_create(certsString.UTF8String, NULL);
   });
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index 4deeec0..18f8bb5 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -33,60 +33,58 @@
 
 #import <Foundation/Foundation.h>
 #include <grpc/grpc.h>
+
 #import "GRPCChannel.h"
 
-typedef void(^GRPCCompletionHandler)(NSDictionary *);
-
-@protocol GRPCOp <NSObject>
-
-- (void)getOp:(grpc_op *)op;
-
+@interface GRPCOperation : NSObject
+@property(nonatomic, readonly) grpc_op op;
+// Guaranteed to be called when the operation has finished.
 - (void)finish;
-
 @end
 
-@interface GRPCOpSendMetadata : NSObject <GRPCOp>
+@interface GRPCOpSendMetadata : GRPCOperation
 
 - (instancetype)initWithMetadata:(NSDictionary *)metadata
-                         handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
+                         handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
-@interface GRPCOpSendMessage : NSObject <GRPCOp>
+@interface GRPCOpSendMessage : GRPCOperation
 
 - (instancetype)initWithMessage:(NSData *)message
-                        handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
+                        handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
-@interface GRPCOpSendClose : NSObject <GRPCOp>
+@interface GRPCOpSendClose : GRPCOperation
 
-- (instancetype)initWithHandler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithHandler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
-@interface GRPCOpRecvMetadata : NSObject <GRPCOp>
+@interface GRPCOpRecvMetadata : GRPCOperation
 
 - (instancetype)initWithHandler:(void(^)(NSDictionary *))handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
-@interface GRPCOpRecvMessage : NSObject <GRPCOp>
+@interface GRPCOpRecvMessage : GRPCOperation
 
 - (instancetype)initWithHandler:(void(^)(grpc_byte_buffer *))handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
-@interface GRPCOpRecvStatus : NSObject <GRPCOp>
+@interface GRPCOpRecvStatus : GRPCOperation
 
-- (instancetype)initWithHandler:(void(^)(NSError *, NSDictionary *))handler NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithHandler:(void(^)(NSError *, NSDictionary *))handler
+    NS_DESIGNATED_INITIALIZER;
 
 @end
 
 @interface GRPCWrappedCall : NSObject
 
 - (instancetype)initWithChannel:(GRPCChannel *)channel
-                         method:(NSString *)method
+                           path:(NSString *)path
                            host:(NSString *)host NS_DESIGNATED_INITIALIZER;
 
 - (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)())errorHandler;
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index ea482b2..1db63df 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -41,110 +41,85 @@
 #import "NSData+GRPC.h"
 #import "NSError+GRPC.h"
 
-@implementation GRPCOpSendMetadata{
-  void(^_handler)(void);
-  grpc_metadata *_sendMetadata;
-  size_t _count;
+@implementation GRPCOperation {
+@protected
+  // Most operation subclasses don't set any flags in the grpc_op, and rely on the flag member being
+  // initialized to zero.
+  grpc_op _op;
+  void(^_handler)();
 }
 
+- (void)finish {
+  if (_handler) {
+    _handler();
+  }
+}
+@end
+
+@implementation GRPCOpSendMetadata
+
 - (instancetype)init {
   return [self initWithMetadata:nil handler:nil];
 }
 
-- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)(void))handler {
+- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)())handler {
   if (self = [super init]) {
-    _sendMetadata = [metadata grpc_metadataArray];
-    _count = metadata.count;
+    _op.op = GRPC_OP_SEND_INITIAL_METADATA;
+    _op.data.send_initial_metadata.count = metadata.count;
+    _op.data.send_initial_metadata.metadata = metadata.grpc_metadataArray;
     _handler = handler;
   }
   return self;
 }
 
-- (void)getOp:(grpc_op *)op {
-  op->op = GRPC_OP_SEND_INITIAL_METADATA;
-  op->data.send_initial_metadata.count = _count;
-  op->data.send_initial_metadata.metadata = _sendMetadata;
-}
-
-- (void)finish {
-  if (_handler) {
-    _handler();
-  }
-}
-
 - (void)dealloc {
-  gpr_free(_sendMetadata);
+  gpr_free(_op.data.send_initial_metadata.metadata);
 }
 
 @end
 
-@implementation GRPCOpSendMessage{
-  void(^_handler)(void);
-  grpc_byte_buffer *_byteBuffer;
-}
+@implementation GRPCOpSendMessage
 
 - (instancetype)init {
   return [self initWithMessage:nil handler:nil];
 }
 
-- (instancetype)initWithMessage:(NSData *)message handler:(void (^)(void))handler {
+- (instancetype)initWithMessage:(NSData *)message handler:(void (^)())handler {
   if (!message) {
     [NSException raise:NSInvalidArgumentException format:@"message cannot be nil"];
   }
   if (self = [super init]) {
-    _byteBuffer = [message grpc_byteBuffer];
+    _op.op = GRPC_OP_SEND_MESSAGE;
+    _op.data.send_message = message.grpc_byteBuffer;
     _handler = handler;
   }
   return self;
 }
 
-- (void)getOp:(grpc_op *)op {
-  op->op = GRPC_OP_SEND_MESSAGE;
-  op->data.send_message = _byteBuffer;
-}
-
-- (void)finish {
-  if (_handler) {
-    _handler();
-  }
-}
-
 - (void)dealloc {
-  gpr_free(_byteBuffer);
+  gpr_free(_op.data.send_message);
 }
 
 @end
 
-@implementation GRPCOpSendClose{
-  void(^_handler)(void);
-}
+@implementation GRPCOpSendClose
 
 - (instancetype)init {
   return [self initWithHandler:nil];
 }
 
-- (instancetype)initWithHandler:(void (^)(void))handler {
+- (instancetype)initWithHandler:(void (^)())handler {
   if (self = [super init]) {
+    _op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
     _handler = handler;
   }
   return self;
 }
 
-- (void)getOp:(grpc_op *)op {
-  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
-}
-
-- (void)finish {
-  if (_handler) {
-    _handler();
-  }
-}
-
 @end
 
-@implementation GRPCOpRecvMetadata{
-  void(^_handler)(NSDictionary *);
-  grpc_metadata_array _recvInitialMetadata;
+@implementation GRPCOpRecvMetadata {
+  grpc_metadata_array _headers;
 }
 
 - (instancetype) init {
@@ -153,33 +128,31 @@
 
 - (instancetype) initWithHandler:(void (^)(NSDictionary *))handler {
   if (self = [super init]) {
-    _handler = handler;
-    grpc_metadata_array_init(&_recvInitialMetadata);
+    _op.op = GRPC_OP_RECV_INITIAL_METADATA;
+    grpc_metadata_array_init(&_headers);
+    _op.data.recv_initial_metadata = &_headers;
+    if (handler) {
+      // Prevent reference cycle with _handler
+      __weak typeof(self) weakSelf = self;
+      _handler = ^{
+        __strong typeof(self) strongSelf = weakSelf;
+        NSDictionary *metadata = [NSDictionary
+                                  grpc_dictionaryFromMetadataArray:strongSelf->_headers];
+        handler(metadata);
+      };
+    }
   }
   return self;
 }
 
-- (void)getOp:(grpc_op *)op {
-  op->op = GRPC_OP_RECV_INITIAL_METADATA;
-  op->data.recv_initial_metadata = &_recvInitialMetadata;
-}
-
-- (void)finish {
-  NSDictionary *metadata = [NSDictionary grpc_dictionaryFromMetadataArray:_recvInitialMetadata];
-  if (_handler) {
-    _handler(metadata);
-  }
-}
-
 - (void)dealloc {
-  grpc_metadata_array_destroy(&_recvInitialMetadata);
+  grpc_metadata_array_destroy(&_headers);
 }
 
 @end
 
 @implementation GRPCOpRecvMessage{
-  void(^_handler)(grpc_byte_buffer *);
-  grpc_byte_buffer *_recvMessage;
+  grpc_byte_buffer *_receivedMessage;
 }
 
 - (instancetype)init {
@@ -188,30 +161,27 @@
 
 - (instancetype)initWithHandler:(void (^)(grpc_byte_buffer *))handler {
   if (self = [super init]) {
-    _handler = handler;
+    _op.op = GRPC_OP_RECV_MESSAGE;
+    _op.data.recv_message = &_receivedMessage;
+    if (handler) {
+      // Prevent reference cycle with _handler
+      __weak typeof(self) weakSelf = self;
+      _handler = ^{
+        __strong typeof(self) strongSelf = weakSelf;
+        handler(strongSelf->_receivedMessage);
+      };
+    }
   }
   return self;
 }
 
-- (void)getOp:(grpc_op *)op {
-  op->op = GRPC_OP_RECV_MESSAGE;
-  op->data.recv_message = &_recvMessage;
-}
-
-- (void)finish {
-  if (_handler) {
-    _handler(_recvMessage);
-  }
-}
-
 @end
 
 @implementation GRPCOpRecvStatus{
-  void(^_handler)(NSError *, NSDictionary *);
   grpc_status_code _statusCode;
   char *_details;
   size_t _detailsCapacity;
-  grpc_metadata_array _metadata;
+  grpc_metadata_array _trailers;
 }
 
 - (instancetype) init {
@@ -220,30 +190,30 @@
 
 - (instancetype) initWithHandler:(void (^)(NSError *, NSDictionary *))handler {
   if (self = [super init]) {
-    _handler = handler;
-    grpc_metadata_array_init(&_metadata);
+    _op.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+    _op.data.recv_status_on_client.status = &_statusCode;
+    _op.data.recv_status_on_client.status_details = &_details;
+    _op.data.recv_status_on_client.status_details_capacity = &_detailsCapacity;
+    grpc_metadata_array_init(&_trailers);
+    _op.data.recv_status_on_client.trailing_metadata = &_trailers;
+    if (handler) {
+      // Prevent reference cycle with _handler
+      __weak typeof(self) weakSelf = self;
+      _handler = ^{
+        __strong typeof(self) strongSelf = weakSelf;
+        NSError *error = [NSError grpc_errorFromStatusCode:strongSelf->_statusCode
+                                                   details:strongSelf->_details];
+        NSDictionary *trailers = [NSDictionary
+                                  grpc_dictionaryFromMetadataArray:strongSelf->_trailers];
+        handler(error, trailers);
+      };
+    }
   }
   return self;
 }
 
-- (void)getOp:(grpc_op *)op {
-  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
-  op->data.recv_status_on_client.status = &_statusCode;
-  op->data.recv_status_on_client.status_details = &_details;
-  op->data.recv_status_on_client.status_details_capacity = &_detailsCapacity;
-  op->data.recv_status_on_client.trailing_metadata = &_metadata;
-}
-
-- (void)finish {
-  if (_handler) {
-    NSError *error = [NSError grpc_errorFromStatusCode:_statusCode details:_details];
-    NSDictionary *trailers = [NSDictionary grpc_dictionaryFromMetadataArray:_metadata];
-    _handler(error, trailers);
-  }
-}
-
 - (void)dealloc {
-  grpc_metadata_array_destroy(&_metadata);
+  grpc_metadata_array_destroy(&_trailers);
   gpr_free(_details);
 }
 
@@ -255,13 +225,13 @@
 }
 
 - (instancetype)init {
-  return [self initWithChannel:nil method:nil host:nil];
+  return [self initWithChannel:nil path:nil host:nil];
 }
 
 - (instancetype)initWithChannel:(GRPCChannel *)channel
-                         method:(NSString *)method
+                           path:(NSString *)path
                            host:(NSString *)host {
-  if (!channel || !method || !host) {
+  if (!channel || !path || !host) {
     [NSException raise:NSInvalidArgumentException
                 format:@"channel, method, and host cannot be nil."];
   }
@@ -276,8 +246,11 @@
     if (!_queue) {
       return nil;
     }
-    _call = grpc_channel_create_call(channel.unmanagedChannel, _queue.unmanagedQueue,
-                                     method.UTF8String, host.UTF8String, gpr_inf_future);
+    _call = grpc_channel_create_call(channel.unmanagedChannel,
+                                     _queue.unmanagedQueue,
+                                     path.UTF8String,
+                                     host.UTF8String,
+                                     gpr_inf_future(GPR_CLOCK_REALTIME));
     if (_call == NULL) {
       return nil;
     }
@@ -293,8 +266,8 @@
   size_t nops = operations.count;
   grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op));
   size_t i = 0;
-  for (id op in operations) {
-    [op getOp:&ops_array[i++]];
+  for (GRPCOperation *operation in operations) {
+    ops_array[i++] = operation.op;
   }
   grpc_call_error error = grpc_call_start_batch(_call, ops_array, nops,
                                                 (__bridge_retained void *)(^(bool success){
@@ -305,14 +278,16 @@
         return;
       }
     }
-    for (id<GRPCOp> operation in operations) {
+    for (GRPCOperation *operation in operations) {
       [operation finish];
     }
   }));
-  
+  gpr_free(ops_array);
+
   if (error != GRPC_CALL_OK) {
     [NSException raise:NSInternalInconsistencyException
-                format:@"A precondition for calling grpc_call_start_batch wasn't met"];
+                format:@"A precondition for calling grpc_call_start_batch wasn't met. Error %i",
+     error];
   }
 }
 
diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.m b/src/objective-c/GRPCClient/private/NSError+GRPC.m
index f739047..638f41c 100644
--- a/src/objective-c/GRPCClient/private/NSError+GRPC.m
+++ b/src/objective-c/GRPCClient/private/NSError+GRPC.m
@@ -33,7 +33,7 @@
 
 #import "NSError+GRPC.h"
 
-#include <grpc.h>
+#include <grpc/grpc.h>
 
 NSString * const kGRPCErrorDomain = @"io.grpc";
 
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.h b/src/objective-c/ProtoRPC/ProtoMethod.h
similarity index 80%
rename from src/objective-c/GRPCClient/GRPCMethodName.h
rename to src/objective-c/ProtoRPC/ProtoMethod.h
index fe153dd..8f554a0 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.h
+++ b/src/objective-c/ProtoRPC/ProtoMethod.h
@@ -33,17 +33,16 @@
 
 #import <Foundation/Foundation.h>
 
-// See the README file for an introduction to this library.
-
-// A fully-qualified gRPC method name. Full qualification is needed because a gRPC endpoint can
-// implement multiple interfaces.
-// TODO(jcanizales): Move to ProtoRPC package.
-// TODO(jcanizales): Rename interface -> service.
-@interface GRPCMethodName : NSObject
+// A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint
+// can implement multiple services.
+@interface ProtoMethod : NSObject
 @property(nonatomic, readonly) NSString *package;
-@property(nonatomic, readonly) NSString *interface;
+@property(nonatomic, readonly) NSString *service;
 @property(nonatomic, readonly) NSString *method;
+
+@property(nonatomic, readonly) NSString *HTTPPath;
+
 - (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
+                        service:(NSString *)service
                          method:(NSString *)method;
 @end
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.m b/src/objective-c/ProtoRPC/ProtoMethod.m
similarity index 83%
rename from src/objective-c/GRPCClient/GRPCMethodName.m
rename to src/objective-c/ProtoRPC/ProtoMethod.m
index 9672407..1113b4f 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.m
+++ b/src/objective-c/ProtoRPC/ProtoMethod.m
@@ -31,17 +31,25 @@
  *
  */
 
-#import "GRPCMethodName.h"
+#import "ProtoMethod.h"
 
-@implementation GRPCMethodName
+@implementation ProtoMethod
 - (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
+                        service:(NSString *)service
                          method:(NSString *)method {
   if ((self = [super init])) {
     _package = [package copy];
-    _interface = [interface copy];
+    _service = [service copy];
     _method = [method copy];
   }
   return self;
 }
+
+- (NSString *)HTTPPath {
+  if (_package) {
+    return [NSString stringWithFormat:@"/%@.%@/%@", _package, _service, _method];
+  } else {
+    return [NSString stringWithFormat:@"/%@/%@", _service, _method];
+  }
+}
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h
index b6375f5..bd926b7 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.h
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -32,13 +32,15 @@
  */
 
 #import <Foundation/Foundation.h>
-#import <gRPC/GRPCCall.h>
+#import <GRPCClient/GRPCCall.h>
+
+#import "ProtoMethod.h"
 
 @interface ProtoRPC : GRPCCall
 
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
-              requestsWriter:(id<GRXWriter>)requestsWriter
+                      method:(ProtoMethod *)method
+              requestsWriter:(GRXWriter *)requestsWriter
                responseClass:(Class)responseClass
           responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
 
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index b8f8008..889d71a 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -33,29 +33,29 @@
 
 #import "ProtoRPC.h"
 
-#import <gRPC/GRXWriteable.h>
-#import <gRPC/GRXWriter.h>
-#import <gRPC/GRXWriter+Transformations.h>
-#import <Protobuf/GPBProtocolBuffers.h>
+#import <GPBProtocolBuffers.h>
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter+Transformations.h>
 
 @implementation ProtoRPC {
   id<GRXWriteable> _responseWriteable;
 }
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
-              requestsWriter:(id<GRXWriter>)requestsWriter {
-  return [self initWithHost:host
-                     method:method
-             requestsWriter:requestsWriter
-              responseClass:nil
-        responsesWriteable:nil];
+                        path:(NSString *)path
+              requestsWriter:(GRXWriter *)requestsWriter {
+  [NSException raise:NSInvalidArgumentException
+              format:@"Please use ProtoRPC's designated initializer instead."];
+  return nil;
 }
+#pragma clang diagnostic pop
 
 // Designated initializer
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
-              requestsWriter:(id<GRXWriter>)requestsWriter
+                      method:(ProtoMethod *)method
+              requestsWriter:(GRXWriter *)requestsWriter
                responseClass:(Class)responseClass
           responsesWriteable:(id<GRXWriteable>)responsesWriteable {
   // Because we can't tell the type system to constrain the class, we need to check at runtime:
@@ -64,11 +64,12 @@
                 format:@"A protobuf class to parse the responses must be provided."];
   }
   // A writer that serializes the proto messages to send.
-  id<GRXWriter> bytesWriter =
-      [[[GRXWriter alloc] initWithWriter:requestsWriter] map:^id(GPBMessage *proto) {
-        return [proto data];
-      }];
-  if ((self = [super initWithHost:host method:method requestsWriter:bytesWriter])) {
+  GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) {
+    // TODO(jcanizales): Fail with an understandable error message if the requestsWriter isn't
+    // sending GPBMessages.
+    return [proto data];
+  }];
+  if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) {
     // A writeable that parses the proto messages received.
     _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
       [responsesWriteable writeValue:[responseClass parseFromData:value error:NULL]];
diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h
index c5ef820..2e8cb33 100644
--- a/src/objective-c/ProtoRPC/ProtoService.h
+++ b/src/objective-c/ProtoRPC/ProtoService.h
@@ -35,7 +35,7 @@
 
 @class ProtoRPC;
 @protocol GRXWriteable;
-@protocol GRXWriter;
+@class GRXWriter;
 
 @interface ProtoService : NSObject
 - (instancetype)initWithHost:(NSString *)host
@@ -43,7 +43,7 @@
                  serviceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER;
 
 - (ProtoRPC *)RPCToMethod:(NSString *)method
-           requestsWriter:(id<GRXWriter>)requestsWriter
+           requestsWriter:(GRXWriter *)requestsWriter
   	        responseClass:(Class)responseClass
   	   responsesWriteable:(id<GRXWriteable>)responsesWriteable;
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
index 453d7b3..fccc6aa 100644
--- a/src/objective-c/ProtoRPC/ProtoService.m
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -33,10 +33,10 @@
 
 #import "ProtoService.h"
 
-#import <gRPC/GRPCMethodName.h>
-#import <gRPC/GRXWriteable.h>
-#import <gRPC/GRXWriter.h>
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter.h>
 
+#import "ProtoMethod.h"
 #import "ProtoRPC.h"
 
 @implementation ProtoService {
@@ -66,12 +66,12 @@
 }
 
 - (ProtoRPC *)RPCToMethod:(NSString *)method
-           requestsWriter:(id<GRXWriter>)requestsWriter
+           requestsWriter:(GRXWriter *)requestsWriter
             responseClass:(Class)responseClass
        responsesWriteable:(id<GRXWriteable>)responsesWriteable {
-  GRPCMethodName *methodName = [[GRPCMethodName alloc] initWithPackage:_packageName
-                                                             interface:_serviceName
-                                                                method:method];
+  ProtoMethod *methodName = [[ProtoMethod alloc] initWithPackage:_packageName
+                                                         service:_serviceName
+                                                          method:method];
   return [[ProtoRPC alloc] initWithHost:_host
                                  method:methodName
                          requestsWriter:requestsWriter
diff --git a/src/objective-c/RxLibrary/GRXBufferedPipe.h b/src/objective-c/RxLibrary/GRXBufferedPipe.h
index 5e876a7..b6296e1 100644
--- a/src/objective-c/RxLibrary/GRXBufferedPipe.h
+++ b/src/objective-c/RxLibrary/GRXBufferedPipe.h
@@ -51,7 +51,7 @@
 // pipe will keep buffering all data written to it, your application could run out of memory and
 // crash. If you want to react to flow control signals to prevent that, instead of using this class
 // you can implement an object that conforms to GRXWriter.
-@interface GRXBufferedPipe : NSObject<GRXWriteable, GRXWriter>
+@interface GRXBufferedPipe : GRXWriter<GRXWriteable>
 
 // Convenience constructor.
 + (instancetype)pipe;
diff --git a/src/objective-c/RxLibrary/GRXConcurrentWriteable.h b/src/objective-c/RxLibrary/GRXConcurrentWriteable.h
new file mode 100644
index 0000000..1080001
--- /dev/null
+++ b/src/objective-c/RxLibrary/GRXConcurrentWriteable.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "GRXWriter.h"
+#import "GRXWriteable.h"
+
+// This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a
+// GRXWriteable instance for the main thread, guaranteeing that writesFinishedWithError: is the last
+// message sent to it (no matter what messages are sent to the wrapper, in what order, nor from
+// which thread). It also guarantees that, if cancelWithError: is called from the main thread (e.g.
+// by the app cancelling the writes), no further messages are sent to the writeable except
+// writesFinishedWithError:.
+//
+// TODO(jcanizales): Let the user specify another queue for the writeable callbacks.
+@interface GRXConcurrentWriteable : NSObject
+
+// The GRXWriteable passed is the wrapped writeable.
+// The GRXWriteable instance is retained until writesFinishedWithError: is sent to it, and released
+// after that.
+- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable NS_DESIGNATED_INITIALIZER;
+
+// Enqueues writeValue: to be sent to the writeable in the main thread.
+// The passed handler is invoked from the main thread after writeValue: returns.
+- (void)enqueueValue:(id)value completionHandler:(void (^)())handler;
+
+// Enqueues writesFinishedWithError:nil to be sent to the writeable in the main thread. After that
+// message is sent to the writeable, all other methods of this object are effectively noops.
+- (void)enqueueSuccessfulCompletion;
+
+// If the writeable has not yet received a writesFinishedWithError: message, this will enqueue one
+// to be sent to it in the main thread, and cancel all other pending messages to the writeable
+// enqueued by this object (both past and future).
+// The error argument cannot be nil.
+- (void)cancelWithError:(NSError *)error;
+
+// Cancels all pending messages to the writeable enqueued by this object (both past and future).
+// Because the writeable won't receive writesFinishedWithError:, this also releases the writeable.
+- (void)cancelSilently;
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m b/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
similarity index 67%
rename from src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
rename to src/objective-c/RxLibrary/GRXConcurrentWriteable.m
index 7d5ecb5..08bd079 100644
--- a/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
+++ b/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
@@ -31,45 +31,42 @@
  *
  */
 
-#import "GRPCDelegateWrapper.h"
+#import "GRXConcurrentWriteable.h"
 
-#import <gRPC/GRXWriteable.h>
+#import <RxLibrary/GRXWriteable.h>
 
-@interface GRPCDelegateWrapper ()
-// These are atomic so that cancellation can nillify them from any thread.
+@interface GRXConcurrentWriteable ()
+// This is atomic so that cancellation can nillify it from any thread.
 @property(atomic, strong) id<GRXWriteable> writeable;
-@property(atomic, strong) id<GRXWriter> writer;
 @end
 
-@implementation GRPCDelegateWrapper {
+@implementation GRXConcurrentWriteable {
   dispatch_queue_t _writeableQueue;
   // This ensures that writesFinishedWithError: is only sent once to the writeable.
   dispatch_once_t _alreadyFinished;
 }
 
 - (instancetype)init {
-  return [self initWithWriteable:nil writer:nil];
+  return [self initWithWriteable:nil];
 }
 
 // Designated initializer
-- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable writer:(id<GRXWriter>)writer {
+- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable {
   if (self = [super init]) {
     _writeableQueue = dispatch_get_main_queue();
     _writeable = writeable;
-    _writer = writer;
   }
   return self;
 }
 
-- (void)enqueueMessage:(NSData *)message completionHandler:(void (^)())handler {
+- (void)enqueueValue:(id)value completionHandler:(void (^)())handler {
   dispatch_async(_writeableQueue, ^{
-    // We're racing a possible cancellation performed by another thread. To turn
-    // all already-enqueued messages into noops, cancellation nillifies the
-    // writeable property. If we get it before it's nil, we won
-    // the race.
+    // We're racing a possible cancellation performed by another thread. To turn all already-
+    // enqueued messages into noops, cancellation nillifies the writeable property. If we get it
+    // before it's nil, we won the race.
     id<GRXWriteable> writeable = self.writeable;
     if (writeable) {
-      [writeable writeValue:message];
+      [writeable writeValue:value];
       handler();
     }
   });
@@ -78,13 +75,11 @@
 - (void)enqueueSuccessfulCompletion {
   dispatch_async(_writeableQueue, ^{
     dispatch_once(&_alreadyFinished, ^{
-      // Cancellation is now impossible. None of the other three blocks can run
-      // concurrently with this one.
+      // Cancellation is now impossible. None of the other three blocks can run concurrently with
+      // this one.
       [self.writeable writesFinishedWithError:nil];
-      // Break the retain cycle with writer, and skip any possible message to the
-      // wrapped writeable enqueued after this one.
+      // Skip any possible message to the wrapped writeable enqueued after this one.
       self.writeable = nil;
-      self.writer = nil;
     });
   });
 }
@@ -92,29 +87,24 @@
 - (void)cancelWithError:(NSError *)error {
   NSAssert(error, @"For a successful completion, use enqueueSuccessfulCompletion.");
   dispatch_once(&_alreadyFinished, ^{
-    // Skip any of the still-enqueued messages to the wrapped writeable. We use
-    // the atomic setter to nillify writer and writeable because we might be
-    // running concurrently with the blocks in _writeableQueue, and assignment
-    // with ARC isn't atomic.
+    // Skip any of the still-enqueued messages to the wrapped writeable. We use the atomic setter to
+    // nillify writeable because we might be running concurrently with the blocks in
+    // _writeableQueue, and assignment with ARC isn't atomic.
     id<GRXWriteable> writeable = self.writeable;
     self.writeable = nil;
 
     dispatch_async(_writeableQueue, ^{
       [writeable writesFinishedWithError:error];
-      // Break the retain cycle with writer.
-      self.writer = nil;
     });
   });
 }
 
 - (void)cancelSilently {
   dispatch_once(&_alreadyFinished, ^{
-    // Skip any of the still-enqueued messages to the wrapped writeable. We use
-    // the atomic setter to nillify writer and writeable because we might be
-    // running concurrently with the blocks in _writeableQueue, and assignment
-    // with ARC isn't atomic.
+    // Skip any of the still-enqueued messages to the wrapped writeable. We use the atomic setter to
+    // nillify writeable because we might be running concurrently with the blocks in
+    // _writeableQueue, and assignment with ARC isn't atomic.
     self.writeable = nil;
-    self.writer = nil;
   });
 }
 @end
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.m b/src/objective-c/RxLibrary/GRXForwardingWriter.h
similarity index 77%
copy from src/objective-c/GRPCClient/GRPCMethodName.m
copy to src/objective-c/RxLibrary/GRXForwardingWriter.h
index 9672407..d004333 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.m
+++ b/src/objective-c/RxLibrary/GRXForwardingWriter.h
@@ -31,17 +31,13 @@
  *
  */
 
-#import "GRPCMethodName.h"
+#import "GRXWriter.h"
 
-@implementation GRPCMethodName
-- (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
-                         method:(NSString *)method {
-  if ((self = [super init])) {
-    _package = [package copy];
-    _interface = [interface copy];
-    _method = [method copy];
-  }
-  return self;
-}
+// A "proxy" class that simply forwards values, completion, and errors from its
+// input writer to its writeable.
+// It is useful as a superclass for pipes that act as a transformation of their
+// input writer, and for classes that represent objects with input and
+// output sequences of values, like an RPC.
+@interface GRXForwardingWriter : GRXWriter
+- (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER;
 @end
diff --git a/src/objective-c/RxLibrary/GRXForwardingWriter.m b/src/objective-c/RxLibrary/GRXForwardingWriter.m
new file mode 100644
index 0000000..2342f51
--- /dev/null
+++ b/src/objective-c/RxLibrary/GRXForwardingWriter.m
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "GRXForwardingWriter.h"
+
+@interface GRXForwardingWriter () <GRXWriteable>
+@end
+
+@implementation GRXForwardingWriter {
+  GRXWriter *_writer;
+  id<GRXWriteable> _writeable;
+}
+
+- (instancetype)init {
+  return [self initWithWriter:nil];
+}
+
+// Designated initializer
+- (instancetype)initWithWriter:(GRXWriter *)writer {
+  if (!writer) {
+    [NSException raise:NSInvalidArgumentException format:@"writer can't be nil."];
+  }
+  if ((self = [super init])) {
+    _writer = writer;
+  }
+  return self;
+}
+
+// This is used to send a completion or an error to the writeable. It nillifies
+// our reference to it in order to guarantee no more messages are sent to it,
+// and to release it.
+- (void)finishOutputWithError:(NSError *)errorOrNil {
+  id<GRXWriteable> writeable = _writeable;
+  _writeable = nil;
+  [writeable writesFinishedWithError:errorOrNil];
+}
+
+// This is used to stop the input writer. It nillifies our reference to it
+// to release it.
+- (void)finishInput {
+  GRXWriter *writer = _writer;
+  _writer = nil;
+  writer.state = GRXWriterStateFinished;
+}
+
+#pragma mark GRXWriteable implementation
+
+- (void)writeValue:(id)value {
+  [_writeable writeValue:value];
+}
+
+- (void)writesFinishedWithError:(NSError *)errorOrNil {
+  _writer = nil;
+  [self finishOutputWithError:errorOrNil];
+}
+
+#pragma mark GRXWriter implementation
+
+- (GRXWriterState)state {
+  return _writer ? _writer.state : GRXWriterStateFinished;
+}
+
+- (void)setState:(GRXWriterState)state {
+  if (state == GRXWriterStateFinished) {
+    _writeable = nil;
+    [self finishInput];
+  } else {
+    _writer.state = state;
+  }
+}
+
+- (void)startWithWriteable:(id<GRXWriteable>)writeable {
+  _writeable = writeable;
+  [_writer startWithWriteable:self];
+}
+
+- (void)finishWithError:(NSError *)errorOrNil {
+  [self finishOutputWithError:errorOrNil];
+  [self finishInput];
+}
+
+@end
diff --git a/src/objective-c/RxLibrary/GRXImmediateWriter.h b/src/objective-c/RxLibrary/GRXImmediateWriter.h
index f86d38d..b171f0c 100644
--- a/src/objective-c/RxLibrary/GRXImmediateWriter.h
+++ b/src/objective-c/RxLibrary/GRXImmediateWriter.h
@@ -40,15 +40,15 @@
 //
 // Unless the writeable callback pauses them or stops them early, these writers will do all their
 // interactions with the writeable before the start method returns.
-@interface GRXImmediateWriter : NSObject<GRXWriter>
+@interface GRXImmediateWriter : GRXWriter
 
 // Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to
 // its writeable. The NSEnumerator is released when it finishes.
-+ (id<GRXWriter>)writerWithEnumerator:(NSEnumerator *)enumerator;
++ (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator;
 
 // Returns a writer that pushes to its writeable the successive values returned by the passed
 // block. When the block first returns nil, it is released.
-+ (id<GRXWriter>)writerWithValueSupplier:(id (^)())block;
++ (GRXWriter *)writerWithValueSupplier:(id (^)())block;
 
 // Returns a writer that iterates over the values of the passed container and pushes them to
 // its writeable. The container is released when the iteration is over.
@@ -56,18 +56,18 @@
 // Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to
 // call one method per element. Because GRXWriteable instances accept values one by one, that speed
 // gain doesn't happen here.
-+ (id<GRXWriter>)writerWithContainer:(id<NSFastEnumeration>)container;
++ (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container;
 
 // Returns a writer that sends the passed value to its writeable and then finishes (releasing the
 // value).
-+ (id<GRXWriter>)writerWithValue:(id)value;
++ (GRXWriter *)writerWithValue:(id)value;
 
 // Returns a writer that, as part of its start method, sends the passed error to the writeable
 // (then releasing the error).
-+ (id<GRXWriter>)writerWithError:(NSError *)error;
++ (GRXWriter *)writerWithError:(NSError *)error;
 
 // Returns a writer that, as part of its start method, finishes immediately without sending any
 // values to its writeable.
-+ (id<GRXWriter>)emptyWriter;
++ (GRXWriter *)emptyWriter;
 
 @end
diff --git a/src/objective-c/RxLibrary/GRXImmediateWriter.m b/src/objective-c/RxLibrary/GRXImmediateWriter.m
index 0b49798..3edae78 100644
--- a/src/objective-c/RxLibrary/GRXImmediateWriter.m
+++ b/src/objective-c/RxLibrary/GRXImmediateWriter.m
@@ -63,41 +63,28 @@
   return [[self alloc] initWithEnumerator:enumerator error:errorOrNil];
 }
 
-+ (id<GRXWriter>)writerWithEnumerator:(NSEnumerator *)enumerator {
++ (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator {
   return [self writerWithEnumerator:enumerator error:nil];
 }
 
-+ (id<GRXWriter>)writerWithValueSupplier:(id (^)())block {
++ (GRXWriter *)writerWithValueSupplier:(id (^)())block {
   return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithValueSupplier:block]];
 }
 
-+ (id<GRXWriter>)writerWithContainer:(id<NSFastEnumeration>)container {
++ (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container {
   return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithContainer:container]];;
 }
 
-+ (id<GRXWriter>)writerWithValue:(id)value {
-  if (value) {
-    return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithSingleValue:value]];
-  } else {
-    return [self emptyWriter];
-  }
++ (GRXWriter *)writerWithValue:(id)value {
+  return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithSingleValue:value]];
 }
 
-+ (id<GRXWriter>)writerWithError:(NSError *)error {
-  if (error) {
-    return [self writerWithEnumerator:nil error:error];
-  } else {
-    return [self emptyWriter];
-  }
++ (GRXWriter *)writerWithError:(NSError *)error {
+  return [self writerWithEnumerator:nil error:error];
 }
 
-+ (id<GRXWriter>)emptyWriter {
-  static GRXImmediateWriter *emptyWriter;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    emptyWriter = [self writerWithEnumerator:nil error:nil];
-  });
-  return emptyWriter;
++ (GRXWriter *)emptyWriter {
+  return [self writerWithEnumerator:nil error:nil];
 }
 
 #pragma mark Conformance with GRXWriter
diff --git a/src/objective-c/RxLibrary/GRXWriter+Immediate.m b/src/objective-c/RxLibrary/GRXWriter+Immediate.m
index 39c54f8..1d55eb3 100644
--- a/src/objective-c/RxLibrary/GRXWriter+Immediate.m
+++ b/src/objective-c/RxLibrary/GRXWriter+Immediate.m
@@ -38,27 +38,27 @@
 @implementation GRXWriter (Immediate)
 
 + (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator {
-  return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithEnumerator:enumerator]];
+  return [GRXImmediateWriter writerWithEnumerator:enumerator];
 }
 
 + (instancetype)writerWithValueSupplier:(id (^)())block {
-  return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithValueSupplier:block]];
+  return [GRXImmediateWriter writerWithValueSupplier:block];
 }
 
 + (instancetype)writerWithContainer:(id<NSFastEnumeration>)container {
-  return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithContainer:container]];
+  return [GRXImmediateWriter writerWithContainer:container];
 }
 
 + (instancetype)writerWithValue:(id)value {
-  return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithValue:value]];
+  return [GRXImmediateWriter writerWithValue:value];
 }
 
 + (instancetype)writerWithError:(NSError *)error {
-  return [[self alloc] initWithWriter:[GRXImmediateWriter writerWithError:error]];
+  return [GRXImmediateWriter writerWithError:error];
 }
 
 + (instancetype)emptyWriter {
-  return [[self alloc] initWithWriter:[GRXImmediateWriter emptyWriter]];
+  return [GRXImmediateWriter emptyWriter];
 }
 
 @end
diff --git a/src/objective-c/RxLibrary/GRXWriter.h b/src/objective-c/RxLibrary/GRXWriter.h
index dcf44e3..5d6e1a4 100644
--- a/src/objective-c/RxLibrary/GRXWriter.h
+++ b/src/objective-c/RxLibrary/GRXWriter.h
@@ -85,7 +85,7 @@
 // Unless otherwise indicated by a conforming class, no messages should be sent
 // concurrently to a GRXWriter. I.e., conforming classes aren't required to
 // be thread-safe.
-@protocol GRXWriter <NSObject>
+@interface GRXWriter : NSObject
 
 // This property can be used to query the current state of the writer, which
 // determines how it might currently use its writeable. Some state transitions can
@@ -116,12 +116,3 @@
 // can't remember the details in the presence of concurrency.
 - (void)finishWithError:(NSError *)errorOrNil;
 @end
-
-// A "proxy" class that simply forwards values, completion, and errors from its
-// input writer to its writeable.
-// It is useful as a superclass for pipes that act as a transformation of their
-// input writer, and for classes that represent objects with input and
-// output sequences of values, like an RPC.
-@interface GRXWriter : NSObject<GRXWriter>
-- (instancetype)initWithWriter:(id<GRXWriter>)writer NS_DESIGNATED_INITIALIZER;
-@end
diff --git a/src/objective-c/RxLibrary/GRXWriter.m b/src/objective-c/RxLibrary/GRXWriter.m
index cc14383..019fcbd 100644
--- a/src/objective-c/RxLibrary/GRXWriter.m
+++ b/src/objective-c/RxLibrary/GRXWriter.m
@@ -33,80 +33,6 @@
 
 #import "GRXWriter.h"
 
-@interface GRXWriter () <GRXWriteable>
-@end
-
-@implementation GRXWriter {
-  id<GRXWriter> _writer;
-  id<GRXWriteable> _writeable;
-}
-
-- (instancetype)init {
-  return [self initWithWriter:nil];
-}
-
-// Designated initializer
-- (instancetype)initWithWriter:(id<GRXWriter>)writer {
-  if (!writer) {
-    [NSException raise:NSInvalidArgumentException format:@"writer can't be nil."];
-  }
-  if ((self = [super init])) {
-    _writer = writer;
-  }
-  return self;
-}
-
-// This is used to send a completion or an error to the writeable. It nillifies
-// our reference to it in order to guarantee no more messages are sent to it,
-// and to release it.
-- (void)finishOutputWithError:(NSError *)errorOrNil {
-  id<GRXWriteable> writeable = _writeable;
-  _writeable = nil;
-  [writeable writesFinishedWithError:errorOrNil];
-}
-
-// This is used to stop the input writer. It nillifies our reference to it
-// to release it.
-- (void)finishInput {
-  id<GRXWriter> writer = _writer;
-  _writer = nil;
-  writer.state = GRXWriterStateFinished;
-}
-
-#pragma mark GRXWriteable implementation
-
-- (void)writeValue:(id)value {
-  [_writeable writeValue:value];
-}
-
-- (void)writesFinishedWithError:(NSError *)errorOrNil {
-  _writer = nil;
-  [self finishOutputWithError:errorOrNil];
-}
-
-#pragma mark GRXWriter implementation
-
-- (GRXWriterState)state {
-  return _writer ? _writer.state : GRXWriterStateFinished;
-}
-
-- (void)setState:(GRXWriterState)state {
-  if (state == GRXWriterStateFinished) {
-    _writeable = nil;
-    [self finishInput];
-  } else {
-    _writer.state = state;
-  }
-}
-
-- (void)startWithWriteable:(id<GRXWriteable>)writeable {
-  _writeable = writeable;
-  [_writer startWithWriteable:self];
-}
-
-- (void)finishWithError:(NSError *)errorOrNil {
-  [self finishOutputWithError:errorOrNil];
-  [self finishInput];
-}
+@implementation GRXWriter
 
 @end
diff --git a/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.m b/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.m
index 2050fa9..0387c99 100644
--- a/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.m
+++ b/src/objective-c/RxLibrary/private/GRXNSFastEnumerator.m
@@ -59,7 +59,6 @@
 
 // Designated initializer.
 - (instancetype)initWithContainer:(id<NSFastEnumeration>)container {
-  NSAssert(container, @"container can't be nil");
   if ((self = [super init])) {
     _container = container;
   }
diff --git a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h
index dcebb61..43b8706 100644
--- a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h
+++ b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.h
@@ -31,10 +31,10 @@
  *
  */
 
-#import "GRXWriter.h"
+#import "RxLibrary/GRXForwardingWriter.h"
 
 // A "proxy" writer that transforms all the values of its input writer by using a mapping function.
-@interface GRXMappingWriter : GRXWriter
-- (instancetype)initWithWriter:(id<GRXWriter>)writer map:(id (^)(id value))map
+@interface GRXMappingWriter : GRXForwardingWriter
+- (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map
     NS_DESIGNATED_INITIALIZER;
 @end
diff --git a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
index 2cdfea1..f3242e4 100644
--- a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
+++ b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
@@ -37,19 +37,19 @@
   return value;
 };
 
-@interface GRXWriter () <GRXWriteable>
+@interface GRXForwardingWriter () <GRXWriteable>
 @end
 
 @implementation GRXMappingWriter {
   id (^_map)(id value);
 }
 
-- (instancetype)initWithWriter:(id<GRXWriter>)writer {
+- (instancetype)initWithWriter:(GRXWriter *)writer {
   return [self initWithWriter:writer map:nil];
 }
 
 // Designated initializer
-- (instancetype)initWithWriter:(id<GRXWriter>)writer map:(id (^)(id value))map {
+- (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map {
   if ((self = [super initWithWriter:writer])) {
     _map = map ?: kIdentity;
   }
diff --git a/src/objective-c/examples/Sample/Sample/ViewController.m b/src/objective-c/examples/Sample/Sample/ViewController.m
index 0011a45..05bd6fa 100644
--- a/src/objective-c/examples/Sample/Sample/ViewController.m
+++ b/src/objective-c/examples/Sample/Sample/ViewController.m
@@ -33,12 +33,12 @@
 
 #import "ViewController.h"
 
-#import <gRPC/GRPCCall.h>
-#import <gRPC/GRPCMethodName.h>
-#import <gRPC/GRXWriter+Immediate.h>
-#import <gRPC/GRXWriteable.h>
+#import <GRPCClient/GRPCCall.h>
+#import <GRPCClient/GRPCMethodName.h>
 #import <RemoteTest/Messages.pbobjc.h>
 #import <RemoteTest/Test.pbrpc.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
+#import <RxLibrary/GRXWriteable.h>
 
 @implementation ViewController
 
diff --git a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec b/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec
index dd0dab3..7cc9a04 100644
--- a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec
@@ -7,7 +7,13 @@
   s.osx.deployment_target = "10.8"
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.prepare_command = "protoc --objc_out=. --objcgrpc_out=. *.proto"
+  s.prepare_command = <<-CMD
+    cd ../../../..
+    # TODO(jcanizales): Make only Objective-C plugin.
+    make plugins
+    cd -
+    protoc --plugin=protoc-gen-grpc=../../../../bins/opt/grpc_objective_c_plugin --objc_out=. --grpc_out=. *.proto
+  CMD
 
   s.subspec "Messages" do |ms|
     ms.source_files = "*.pbobjc.{h,m}"
diff --git a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec b/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec
index e26e62f..0e8dacd 100644
--- a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec
+++ b/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec
@@ -7,7 +7,13 @@
   s.osx.deployment_target = "10.8"
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.prepare_command = "protoc --objc_out=. --objcgrpc_out=. *.proto"
+  s.prepare_command = <<-CMD
+    cd ../../../..
+    # TODO(jcanizales): Make only Objective-C plugin.
+    make plugins
+    cd -
+    protoc --plugin=protoc-gen-grpc=../../../../bins/opt/grpc_objective_c_plugin --objc_out=. --grpc_out=. *.proto
+  CMD
 
   s.subspec "Messages" do |ms|
     ms.source_files = "*.pbobjc.{h,m}"
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index 268e67a..3210ad7 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -34,11 +34,11 @@
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
-#import <gRPC/GRPCCall.h>
-#import <gRPC/GRPCMethodName.h>
-#import <gRPC/GRXWriter+Immediate.h>
-#import <gRPC/GRXWriteable.h>
+#import <GRPCClient/GRPCCall.h>
+#import <ProtoRPC/ProtoMethod.h>
 #import <RemoteTest/Messages.pbobjc.h>
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
 
 // These are a few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall)
 // rather than a generated proto library on top of it.
@@ -47,9 +47,9 @@
 static NSString * const kPackage = @"grpc.testing";
 static NSString * const kService = @"TestService";
 
-static GRPCMethodName *kInexistentMethod;
-static GRPCMethodName *kEmptyCallMethod;
-static GRPCMethodName *kUnaryCallMethod;
+static ProtoMethod *kInexistentMethod;
+static ProtoMethod *kEmptyCallMethod;
+static ProtoMethod *kUnaryCallMethod;
 
 @interface GRPCClientTests : XCTestCase
 @end
@@ -58,22 +58,22 @@
 
 - (void)setUp {
   // This method isn't implemented by the remote server.
-  kInexistentMethod = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                    interface:kService
-                                                       method:@"Inexistent"];
-  kEmptyCallMethod = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                   interface:kService
-                                                      method:@"EmptyCall"];
-  kUnaryCallMethod = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                   interface:kService
-                                                      method:@"UnaryCall"];
+  kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                   service:kService
+                                                    method:@"Inexistent"];
+  kEmptyCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                  service:kService
+                                                   method:@"EmptyCall"];
+  kUnaryCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                  service:kService
+                                                   method:@"UnaryCall"];
 }
 
 - (void)testConnectionToRemoteServer {
   __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kInexistentMethod
+                                             path:kInexistentMethod.HTTPPath
                                    requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -87,7 +87,7 @@
 
   [call startWithWriteable:responsesWriteable];
 
-  [self waitForExpectationsWithTimeout:2. handler:nil];
+  [self waitForExpectationsWithTimeout:4 handler:nil];
 }
 
 - (void)testEmptyRPC {
@@ -95,7 +95,7 @@
   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kEmptyCallMethod
+                                             path:kEmptyCallMethod.HTTPPath
                                    requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -109,7 +109,7 @@
 
   [call startWithWriteable:responsesWriteable];
 
-  [self waitForExpectationsWithTimeout:2. handler:nil];
+  [self waitForExpectationsWithTimeout:4 handler:nil];
 }
 
 - (void)testSimpleProtoRPC {
@@ -120,10 +120,10 @@
   request.responseSize = 100;
   request.fillUsername = YES;
   request.fillOauthScope = YES;
-  id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
+  GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kUnaryCallMethod
+                                             path:kUnaryCallMethod.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -141,7 +141,7 @@
 
   [call startWithWriteable:responsesWriteable];
 
-  [self waitForExpectationsWithTimeout:2. handler:nil];
+  [self waitForExpectationsWithTimeout:4 handler:nil];
 }
 
 - (void)testMetadata {
@@ -150,10 +150,10 @@
   RMTSimpleRequest *request = [RMTSimpleRequest message];
   request.fillUsername = YES;
   request.fillOauthScope = YES;
-  id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
+  GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kUnaryCallMethod
+                                             path:kUnaryCallMethod.HTTPPath
                                    requestsWriter:requestsWriter];
 
   call.requestMetadata[@"Authorization"] = @"Bearer bogusToken";
@@ -173,7 +173,7 @@
 
   [call startWithWriteable:responsesWriteable];
 
-  [self waitForExpectationsWithTimeout:2. handler:nil];
+  [self waitForExpectationsWithTimeout:4 handler:nil];
 }
 
 @end
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 0a512c1..501f333 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -36,13 +36,13 @@
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
-#import <gRPC/GRXWriter+Immediate.h>
-#import <gRPC/GRXBufferedPipe.h>
-#import <gRPC/ProtoRPC.h>
+#import <ProtoRPC/ProtoRPC.h>
 #import <RemoteTest/Empty.pbobjc.h>
 #import <RemoteTest/Messages.pbobjc.h>
 #import <RemoteTest/Test.pbobjc.h>
 #import <RemoteTest/Test.pbrpc.h>
+#import <RxLibrary/GRXBufferedPipe.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
 
 // Convenience constructors for the generated proto messages:
 
@@ -103,7 +103,7 @@
     [expectation fulfill];
   }];
 
-  [self waitForExpectationsWithTimeout:2 handler:nil];
+  [self waitForExpectationsWithTimeout:4 handler:nil];
 }
 
 - (void)testLargeUnaryRPC {
@@ -125,7 +125,7 @@
     [expectation fulfill];
   }];
 
-  [self waitForExpectationsWithTimeout:4 handler:nil];
+  [self waitForExpectationsWithTimeout:8 handler:nil];
 }
 
 - (void)testClientStreamingRPC {
@@ -143,7 +143,7 @@
   RMTStreamingInputCallRequest *request4 = [RMTStreamingInputCallRequest message];
   request4.payload.body = [NSMutableData dataWithLength:45904];
 
-  id<GRXWriter> writer = [GRXWriter writerWithContainer:@[request1, request2, request3, request4]];
+  GRXWriter *writer = [GRXWriter writerWithContainer:@[request1, request2, request3, request4]];
 
   [_service streamingInputCallWithRequestsWriter:writer
                                          handler:^(RMTStreamingInputCallResponse *response,
@@ -157,7 +157,7 @@
     [expectation fulfill];
   }];
 
-  [self waitForExpectationsWithTimeout:4 handler:nil];
+  [self waitForExpectationsWithTimeout:8 handler:nil];
 }
 
 - (void)testServerStreamingRPC {
@@ -174,7 +174,7 @@
 
   __block int index = 0;
   [_service streamingOutputCallWithRequest:request
-                                   handler:^(BOOL done,
+                              eventHandler:^(BOOL done,
                                              RMTStreamingOutputCallResponse *response,
                                              NSError *error){
     XCTAssertNil(error, @"Finished with unexpected error: %@", error);
@@ -193,7 +193,7 @@
     }
   }];
 
-  [self waitForExpectationsWithTimeout:4 handler:nil];
+  [self waitForExpectationsWithTimeout:8 handler:nil];
 }
 
 - (void)testPingPongRPC {
@@ -211,7 +211,7 @@
   [requestsBuffer writeValue:request];
 
   [_service fullDuplexCallWithRequestsWriter:requestsBuffer
-                                     handler:^(BOOL done,
+                                eventHandler:^(BOOL done,
                                                RMTStreamingOutputCallResponse *response,
                                                NSError *error) {
     XCTAssertNil(error, @"Finished with unexpected error: %@", error);
@@ -236,13 +236,13 @@
       [expectation fulfill];
     }
   }];
-  [self waitForExpectationsWithTimeout:2 handler:nil];
+  [self waitForExpectationsWithTimeout:4 handler:nil];
 }
 
 - (void)testEmptyStreamRPC {
   __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"];
   [_service fullDuplexCallWithRequestsWriter:[GRXWriter emptyWriter]
-                                     handler:^(BOOL done,
+                                eventHandler:^(BOOL done,
                                                RMTStreamingOutputCallResponse *response,
                                                NSError *error) {
     XCTAssertNil(error, @"Finished with unexpected error: %@", error);
@@ -282,10 +282,11 @@
   
   [requestsBuffer writeValue:request];
   
-  __block ProtoRPC *call = [_service RPCToFullDuplexCallWithRequestsWriter:requestsBuffer
-                                                                   handler:^(BOOL done,
-                                                                             RMTStreamingOutputCallResponse *response,
-                                                                             NSError *error) {
+  __block ProtoRPC *call =
+      [_service RPCToFullDuplexCallWithRequestsWriter:requestsBuffer
+                                         eventHandler:^(BOOL done,
+                                                        RMTStreamingOutputCallResponse *response,
+                                                        NSError *error) {
     if (receivedResponse) {
       XCTAssert(done, @"Unexpected extra response %@", response);
       XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
@@ -299,7 +300,7 @@
     }
   }];
   [call start];
-  [self waitForExpectationsWithTimeout:4 handler:nil];
+  [self waitForExpectationsWithTimeout:8 handler:nil];
 }
 
 @end
diff --git a/src/objective-c/tests/LocalClearTextTests.m b/src/objective-c/tests/LocalClearTextTests.m
index 68ffd23..4317614 100644
--- a/src/objective-c/tests/LocalClearTextTests.m
+++ b/src/objective-c/tests/LocalClearTextTests.m
@@ -34,12 +34,12 @@
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
-#import <gRPC/GRPCCall.h>
-#import <gRPC/GRPCMethodName.h>
-#import <gRPC/GRXWriter+Immediate.h>
-#import <gRPC/GRXWriteable.h>
+#import <GRPCClient/GRPCCall.h>
+#import <ProtoRPC/ProtoMethod.h>
 #import <RouteGuide/RouteGuide.pbobjc.h>
 #import <RouteGuide/RouteGuide.pbrpc.h>
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
 
 // These tests require a gRPC "RouteGuide" sample server to be running locally. You can compile and
 // run one by following the instructions here: https://github.com/grpc/grpc-common/blob/master/cpp/cpptutorial.md#try-it-out
@@ -64,7 +64,7 @@
 //                                                         interface:kService
 //                                                            method:@"EmptyCall"];
 //
-//  id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[NSData data]];
+//  GRXWriter *requestsWriter = [GRXWriter writerWithValue:[NSData data]];
 //
 //  GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost
 //                                           method:method
@@ -87,14 +87,14 @@
   __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
 
-  GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                         interface:kService
-                                                            method:@"RecordRoute"];
+  ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                     service:kService
+                                                      method:@"RecordRoute"];
 
-  id<GRXWriter> requestsWriter = [GRXWriter emptyWriter];
+  GRXWriter *requestsWriter = [GRXWriter emptyWriter];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost
-                                           method:method
+                                             path:method.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -115,17 +115,17 @@
   __weak XCTestExpectation *response = [self expectationWithDescription:@"Response received."];
   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-  GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                         interface:kService
-                                                            method:@"GetFeature"];
+  ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                     service:kService
+                                                      method:@"GetFeature"];
 
   RGDPoint *point = [RGDPoint message];
   point.latitude = 28E7;
   point.longitude = -15E7;
-  id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[point data]];
+  GRXWriter *requestsWriter = [GRXWriter writerWithValue:[point data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost
-                                           method:method
+                                             path:method.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 026868d..2aa837f 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -1,6 +1,7 @@
 source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
+pod 'Protobuf', :path => "../../../third_party/protobuf"
 pod 'gRPC', :path => "../../.."
 pod 'RemoteTest', :path => "../generated_libraries/RemoteTestClient"
 pod 'RouteGuide', :path => "../generated_libraries/RouteGuideClient"
diff --git a/src/objective-c/tests/RxLibraryUnitTests.m b/src/objective-c/tests/RxLibraryUnitTests.m
index 89984d9..5e31628 100644
--- a/src/objective-c/tests/RxLibraryUnitTests.m
+++ b/src/objective-c/tests/RxLibraryUnitTests.m
@@ -34,9 +34,9 @@
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
-#import <gRPC/GRXBufferedPipe.h>
-#import <gRPC/GRXWriter.h>
-#import <gRPC/GRXWriteable.h>
+#import <RxLibrary/GRXBufferedPipe.h>
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter.h>
 
 // A mock of a GRXSingleValueHandler block that can be queried for how many times it was called and
 // what were the last values passed to it.
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index 34be705..f13fb82 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -391,7 +391,6 @@
 		635697DC1B14FC11007A7283 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				OTHER_LDFLAGS = "-ObjC";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 			};
@@ -400,7 +399,6 @@
 		635697DD1B14FC11007A7283 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				OTHER_LDFLAGS = "-ObjC";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 			};
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
new file mode 100644
index 0000000..3a6e2c3
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0630"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "63423F431B150A5F006CF63C"
+               BuildableName = "AllTests.xctest"
+               BlueprintName = "AllTests"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "63423F431B150A5F006CF63C"
+               BuildableName = "AllTests.xctest"
+               BlueprintName = "AllTests"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+            <SkippedTests>
+               <Test
+                  Identifier = "LocalClearTextTests">
+               </Test>
+               <Test
+                  Identifier = "LocalClearTextTests/testConnectionToLocalServer">
+               </Test>
+            </SkippedTests>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "63423F431B150A5F006CF63C"
+            BuildableName = "AllTests.xctest"
+            BlueprintName = "AllTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "63423F431B150A5F006CF63C"
+            BuildableName = "AllTests.xctest"
+            BlueprintName = "AllTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "63423F431B150A5F006CF63C"
+            BuildableName = "AllTests.xctest"
+            BlueprintName = "AllTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
new file mode 100755
index 0000000..37fced3
--- /dev/null
+++ b/src/objective-c/tests/run_tests.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+cd $(dirname $0)
+
+# TODO(jcanizales): Remove when Cocoapods issue #3823 is resolved.
+export COCOAPODS_DISABLE_DETERMINISTIC_UUIDS=YES
+pod install
+
+# xcodebuild is very verbose. We filter its output and tell Bash to fail if any
+# element of the pipe fails.
+# TODO(jcanizales): Use xctool instead? Issue #2540.
+set -o pipefail
+XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail)'
+xcodebuild \
+    -workspace Tests.xcworkspace \
+    -scheme AllTests \
+    -destination name="iPhone 6" \
+    test \
+    | egrep "$XCODEBUILD_FILTER" -
diff --git a/src/php/README.md b/src/php/README.md
index 42ddb2d..1804606 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -5,14 +5,27 @@
 
 #Status
 
-Pre-Alpha : This gRPC PHP implementation is work-in-progress and is not expected to work yet.
+Alpha : Ready for early adopters
 
 ## ENVIRONMENT
 
-Prerequisite: PHP 5.5 or later, PHPUnit, pecl
+Prerequisite: PHP 5.5 or later, `phpunit`, `pecl`
+
+Linux:
 
 ```sh
-sudo apt-get install php5 php5-dev phpunit php-pear
+$ sudo apt-get install php5 php5-dev phpunit php-pear
+```
+
+OS X:
+
+```sh
+$ curl https://phar.phpunit.de/phpunit.phar -o phpunit.phar
+$ chmod +x phpunit.phar
+$ sudo mv phpunit.phar /usr/local/bin/phpunit
+
+$ curl -O http://pear.php.net/go-pear.phar
+$ sudo php -d detect_unicode=0 go-pear.phar
 ```
 
 ## Build from Homebrew
diff --git a/src/php/bin/determine_extension_dir.sh b/src/php/bin/determine_extension_dir.sh
new file mode 100755
index 0000000..b4342ac
--- /dev/null
+++ b/src/php/bin/determine_extension_dir.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+# 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.
+set -e
+default_extension_dir=$(php-config --extension-dir)
+if command -v brew > /dev/null && \
+   brew ls --versions | grep php5[56]-grpc > /dev/null; then
+  # the grpc php extension was installed by homebrew
+  :
+elif [ ! -e $default_extension_dir/grpc.so ]; then
+  # the grpc extension is not found in the default PHP extension dir
+  # try the source modules directory
+  module_dir=../ext/grpc/modules
+  if [ ! -e $module_dir/grpc.so ]; then
+    echo "Please run 'phpize && ./configure && make' from ext/grpc first"
+    exit 1
+  fi
+  # sym-link in system supplied extensions
+  for f in $default_extension_dir/*.so; do
+    ln -s $f $module_dir/$(basename $f) &> /dev/null || true
+  done
+  extension_dir="-d extension_dir=${module_dir} -d extension=grpc.so"
+else
+  extension_dir="-d extension=grpc.so"
+fi
diff --git a/src/php/bin/interop_client.sh b/src/php/bin/interop_client.sh
index 4fe6378..17b888d 100755
--- a/src/php/bin/interop_client.sh
+++ b/src/php/bin/interop_client.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +28,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
-set +e
+set -e
 cd $(dirname $0)
-
-module_dir=../ext/grpc/modules
-
-php -d extension_dir=$module_dir -d extension=grpc.so \
+source ./determine_extension_dir.sh
+php $extension_dir \
   ../tests/interop/interop_client.php $@ 1>&2
diff --git a/src/php/bin/run_gen_code_test.sh b/src/php/bin/run_gen_code_test.sh
index 1be2ed3..6e56c72 100755
--- a/src/php/bin/run_gen_code_test.sh
+++ b/src/php/bin/run_gen_code_test.sh
@@ -1,4 +1,4 @@
-# Runs the generated code test against the ruby server
+#!/bin/bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -28,10 +28,11 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+set -e
 cd $(dirname $0)
-GRPC_TEST_HOST=localhost:50051 php -d extension_dir=../ext/grpc/modules/ \
-  -d extension=grpc.so `which phpunit` -v --debug --strict \
+source ./determine_extension_dir.sh
+export GRPC_TEST_HOST=localhost:50051
+php $extension_dir $(which phpunit) -v --debug --strict \
   ../tests/generated_code/GeneratedCodeTest.php
-GRPC_TEST_HOST=localhost:50051 php -d extension_dir=../ext/grpc/modules/ \
-  -d extension=grpc.so `which phpunit` -v --debug --strict \
+php $extension_dir $(which phpunit) -v --debug --strict \
   ../tests/generated_code/GeneratedCodeWithCallbackTest.php
diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh
index 422757b..953f408 100755
--- a/src/php/bin/run_tests.sh
+++ b/src/php/bin/run_tests.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -32,33 +32,6 @@
 # against it
 set -e
 cd $(dirname $0)
-default_extension_dir=`php -i | grep extension_dir | sed 's/.*=> //g'`
-
-if command -v brew >/dev/null && [ -d `brew --prefix`/opt/grpc-php ]
-then
-  # homebrew and the grpc-php formula are installed
-  extension_dir="-d extension_dir="`brew --prefix`/opt/grpc-php
-elif [ ! -e $default_extension_dir/grpc.so ]
-then
-  # the grpc extension is not found in the default PHP extension dir
-  # try the source modules directory
-  module_dir=../ext/grpc/modules
-  if [ ! -d $module_dir ]
-  then
-    echo "Please run 'phpize && ./configure && make' from ext/grpc first"
-    exit 1
-  fi
-
-  # sym-link in system supplied extensions
-  for f in $default_extension_dir/*.so
-  do
-    ln -s $f $module_dir/$(basename $f) &> /dev/null || true
-  done
-
-  extension_dir='-d extension_dir='$module_dir
-fi
-
-php \
-  $extension_dir \
-  -d extension=grpc.so \
-  `which phpunit` -v --debug --strict ../tests/unit_tests
+source ./determine_extension_dir.sh
+php $extension_dir $(which phpunit) -v --debug --strict \
+  ../tests/unit_tests
diff --git a/src/php/ext/grpc/README.md b/src/php/ext/grpc/README.md
index 0ac09e1..88d2c48 100644
--- a/src/php/ext/grpc/README.md
+++ b/src/php/ext/grpc/README.md
@@ -4,7 +4,7 @@
 # Requirements
 
  * PHP 5.5+
- * [gRPC core library](https://github.com/grpc/grpc) 0.9.1
+ * [gRPC core library](https://github.com/grpc/grpc) 0.10.0
 
 # Installation
 
@@ -55,7 +55,7 @@
 Note: before a stable release, you may need to do
 
 ```sh
-$ sudo pecl install grpc-0.5.0
+$ sudo pecl install grpc-0.5.1
 ```
 
 OR
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 10a4946..b67bae7 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -408,7 +408,7 @@
     goto cleanup;
   }
   event = grpc_completion_queue_pluck(completion_queue, call->wrapped,
-                                      gpr_inf_future);
+                                      gpr_inf_future(GPR_CLOCK_REALTIME));
   if (!event.success) {
     zend_throw_exception(spl_ce_LogicException,
                          "The batch failed for some reason",
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
index b24c837..c653a59 100644
--- a/src/php/ext/grpc/completion_queue.c
+++ b/src/php/ext/grpc/completion_queue.c
@@ -43,8 +43,9 @@
 
 void grpc_php_shutdown_completion_queue(TSRMLS_D) {
   grpc_completion_queue_shutdown(completion_queue);
-  while (grpc_completion_queue_next(completion_queue, gpr_inf_future).type !=
-         GRPC_QUEUE_SHUTDOWN)
+  while (grpc_completion_queue_next(completion_queue,
+                                    gpr_inf_future(GPR_CLOCK_REALTIME))
+             .type != GRPC_QUEUE_SHUTDOWN)
     ;
   grpc_completion_queue_destroy(completion_queue);
 }
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index b485aab..8bacdfb 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -35,8 +35,13 @@
   PHP_ADD_LIBRARY(dl,,GRPC_SHARED_LIBADD)
   PHP_ADD_LIBRARY(dl)
 
-  PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD)
-  PHP_ADD_LIBRARY(rt)
+  case $host in
+    *darwin*) ;;
+    *)
+      PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD)
+      PHP_ADD_LIBRARY(rt)
+      ;;
+  esac
 
   GRPC_LIBDIR=$GRPC_DIR/${GRPC_LIB_SUBDIR-lib}
 
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index 2c89829..bc2a059 100644
--- a/src/php/ext/grpc/package.xml
+++ b/src/php/ext/grpc/package.xml
@@ -10,11 +10,11 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2015-06-16</date>
- <time>20:12:55</time>
+ <date>2015-07-09</date>
+ <time>21:47:27</time>
  <version>
-  <release>0.5.0</release>
-  <api>0.5.0</api>
+  <release>0.5.1</release>
+  <api>0.5.1</api>
  </version>
  <stability>
   <release>alpha</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-First alpha release
+Update to wrap gRPC C Core version 0.10.0
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -34,15 +34,15 @@
    <file baseinstalldir="/" md5sum="f1b66029daeced20b47cf00cc6523fc8" name="channel.h" role="src" />
    <file baseinstalldir="/" md5sum="81a1193e93d8b6602add8ac360de565b" name="completion_queue.c" role="src" />
    <file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
-   <file baseinstalldir="/" md5sum="a9181ed994a072ac5f41e7c9705c170f" name="config.m4" role="src" />
+   <file baseinstalldir="/" md5sum="a22f8eac0164761058cc4d9eb2ceb069" name="config.m4" role="src" />
    <file baseinstalldir="/" md5sum="8c3f1e11dac623001378bfd53b554f08" name="credentials.c" role="src" />
    <file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" />
    <file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
    <file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" />
    <file baseinstalldir="/" md5sum="6aaa7a290122d230f2d8c4e4e05da4a9" name="php_grpc.c" role="src" />
    <file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
-   <file baseinstalldir="/" md5sum="4d4d3382f8d10cae2e4378468e5516b9" name="README.md" role="doc" />
-   <file baseinstalldir="/" md5sum="53fda0ee6937f6ddc8e271886018d441" name="server.c" role="src" />
+   <file baseinstalldir="/" md5sum="c1d0b42fd77b7d6740bf7744bee90af5" name="README.md" role="doc" />
+   <file baseinstalldir="/" md5sum="30997dd423403e1f8ad09dcee598e5c4" name="server.c" role="src" />
    <file baseinstalldir="/" md5sum="4b730f06d14cbbb0642bdbd194749595" name="server.h" role="src" />
    <file baseinstalldir="/" md5sum="f6930beafb6c0e061899262f2f077e98" name="server_credentials.c" role="src" />
    <file baseinstalldir="/" md5sum="9c4b4cc06356a8a39a16a085a9b85996" name="server_credentials.h" role="src" />
@@ -78,5 +78,20 @@
 First alpha release
    </notes>
   </release>
+  <release>
+   <version>
+    <release>0.5.1</release>
+    <api>0.5.1</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2015-07-09</date>
+   <license>BSD</license>
+   <notes>
+Update to wrap gRPC C Core version 0.10.0
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 02c886c..c319526 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -64,7 +64,8 @@
   wrapped_grpc_server *server = (wrapped_grpc_server *)object;
   if (server->wrapped != NULL) {
     grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
-    grpc_completion_queue_pluck(completion_queue, NULL, gpr_inf_future);
+    grpc_completion_queue_pluck(completion_queue, NULL,
+                                gpr_inf_future(GPR_CLOCK_REALTIME));
     grpc_server_destroy(server->wrapped);
   }
   efree(server);
@@ -143,7 +144,8 @@
                          (long)error_code TSRMLS_CC);
     goto cleanup;
   }
-  event = grpc_completion_queue_pluck(completion_queue, NULL, gpr_inf_future);
+  event = grpc_completion_queue_pluck(completion_queue, NULL,
+                                      gpr_inf_future(GPR_CLOCK_REALTIME));
   if (!event.success) {
     zend_throw_exception(spl_ce_LogicException,
                          "Failed to request a call for some reason",
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 8a278d6..4fd069e 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -98,7 +98,7 @@
                          "Timeval expects a long", 1 TSRMLS_CC);
     return;
   }
-  gpr_timespec time = gpr_time_from_micros(microseconds);
+  gpr_timespec time = gpr_time_from_micros(microseconds, GPR_TIMESPAN);
   memcpy(&timeval->wrapped, &time, sizeof(gpr_timespec));
 }
 
@@ -208,7 +208,7 @@
  * @return Timeval The current time
  */
 PHP_METHOD(Timeval, now) {
-  zval *now = grpc_php_wrap_timeval(gpr_now());
+  zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME));
   RETURN_DESTROY_ZVAL(now);
 }
 
@@ -217,7 +217,8 @@
  * @return Timeval Zero length time interval
  */
 PHP_METHOD(Timeval, zero) {
-  zval *grpc_php_timeval_zero = grpc_php_wrap_timeval(gpr_time_0);
+  zval *grpc_php_timeval_zero =
+      grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME));
   RETURN_ZVAL(grpc_php_timeval_zero,
               false, /* Copy original before returning? */
               true /* Destroy original before returning */);
@@ -228,7 +229,8 @@
  * @return Timeval Infinite future time value
  */
 PHP_METHOD(Timeval, infFuture) {
-  zval *grpc_php_timeval_inf_future = grpc_php_wrap_timeval(gpr_inf_future);
+  zval *grpc_php_timeval_inf_future =
+      grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME));
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
 }
 
@@ -237,7 +239,8 @@
  * @return Timeval Infinite past time value
  */
 PHP_METHOD(Timeval, infPast) {
-  zval *grpc_php_timeval_inf_past = grpc_php_wrap_timeval(gpr_inf_past);
+  zval *grpc_php_timeval_inf_past =
+      grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME));
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
 }
 
diff --git a/src/python/interop/setup.py b/src/python/interop/setup.py
index 502fcbe..75012b0 100644
--- a/src/python/interop/setup.py
+++ b/src/python/interop/setup.py
@@ -45,7 +45,7 @@
         'credentials/server1.pem',]
 }
 
-_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.4.0a4']
+_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.10.0a0']
 
 setuptools.setup(
     name='interop',
diff --git a/src/python/src/.gitignore b/src/python/src/.gitignore
index bc15a52..144e501 100644
--- a/src/python/src/.gitignore
+++ b/src/python/src/.gitignore
@@ -1,3 +1,4 @@
 MANIFEST
 grpcio.egg-info/
+build/
 dist/
diff --git a/src/python/src/grpc/_adapter/.gitignore b/src/python/src/grpc/_adapter/.gitignore
new file mode 100644
index 0000000..a6f96cd
--- /dev/null
+++ b/src/python/src/grpc/_adapter/.gitignore
@@ -0,0 +1,5 @@
+*.a
+*.so
+*.dll
+*.pyc
+*.pyd
diff --git a/src/python/src/grpc/_adapter/_c/types.h b/src/python/src/grpc/_adapter/_c/types.h
index e189ae2..3449f06 100644
--- a/src/python/src/grpc/_adapter/_c/types.h
+++ b/src/python/src/grpc/_adapter/_c/types.h
@@ -241,10 +241,10 @@
 gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds);
 
 /* Returns true on success, false on failure. */
-int pygrpc_cast_pylist_to_send_metadata(
-    PyObject *pylist, grpc_metadata **metadata, size_t *count);
+int pygrpc_cast_pyseq_to_send_metadata(
+    PyObject *pyseq, grpc_metadata **metadata, size_t *count);
 /* Returns a metadata array as a Python object on success, else NULL. */
-PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata);
+PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata);
 
 /* Transliterate from a list of python channel arguments (2-tuples of string
    and string|integer|None) to a grpc_channel_args object. The strings placed
diff --git a/src/python/src/grpc/_adapter/_c/types/server.c b/src/python/src/grpc/_adapter/_c/types/server.c
index 26b38da..2a00f34 100644
--- a/src/python/src/grpc/_adapter/_c/types/server.c
+++ b/src/python/src/grpc/_adapter/_c/types/server.c
@@ -105,6 +105,7 @@
   }
   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);
   pygrpc_discard_channel_args(c_args);
   self->cq = cq;
   Py_INCREF(self->cq);
diff --git a/src/python/src/grpc/_adapter/_c/utility.c b/src/python/src/grpc/_adapter/_c/utility.c
index a433f26..000c8d0 100644
--- a/src/python/src/grpc/_adapter/_c/utility.c
+++ b/src/python/src/grpc/_adapter/_c/utility.c
@@ -32,6 +32,7 @@
  */
 
 #include <math.h>
+#include <string.h>
 
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
@@ -118,7 +119,7 @@
           tag->request_call_details.method, tag->request_call_details.host,
           pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline),
           GRPC_OP_RECV_INITIAL_METADATA,
-          pygrpc_cast_metadata_array_to_pylist(tag->request_metadata), Py_None,
+          pygrpc_cast_metadata_array_to_pyseq(tag->request_metadata), Py_None,
           Py_None, Py_None, Py_None,
           event.success ? Py_True : Py_False);
     } else {
@@ -172,7 +173,7 @@
   c_op.flags = 0;
   switch (type) {
   case GRPC_OP_SEND_INITIAL_METADATA:
-    if (!pygrpc_cast_pylist_to_send_metadata(
+    if (!pygrpc_cast_pyseq_to_send_metadata(
             PyTuple_GetItem(op, INITIAL_METADATA_INDEX),
             &c_op.data.send_initial_metadata.metadata,
             &c_op.data.send_initial_metadata.count)) {
@@ -190,7 +191,7 @@
     /* Don't need to fill in any other fields. */
     break;
   case GRPC_OP_SEND_STATUS_FROM_SERVER:
-    if (!pygrpc_cast_pylist_to_send_metadata(
+    if (!pygrpc_cast_pyseq_to_send_metadata(
             PyTuple_GetItem(op, TRAILING_METADATA_INDEX),
             &c_op.data.send_status_from_server.trailing_metadata,
             &c_op.data.send_status_from_server.trailing_metadata_count)) {
@@ -247,8 +248,16 @@
 }
 
 void pygrpc_discard_op(grpc_op op) {
+  size_t i;
   switch(op.op) {
   case GRPC_OP_SEND_INITIAL_METADATA:
+    /* Whenever we produce send-metadata, we allocate new strings (to handle
+       arbitrary sequence input as opposed to just lists or just tuples). We
+       thus must free those elements. */
+    for (i = 0; i < op.data.send_initial_metadata.count; ++i) {
+      gpr_free((void *)op.data.send_initial_metadata.metadata[i].key);
+      gpr_free((void *)op.data.send_initial_metadata.metadata[i].value);
+    }
     gpr_free(op.data.send_initial_metadata.metadata);
     break;
   case GRPC_OP_SEND_MESSAGE:
@@ -258,6 +267,16 @@
     /* Don't need to free any fields. */
     break;
   case GRPC_OP_SEND_STATUS_FROM_SERVER:
+    /* Whenever we produce send-metadata, we allocate new strings (to handle
+       arbitrary sequence input as opposed to just lists or just tuples). We
+       thus must free those elements. */
+    for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count;
+         ++i) {
+      gpr_free(
+          (void *)op.data.send_status_from_server.trailing_metadata[i].key);
+      gpr_free(
+          (void *)op.data.send_status_from_server.trailing_metadata[i].value);
+    }
     gpr_free(op.data.send_status_from_server.trailing_metadata);
     gpr_free((char *)op.data.send_status_from_server.status_details);
     break;
@@ -366,10 +385,12 @@
 gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) {
   gpr_timespec result;
   if (pygrpc_isinf(seconds)) {
-    result = seconds > 0.0 ? gpr_inf_future : gpr_inf_past;
+    result = seconds > 0.0 ? gpr_inf_future(GPR_CLOCK_REALTIME)
+                           : gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
     result.tv_sec = (time_t)seconds;
     result.tv_nsec = ((seconds - result.tv_sec) * 1e9);
+    result.clock_type = GPR_CLOCK_REALTIME;
   }
   return result;
 }
@@ -419,31 +440,41 @@
   gpr_free(args.args);
 }
 
-int pygrpc_cast_pylist_to_send_metadata(
-    PyObject *pylist, grpc_metadata **metadata, size_t *count) {
+int pygrpc_cast_pyseq_to_send_metadata(
+    PyObject *pyseq, grpc_metadata **metadata, size_t *count) {
   size_t i;
   Py_ssize_t value_length;
-  *count = PyList_Size(pylist);
+  char *key;
+  char *value;
+  if (!PySequence_Check(pyseq)) {
+    return 0;
+  }
+  *count = PySequence_Size(pyseq);
   *metadata = gpr_malloc(sizeof(grpc_metadata) * *count);
   for (i = 0; i < *count; ++i) {
-    if (!PyArg_ParseTuple(
-        PyList_GetItem(pylist, i), "ss#",
-        &(*metadata)[i].key, &(*metadata)[i].value, &value_length)) {
+    PyObject *item = PySequence_GetItem(pyseq, i);
+    if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) {
+      Py_DECREF(item);
       gpr_free(*metadata);
       *count = 0;
       *metadata = NULL;
       return 0;
+    } else {
+      (*metadata)[i].key = gpr_strdup(key);
+      (*metadata)[i].value = gpr_malloc(value_length);
+      memcpy((void *)(*metadata)[i].value, value, value_length);
+      Py_DECREF(item);
     }
     (*metadata)[i].value_length = value_length;
   }
   return 1;
 }
 
-PyObject *pygrpc_cast_metadata_array_to_pylist(grpc_metadata_array metadata) {
-  PyObject *result = PyList_New(metadata.count);
+PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) {
+  PyObject *result = PyTuple_New(metadata.count);
   size_t i;
   for (i = 0; i < metadata.count; ++i) {
-    PyList_SetItem(
+    PyTuple_SetItem(
         result, i, Py_BuildValue(
             "ss#", metadata.metadata[i].key, metadata.metadata[i].value,
             (Py_ssize_t)metadata.metadata[i].value_length));
diff --git a/src/python/src/grpc/_adapter/_intermediary_low.py b/src/python/src/grpc/_adapter/_intermediary_low.py
index 6b96aef..3c7f0a2 100644
--- a/src/python/src/grpc/_adapter/_intermediary_low.py
+++ b/src/python/src/grpc/_adapter/_intermediary_low.py
@@ -144,10 +144,11 @@
     self._metadata.append((key, value))
 
   def premetadata(self):
-    return self._internal.start_batch([
+    result = self._internal.start_batch([
           _types.OpArgs.send_initial_metadata(self._metadata)
       ], _IGNORE_ME_TAG)
     self._metadata = []
+    return result
 
   def read(self, tag):
     return self._internal.start_batch([
diff --git a/src/python/src/grpc/_adapter/_intermediary_low_test.py b/src/python/src/grpc/_adapter/_intermediary_low_test.py
index 4783463..27a5b82 100644
--- a/src/python/src/grpc/_adapter/_intermediary_low_test.py
+++ b/src/python/src/grpc/_adapter/_intermediary_low_test.py
@@ -29,6 +29,8 @@
 
 """Tests for the old '_low'."""
 
+import Queue
+import threading
 import time
 import unittest
 
@@ -43,6 +45,7 @@
     bytes(bytearray((row + column) % 256 for column in range(row)))
     for row in range(_STREAM_LENGTH))
 
+
 class LonelyClientTest(unittest.TestCase):
 
   def testLonelyClient(self):
@@ -79,6 +82,14 @@
     del completion_queue
 
 
+def _drive_completion_queue(completion_queue, event_queue):
+  while True:
+    event = completion_queue.get(_FUTURE)
+    if event.kind is _low.Event.Kind.STOP:
+      break
+    event_queue.put(event)
+
+
 class EchoTest(unittest.TestCase):
 
   def setUp(self):
@@ -88,24 +99,26 @@
     self.server = _low.Server(self.server_completion_queue)
     port = self.server.add_http2_addr('[::]:0')
     self.server.start()
+    self.server_events = Queue.Queue()
+    self.server_completion_queue_thread = threading.Thread(
+        target=_drive_completion_queue,
+        args=(self.server_completion_queue, self.server_events))
+    self.server_completion_queue_thread.start()
 
     self.client_completion_queue = _low.CompletionQueue()
     self.channel = _low.Channel('%s:%d' % (self.host, port), None)
+    self.client_events = Queue.Queue()
+    self.client_completion_queue_thread = threading.Thread(
+        target=_drive_completion_queue,
+        args=(self.client_completion_queue, self.client_events))
+    self.client_completion_queue_thread.start()
 
   def tearDown(self):
     self.server.stop()
     self.server_completion_queue.stop()
     self.client_completion_queue.stop()
-    while True:
-      event = self.server_completion_queue.get(_FUTURE)
-      if event is not None and event.kind is _low.Event.Kind.STOP:
-        break
-    while True:
-      event = self.client_completion_queue.get(_FUTURE)
-      if event is not None and event.kind is _low.Event.Kind.STOP:
-        break
-    self.server_completion_queue = None
-    self.client_completion_queue = None
+    self.server_completion_queue_thread.join()
+    self.client_completion_queue_thread.join()
     del self.server
 
   def _perform_echo_test(self, test_data):
@@ -144,7 +157,7 @@
     client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
 
     self.server.service(service_tag)
-    service_accepted = self.server_completion_queue.get(_FUTURE)
+    service_accepted = self.server_events.get()
     self.assertIsNotNone(service_accepted)
     self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED)
     self.assertIs(service_accepted.tag, service_tag)
@@ -165,7 +178,7 @@
                              server_leading_binary_metadata_value)
     server_call.premetadata()
 
-    metadata_accepted = self.client_completion_queue.get(_FUTURE)
+    metadata_accepted = self.client_events.get()
     self.assertIsNotNone(metadata_accepted)
     self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
     self.assertEqual(metadata_tag, metadata_accepted.tag)
@@ -179,14 +192,14 @@
 
     for datum in test_data:
       client_call.write(datum, write_tag)
-      write_accepted = self.client_completion_queue.get(_FUTURE)
+      write_accepted = self.client_events.get()
       self.assertIsNotNone(write_accepted)
       self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED)
       self.assertIs(write_accepted.tag, write_tag)
       self.assertIs(write_accepted.write_accepted, True)
 
       server_call.read(read_tag)
-      read_accepted = self.server_completion_queue.get(_FUTURE)
+      read_accepted = self.server_events.get()
       self.assertIsNotNone(read_accepted)
       self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
       self.assertEqual(read_tag, read_accepted.tag)
@@ -194,14 +207,14 @@
       server_data.append(read_accepted.bytes)
 
       server_call.write(read_accepted.bytes, write_tag)
-      write_accepted = self.server_completion_queue.get(_FUTURE)
+      write_accepted = self.server_events.get()
       self.assertIsNotNone(write_accepted)
       self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind)
       self.assertEqual(write_tag, write_accepted.tag)
       self.assertTrue(write_accepted.write_accepted)
 
       client_call.read(read_tag)
-      read_accepted = self.client_completion_queue.get(_FUTURE)
+      read_accepted = self.client_events.get()
       self.assertIsNotNone(read_accepted)
       self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
       self.assertEqual(read_tag, read_accepted.tag)
@@ -209,14 +222,14 @@
       client_data.append(read_accepted.bytes)
 
     client_call.complete(complete_tag)
-    complete_accepted = self.client_completion_queue.get(_FUTURE)
+    complete_accepted = self.client_events.get()
     self.assertIsNotNone(complete_accepted)
     self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED)
     self.assertIs(complete_accepted.tag, complete_tag)
     self.assertIs(complete_accepted.complete_accepted, True)
 
     server_call.read(read_tag)
-    read_accepted = self.server_completion_queue.get(_FUTURE)
+    read_accepted = self.server_events.get()
     self.assertIsNotNone(read_accepted)
     self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
     self.assertEqual(read_tag, read_accepted.tag)
@@ -228,8 +241,8 @@
                              server_trailing_binary_metadata_value)
 
     server_call.status(_low.Status(_low.Code.OK, details), status_tag)
-    server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
-    server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
+    server_terminal_event_one = self.server_events.get()
+    server_terminal_event_two = self.server_events.get()
     if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED:
       status_accepted = server_terminal_event_one
       rpc_accepted = server_terminal_event_two
@@ -246,8 +259,8 @@
     self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status)
 
     client_call.read(read_tag)
-    client_terminal_event_one = self.client_completion_queue.get(_FUTURE)
-    client_terminal_event_two = self.client_completion_queue.get(_FUTURE)
+    client_terminal_event_one = self.client_events.get()
+    client_terminal_event_two = self.client_events.get()
     if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
       read_accepted = client_terminal_event_one
       finish_accepted = client_terminal_event_two
@@ -269,6 +282,9 @@
     self.assertIn(server_trailing_binary_metadata_key, metadata)
     self.assertEqual(server_trailing_binary_metadata_value,
                      metadata[server_trailing_binary_metadata_key])
+    self.assertSetEqual(set(key for key, _ in finish_accepted.metadata),
+                        set((server_trailing_metadata_key,
+                             server_trailing_binary_metadata_key,)))
 
     server_timeout_none_event = self.server_completion_queue.get(0)
     self.assertIsNone(server_timeout_none_event)
@@ -303,22 +319,26 @@
     self.server = _low.Server(self.server_completion_queue)
     port = self.server.add_http2_addr('[::]:0')
     self.server.start()
+    self.server_events = Queue.Queue()
+    self.server_completion_queue_thread = threading.Thread(
+        target=_drive_completion_queue,
+        args=(self.server_completion_queue, self.server_events))
+    self.server_completion_queue_thread.start()
 
     self.client_completion_queue = _low.CompletionQueue()
     self.channel = _low.Channel('%s:%d' % (self.host, port), None)
+    self.client_events = Queue.Queue()
+    self.client_completion_queue_thread = threading.Thread(
+        target=_drive_completion_queue,
+        args=(self.client_completion_queue, self.client_events))
+    self.client_completion_queue_thread.start()
 
   def tearDown(self):
     self.server.stop()
     self.server_completion_queue.stop()
     self.client_completion_queue.stop()
-    while True:
-      event = self.server_completion_queue.get(0)
-      if event is not None and event.kind is _low.Event.Kind.STOP:
-        break
-    while True:
-      event = self.client_completion_queue.get(0)
-      if event is not None and event.kind is _low.Event.Kind.STOP:
-        break
+    self.server_completion_queue_thread.join()
+    self.client_completion_queue_thread.join()
     del self.server
 
   def testCancellation(self):
@@ -340,29 +360,29 @@
     client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
 
     self.server.service(service_tag)
-    service_accepted = self.server_completion_queue.get(_FUTURE)
+    service_accepted = self.server_events.get()
     server_call = service_accepted.service_acceptance.call
 
     server_call.accept(self.server_completion_queue, finish_tag)
     server_call.premetadata()
 
-    metadata_accepted = self.client_completion_queue.get(_FUTURE)
+    metadata_accepted = self.client_events.get()
     self.assertIsNotNone(metadata_accepted)
 
     for datum in test_data:
       client_call.write(datum, write_tag)
-      write_accepted = self.client_completion_queue.get(_FUTURE)
+      write_accepted = self.client_events.get()
 
       server_call.read(read_tag)
-      read_accepted = self.server_completion_queue.get(_FUTURE)
+      read_accepted = self.server_events.get()
       server_data.append(read_accepted.bytes)
 
       server_call.write(read_accepted.bytes, write_tag)
-      write_accepted = self.server_completion_queue.get(_FUTURE)
+      write_accepted = self.server_events.get()
       self.assertIsNotNone(write_accepted)
 
       client_call.read(read_tag)
-      read_accepted = self.client_completion_queue.get(_FUTURE)
+      read_accepted = self.client_events.get()
       client_data.append(read_accepted.bytes)
 
     client_call.cancel()
@@ -373,8 +393,8 @@
 
     server_call.read(read_tag)
 
-    server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
-    server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
+    server_terminal_event_one = self.server_events.get()
+    server_terminal_event_two = self.server_events.get()
     if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
       read_accepted = server_terminal_event_one
       rpc_accepted = server_terminal_event_two
@@ -388,7 +408,7 @@
     self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
     self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status)
 
-    finish_event = self.client_completion_queue.get(_FUTURE)
+    finish_event = self.client_events.get()
     self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
     self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'), 
                                  finish_event.status)
diff --git a/src/python/src/grpc/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
index 8a9f1a0..268e5fe 100644
--- a/src/python/src/grpc/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -27,6 +27,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.
 
+import threading
 import time
 import unittest
 
@@ -34,6 +35,33 @@
 from grpc._adapter import _low
 
 
+def WaitForEvents(completion_queues, deadline):
+  """
+  Args:
+    completion_queues: list of completion queues to wait for events on
+    deadline: absolute deadline to wait until
+
+  Returns:
+    a sequence of events of length len(completion_queues).
+  """
+
+  results = [None] * len(completion_queues)
+  lock = threading.Lock()
+  threads = []
+  def set_ith_result(i, completion_queue):
+    result = completion_queue.next(deadline)
+    with lock:
+      print i, completion_queue, result, time.time() - deadline
+      results[i] = result
+  for i, completion_queue in enumerate(completion_queues):
+    thread = threading.Thread(target=set_ith_result,
+                              args=[i, completion_queue])
+    thread.start()
+    threads.append(thread)
+  for thread in threads:
+    thread.join()
+  return results
+
 class InsecureServerInsecureClient(unittest.TestCase):
 
   def setUp(self):
@@ -95,7 +123,8 @@
     ], client_call_tag)
     self.assertEquals(_types.CallError.OK, client_start_batch_result)
 
-    request_event = self.server_completion_queue.next(DEADLINE)
+    client_no_event, request_event, = WaitForEvents([self.client_completion_queue, self.server_completion_queue], time.time() + 2)
+    self.assertEquals(client_no_event, None)
     self.assertEquals(_types.EventType.OP_COMPLETE, request_event.type)
     self.assertIsInstance(request_event.call, _low.Call)
     self.assertIs(server_request_tag, request_event.tag)
@@ -118,8 +147,7 @@
     ], server_call_tag)
     self.assertEquals(_types.CallError.OK, server_start_batch_result)
 
-    client_event = self.client_completion_queue.next(DEADLINE)
-    server_event = self.server_completion_queue.next(DEADLINE)
+    client_event, server_event, = WaitForEvents([self.client_completion_queue, self.server_completion_queue], time.time() + 1)
 
     self.assertEquals(6, len(client_event.results))
     found_client_op_types = set()
diff --git a/src/python/src/grpc/_cython/.gitignore b/src/python/src/grpc/_cython/.gitignore
new file mode 100644
index 0000000..c315029
--- /dev/null
+++ b/src/python/src/grpc/_cython/.gitignore
@@ -0,0 +1,7 @@
+*.h
+*.c
+*.a
+*.so
+*.dll
+*.pyc
+*.pyd
diff --git a/src/python/src/grpc/_cython/README.rst b/src/python/src/grpc/_cython/README.rst
new file mode 100644
index 0000000..c0e6673
--- /dev/null
+++ b/src/python/src/grpc/_cython/README.rst
@@ -0,0 +1,52 @@
+GRPC Python Cython layer
+========================
+
+Package for the GRPC Python Cython layer.
+
+What is Cython?
+---------------
+
+Cython is both a superset of the Python language with extensions for dealing
+with C types and a tool that transpiles this superset into C code. It provides
+convenient means of statically typing expressions and of converting Python
+strings to pointers (among other niceties), thus dramatically smoothing the
+Python/C interop by allowing fluid use of APIs in both from the same source.
+See the wonderful `Cython website`_.
+
+Why Cython?
+-----------
+
+- **Python 2 and 3 support**
+  Cython generated C code has precompiler macros to target both Python 2 and
+  Python 3 C APIs, even while acting as a superset of just the Python 2
+  language (e.g. using ``basestring``).
+- **Significantly less semantic noise**
+  A lot of CPython code is just glue, especially human-error-prone
+  ``Py_INCREF``-ing and ``Py_DECREF``-ing around error handlers and such.
+  Cython takes care of that automagically.
+- **Possible PyPy support**
+  One of the major developments in Cython over the past few years was the
+  addition of support for PyPy. We might soon be able to provide such support
+  ourselves through our use of Cython.
+- **Less Python glue code**
+  There existed several adapter layers in and around the original CPython code
+  to smooth the surface exposed to Python due to how much trouble it was to
+  make such a smooth surface via the CPython API alone. Cython makes writing
+  such a surface incredibly easy, so these adapter layers may be removed.
+
+Implications for Users
+----------------------
+
+Nothing additional will be required for users. PyPI packages will contain
+Cython generated C code and thus not necessitate a Cython installation.
+
+Implications for GRPC Developers
+--------------------------------
+
+A typical edit-compile-debug cycle now requires Cython. We install Cython in
+the ``virtualenv`` generated for the Python tests in this repository, so
+initial test runs may take an extra 2+ minutes to complete.  Subsequent test
+runs won't reinstall ``Cython`` (unless required versions change and the
+``virtualenv`` doesn't have installed versions that satisfy the change).
+
+.. _`Cython website`: http://cython.org/
diff --git a/src/python/src/grpc/_cython/__init__.py b/src/python/src/grpc/_cython/__init__.py
new file mode 100644
index 0000000..b893988
--- /dev/null
+++ b/src/python/src/grpc/_cython/__init__.py
@@ -0,0 +1,28 @@
+# 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.
diff --git a/src/python/src/grpc/_cython/_cygrpc/__init__.py b/src/python/src/grpc/_cython/_cygrpc/__init__.py
new file mode 100644
index 0000000..b893988
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/__init__.py
@@ -0,0 +1,28 @@
+# 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.
diff --git a/src/python/src/grpc/_cython/_cygrpc/call.pxd b/src/python/src/grpc/_cython/_cygrpc/call.pxd
new file mode 100644
index 0000000..fe9b81e
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/call.pxd
@@ -0,0 +1,37 @@
+# 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.
+
+from grpc._cython._cygrpc cimport grpc
+
+
+cdef class Call:
+
+  cdef grpc.grpc_call *c_call
+  cdef list references
+
diff --git a/src/python/src/grpc/_cython/_cygrpc/call.pyx b/src/python/src/grpc/_cython/_cygrpc/call.pyx
new file mode 100644
index 0000000..4349786
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/call.pyx
@@ -0,0 +1,82 @@
+# 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.
+
+cimport cpython
+
+from grpc._cython._cygrpc cimport records
+
+
+cdef class Call:
+
+  def __cinit__(self):
+    # Create an *empty* call
+    self.c_call = NULL
+    self.references = []
+
+  def start_batch(self, operations, tag):
+    if not self.is_valid:
+      raise ValueError("invalid call object cannot be used from Python")
+    cdef records.Operations cy_operations = records.Operations(operations)
+    cdef records.OperationTag operation_tag = records.OperationTag(tag)
+    operation_tag.operation_call = self
+    operation_tag.batch_operations = cy_operations
+    cpython.Py_INCREF(operation_tag)
+    return grpc.grpc_call_start_batch(
+        self.c_call, cy_operations.c_ops, cy_operations.c_nops,
+        <cpython.PyObject *>operation_tag)
+
+  def cancel(self,
+             grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
+             details=None):
+    if not self.is_valid:
+      raise ValueError("invalid call object cannot be used from Python")
+    if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE):
+      raise ValueError("if error_code is specified, so must details "
+                       "(and vice-versa)")
+    if isinstance(details, bytes):
+      pass
+    elif isinstance(details, basestring):
+      details = details.encode()
+    else:
+      raise TypeError("expected details to be str or bytes")
+    if error_code != grpc.GRPC_STATUS__DO_NOT_USE:
+      self.references.append(details)
+      return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details)
+    else:
+      return grpc.grpc_call_cancel(self.c_call)
+
+  def __dealloc__(self):
+    if self.c_call != NULL:
+      grpc.grpc_call_destroy(self.c_call)
+
+  # The object *should* always be valid from Python. Used for debugging.
+  @property
+  def is_valid(self):
+    return self.c_call != NULL
+
diff --git a/src/python/src/grpc/_cython/_cygrpc/channel.pxd b/src/python/src/grpc/_cython/_cygrpc/channel.pxd
new file mode 100644
index 0000000..3e341bf
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/channel.pxd
@@ -0,0 +1,36 @@
+# 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.
+
+from grpc._cython._cygrpc cimport grpc
+
+
+cdef class Channel:
+
+  cdef grpc.grpc_channel *c_channel
+  cdef list references
diff --git a/src/python/src/grpc/_cython/_cygrpc/channel.pyx b/src/python/src/grpc/_cython/_cygrpc/channel.pyx
new file mode 100644
index 0000000..b203138
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/channel.pyx
@@ -0,0 +1,84 @@
+# 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.
+
+from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport completion_queue
+from grpc._cython._cygrpc cimport credentials
+from grpc._cython._cygrpc cimport records
+
+
+cdef class Channel:
+
+  def __cinit__(self, target, records.ChannelArgs arguments=None,
+                credentials.ClientCredentials client_credentials=None):
+    cdef grpc.grpc_channel_args *c_arguments = NULL
+    self.c_channel = NULL
+    self.references = []
+    if arguments is not None:
+      c_arguments = &arguments.c_args
+    if isinstance(target, bytes):
+      pass
+    elif isinstance(target, basestring):
+      target = target.encode()
+    else:
+      raise TypeError("expected target to be str or bytes")
+    if client_credentials is None:
+      self.c_channel = grpc.grpc_channel_create(target, c_arguments)
+    else:
+      self.c_channel = grpc.grpc_secure_channel_create(
+          client_credentials.c_credentials, target, c_arguments)
+      self.references.append(client_credentials)
+    self.references.append(target)
+    self.references.append(arguments)
+
+  def create_call(self, completion_queue.CompletionQueue queue not None,
+                  method, host, records.Timespec deadline not None):
+    if queue.is_shutting_down:
+      raise ValueError("queue must not be shutting down or shutdown")
+    if isinstance(method, bytes):
+      pass
+    elif isinstance(method, basestring):
+      method = method.encode()
+    else:
+      raise TypeError("expected method to be str or bytes")
+    if isinstance(host, bytes):
+      pass
+    elif isinstance(host, basestring):
+      host = host.encode()
+    else:
+      raise TypeError("expected host to be str or bytes")
+    cdef call.Call operation_call = call.Call()
+    operation_call.references = [self, method, host, queue]
+    operation_call.c_call = grpc.grpc_channel_create_call(
+        self.c_channel, queue.c_completion_queue, method, host, deadline.c_time)
+    return operation_call
+
+  def __dealloc__(self):
+    if self.c_channel != NULL:
+      grpc.grpc_channel_destroy(self.c_channel)
diff --git a/src/python/src/grpc/_cython/_cygrpc/completion_queue.pxd b/src/python/src/grpc/_cython/_cygrpc/completion_queue.pxd
new file mode 100644
index 0000000..fd562ad
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/completion_queue.pxd
@@ -0,0 +1,39 @@
+# 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.
+
+from grpc._cython._cygrpc cimport grpc
+
+
+cdef class CompletionQueue:
+
+  cdef grpc.grpc_completion_queue *c_completion_queue
+  cdef object poll_condition
+  cdef bint is_polling
+  cdef bint is_shutting_down
+  cdef bint is_shutdown
diff --git a/src/python/src/grpc/_cython/_cygrpc/completion_queue.pyx b/src/python/src/grpc/_cython/_cygrpc/completion_queue.pyx
new file mode 100644
index 0000000..886d853
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/completion_queue.pyx
@@ -0,0 +1,117 @@
+# 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.
+
+cimport cpython
+
+from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport records
+
+import threading
+import time
+
+
+cdef class CompletionQueue:
+
+  def __cinit__(self):
+    self.c_completion_queue = grpc.grpc_completion_queue_create()
+    self.is_shutting_down = False
+    self.is_shutdown = False
+    self.poll_condition = threading.Condition()
+    self.is_polling = False
+
+  def poll(self, records.Timespec deadline=None):
+    # We name this 'poll' to avoid problems with CPython's expectations for
+    # 'special' methods (like next and __next__).
+    cdef grpc.gpr_timespec c_deadline = grpc.gpr_inf_future
+    cdef records.OperationTag tag = None
+    cdef object user_tag = None
+    cdef call.Call operation_call = None
+    cdef records.CallDetails request_call_details = None
+    cdef records.Metadata request_metadata = None
+    cdef records.Operations batch_operations = None
+    if deadline is not None:
+      c_deadline = deadline.c_time
+    cdef grpc.grpc_event event
+
+    # Poll within a critical section
+    with self.poll_condition:
+      while self.is_polling:
+        self.poll_condition.wait(float(deadline) - time.time())
+      self.is_polling = True
+    with nogil:
+      event = grpc.grpc_completion_queue_next(
+          self.c_completion_queue, c_deadline)
+    with self.poll_condition:
+      self.is_polling = False
+      self.poll_condition.notify()
+
+    if event.type == grpc.GRPC_QUEUE_TIMEOUT:
+      return records.Event(event.type, False, None, None, None, None, None)
+    elif event.type == grpc.GRPC_QUEUE_SHUTDOWN:
+      self.is_shutdown = True
+      return records.Event(event.type, True, None, None, None, None, None)
+    else:
+      if event.tag != NULL:
+        tag = <records.OperationTag>event.tag
+        # We receive event tags only after they've been inc-ref'd elsewhere in
+        # the code.
+        cpython.Py_DECREF(tag)
+        if tag.shutting_down_server is not None:
+          tag.shutting_down_server.notify_shutdown_complete()
+        user_tag = tag.user_tag
+        operation_call = tag.operation_call
+        request_call_details = tag.request_call_details
+        request_metadata = tag.request_metadata
+        batch_operations = tag.batch_operations
+        if tag.is_new_request:
+          # Stuff in the tag not explicitly handled by us needs to live through
+          # the life of the call
+          operation_call.references.extend(tag.references)
+      return records.Event(
+          event.type, event.success, user_tag, operation_call,
+          request_call_details, request_metadata, batch_operations)
+
+  def shutdown(self):
+    grpc.grpc_completion_queue_shutdown(self.c_completion_queue)
+    self.is_shutting_down = True
+
+  def clear(self):
+    if not self.is_shutting_down:
+      raise ValueError('queue must be shutting down to be cleared')
+    while self.poll().type != grpc.GRPC_QUEUE_SHUTDOWN:
+      pass
+
+  def __dealloc__(self):
+    if self.c_completion_queue != NULL:
+      # Ensure shutdown, pump the queue
+      if not self.is_shutting_down:
+        self.shutdown()
+      while not self.is_shutdown:
+        self.poll()
+      grpc.grpc_completion_queue_destroy(self.c_completion_queue)
diff --git a/src/python/src/grpc/_cython/_cygrpc/credentials.pxd b/src/python/src/grpc/_cython/_cygrpc/credentials.pxd
new file mode 100644
index 0000000..6b74a26
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/credentials.pxd
@@ -0,0 +1,45 @@
+# 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.
+
+from grpc._cython._cygrpc cimport grpc
+
+
+cdef class ClientCredentials:
+
+  cdef grpc.grpc_credentials *c_credentials
+  cdef grpc.grpc_ssl_pem_key_cert_pair c_ssl_pem_key_cert_pair
+  cdef list references
+
+
+cdef class ServerCredentials:
+
+  cdef grpc.grpc_server_credentials *c_credentials
+  cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
+  cdef size_t c_ssl_pem_key_cert_pairs_count
+  cdef list references
diff --git a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx
new file mode 100644
index 0000000..c14d884
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx
@@ -0,0 +1,217 @@
+# 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.
+
+from grpc._cython._cygrpc cimport records
+
+
+cdef class ClientCredentials:
+
+  def __cinit__(self):
+    self.c_credentials = NULL
+    self.c_ssl_pem_key_cert_pair.private_key = NULL
+    self.c_ssl_pem_key_cert_pair.certificate_chain = NULL
+    self.references = []
+
+  # The object *can* be invalid in Python if we fail to make the credentials
+  # (and the core thus returns NULL credentials). Used primarily for debugging.
+  @property
+  def is_valid(self):
+    return self.c_credentials != NULL
+
+  def __dealloc__(self):
+    if self.c_credentials != NULL:
+      grpc.grpc_credentials_release(self.c_credentials)
+
+
+cdef class ServerCredentials:
+
+  def __cinit__(self):
+    self.c_credentials = NULL
+
+  def __dealloc__(self):
+    if self.c_credentials != NULL:
+      grpc.grpc_server_credentials_release(self.c_credentials)
+
+
+def client_credentials_google_default():
+  cdef ClientCredentials credentials = ClientCredentials();
+  credentials.c_credentials = grpc.grpc_google_default_credentials_create()
+  return credentials
+
+def client_credentials_ssl(pem_root_certificates,
+                           records.SslPemKeyCertPair ssl_pem_key_cert_pair):
+  if pem_root_certificates is None:
+    pass
+  elif isinstance(pem_root_certificates, bytes):
+    pass
+  elif isinstance(pem_root_certificates, basestring):
+    pem_root_certificates = pem_root_certificates.encode()
+  else:
+    raise TypeError("expected str or bytes for pem_root_certificates")
+  cdef ClientCredentials credentials = ClientCredentials()
+  cdef const char *c_pem_root_certificates = NULL
+  if pem_root_certificates is not None:
+    c_pem_root_certificates = pem_root_certificates
+    credentials.references.append(pem_root_certificates)
+  if ssl_pem_key_cert_pair is not None:
+    credentials.c_credentials = grpc.grpc_ssl_credentials_create(
+        c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair
+    )
+    credentials.references.append(ssl_pem_key_cert_pair)
+  else:
+    credentials.c_credentials = grpc.grpc_ssl_credentials_create(
+      c_pem_root_certificates, NULL
+    )
+
+def client_credentials_composite_credentials(
+    ClientCredentials credentials_1 not None,
+    ClientCredentials credentials_2 not None):
+  if not credentials_1.is_valid or not credentials_2.is_valid:
+    raise ValueError("passed credentials must both be valid")
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = grpc.grpc_composite_credentials_create(
+      credentials_1.c_credentials, credentials_2.c_credentials)
+  credentials.references.append(credentials_1)
+  credentials.references.append(credentials_2)
+  return credentials
+
+def client_credentials_compute_engine():
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = grpc.grpc_compute_engine_credentials_create()
+  return credentials
+
+def client_credentials_service_account(
+    json_key, scope, records.Timespec token_lifetime not None):
+  if isinstance(json_key, bytes):
+    pass
+  elif isinstance(json_key, basestring):
+    json_key = json_key.encode()
+  else:
+    raise TypeError("expected json_key to be str or bytes")
+  if isinstance(scope, bytes):
+    pass
+  elif isinstance(scope, basestring):
+    scope = scope.encode()
+  else:
+    raise TypeError("expected scope to be str or bytes")
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = grpc.grpc_service_account_credentials_create(
+      json_key, scope, token_lifetime.c_time)
+  credentials.references.extend([json_key, scope])
+  return credentials
+
+def client_credentials_jwt(json_key, records.Timespec token_lifetime not None):
+  if isinstance(json_key, bytes):
+    pass
+  elif isinstance(json_key, basestring):
+    json_key = json_key.encode()
+  else:
+    raise TypeError("expected json_key to be str or bytes")
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = grpc.grpc_jwt_credentials_create(
+      json_key, token_lifetime.c_time)
+  credentials.references.append(json_key)
+  return credentials
+
+def client_credentials_refresh_token(json_refresh_token):
+  if isinstance(json_refresh_token, bytes):
+    pass
+  elif isinstance(json_refresh_token, basestring):
+    json_refresh_token = json_refresh_token.encode()
+  else:
+    raise TypeError("expected json_refresh_token to be str or bytes")
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = grpc.grpc_refresh_token_credentials_create(
+      json_refresh_token)
+  credentials.references.append(json_refresh_token)
+  return credentials
+
+def client_credentials_fake_transport_security():
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = (
+      grpc.grpc_fake_transport_security_credentials_create())
+  return credentials
+
+def client_credentials_iam(authorization_token, authority_selector):
+  if isinstance(authorization_token, bytes):
+    pass
+  elif isinstance(authorization_token, basestring):
+    authorization_token = authorization_token.encode()
+  else:
+    raise TypeError("expected authorization_token to be str or bytes")
+  if isinstance(authority_selector, bytes):
+    pass
+  elif isinstance(authority_selector, basestring):
+    authority_selector = authority_selector.encode()
+  else:
+    raise TypeError("expected authority_selector to be str or bytes")
+  cdef ClientCredentials credentials = ClientCredentials()
+  credentials.c_credentials = grpc.grpc_iam_credentials_create(
+      authorization_token, authority_selector)
+  credentials.references.append(authorization_token)
+  credentials.references.append(authority_selector)
+  return credentials
+
+def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs):
+  if pem_root_certs is None:
+    pass
+  elif isinstance(pem_root_certs, bytes):
+    pass
+  elif isinstance(pem_root_certs, basestring):
+    pem_root_certs = pem_root_certs.encode()
+  else:
+    raise TypeError("expected pem_root_certs to be str or bytes")
+  pem_key_cert_pairs = list(pem_key_cert_pairs)
+  for pair in pem_key_cert_pairs:
+    if not isinstance(pair, records.SslPemKeyCertPair):
+      raise TypeError("expected pem_key_cert_pairs to be sequence of "
+                      "records.SslPemKeyCertPair")
+  cdef ServerCredentials credentials = ServerCredentials()
+  credentials.references.append(pem_key_cert_pairs)
+  credentials.references.append(pem_root_certs)
+  credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs)
+  credentials.c_ssl_pem_key_cert_pairs = (
+      <grpc.grpc_ssl_pem_key_cert_pair *>grpc.gpr_malloc(
+          sizeof(grpc.grpc_ssl_pem_key_cert_pair) *
+              credentials.c_ssl_pem_key_cert_pairs_count
+      ))
+  for i in range(credentials.c_ssl_pem_key_cert_pairs_count):
+    credentials.c_ssl_pem_key_cert_pairs[i] = (
+        (<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
+  credentials.c_credentials = grpc.grpc_ssl_server_credentials_create(
+      pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
+      credentials.c_ssl_pem_key_cert_pairs_count
+  )
+  return credentials
+
+def server_credentials_fake_transport_security():
+  cdef ServerCredentials credentials = ServerCredentials()
+  credentials.c_credentials = (
+      grpc.grpc_fake_transport_security_server_credentials_create())
+  return credentials
diff --git a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd
new file mode 100644
index 0000000..7db8fbe
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd
@@ -0,0 +1,344 @@
+# 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.
+
+cimport libc.time
+
+
+cdef extern from "grpc/support/alloc.h":
+  void *gpr_malloc(size_t size)
+  void gpr_free(void *ptr)
+  void *gpr_realloc(void *p, size_t size)
+
+cdef extern from "grpc/support/slice.h":
+  ctypedef struct gpr_slice:
+    # don't worry about writing out the members of gpr_slice; we never access
+    # them directly.
+    pass
+
+  gpr_slice gpr_slice_ref(gpr_slice s)
+  void gpr_slice_unref(gpr_slice s)
+  gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *))
+  gpr_slice gpr_slice_new_with_len(
+      void *p, size_t len, void (*destroy)(void *, size_t))
+  gpr_slice gpr_slice_malloc(size_t length)
+  gpr_slice gpr_slice_from_copied_string(const char *source)
+  gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len)
+
+  # Declare functions for function-like macros (because Cython)...
+  void *gpr_slice_start_ptr "GPR_SLICE_START_PTR" (gpr_slice s)
+  size_t gpr_slice_length "GPR_SLICE_LENGTH" (gpr_slice s)
+
+
+cdef extern from "grpc/support/port_platform.h":
+  # As long as the header file gets this type right, we don't need to get this
+  # type exactly; just close enough that the operations will be supported in the
+  # underlying C layers.
+  ctypedef unsigned int gpr_uint32
+
+
+cdef extern from "grpc/support/time.h":
+
+  ctypedef struct gpr_timespec:
+    libc.time.time_t seconds "tv_sec"
+    int nanoseconds "tv_nsec"
+
+  cdef gpr_timespec gpr_time_0
+  cdef gpr_timespec gpr_inf_future
+  cdef gpr_timespec gpr_inf_past
+
+  gpr_timespec gpr_now()
+
+
+cdef extern from "grpc/status.h":
+  ctypedef enum grpc_status_code:
+    GRPC_STATUS_OK
+    GRPC_STATUS_CANCELLED
+    GRPC_STATUS_UNKNOWN
+    GRPC_STATUS_INVALID_ARGUMENT
+    GRPC_STATUS_DEADLINE_EXCEEDED
+    GRPC_STATUS_NOT_FOUND
+    GRPC_STATUS_ALREADY_EXISTS
+    GRPC_STATUS_PERMISSION_DENIED
+    GRPC_STATUS_UNAUTHENTICATED
+    GRPC_STATUS_RESOURCE_EXHAUSTED
+    GRPC_STATUS_FAILED_PRECONDITION
+    GRPC_STATUS_ABORTED
+    GRPC_STATUS_OUT_OF_RANGE
+    GRPC_STATUS_UNIMPLEMENTED
+    GRPC_STATUS_INTERNAL
+    GRPC_STATUS_UNAVAILABLE
+    GRPC_STATUS_DATA_LOSS
+    GRPC_STATUS__DO_NOT_USE
+
+
+cdef extern from "grpc/byte_buffer_reader.h":
+  struct grpc_byte_buffer_reader:
+    # We don't care about the internals
+    pass
+
+
+cdef extern from "grpc/byte_buffer.h":
+  ctypedef struct grpc_byte_buffer:
+    # We don't care about the internals.
+    pass
+
+  grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
+                                                size_t nslices)
+  size_t grpc_byte_buffer_length(grpc_byte_buffer *bb)
+  void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer)
+
+  void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
+                                    grpc_byte_buffer *buffer)
+  int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
+                                   gpr_slice *slice)
+  void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader)
+
+
+cdef extern from "grpc/grpc.h":
+
+  ctypedef struct grpc_completion_queue:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  ctypedef struct grpc_channel:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  ctypedef struct grpc_server:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  ctypedef struct grpc_call:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  ctypedef enum grpc_arg_type:
+    grpc_arg_string "GRPC_ARG_STRING"
+    grpc_arg_integer "GRPC_ARG_INTEGER"
+    grpc_arg_pointer "GRPC_ARG_POINTER"
+
+  ctypedef struct grpc_arg_value_pointer:
+    void *address "p"
+    void *(*copy)(void *)
+    void (*destroy)(void *)
+
+  union grpc_arg_value:
+    char *string
+    int integer
+    grpc_arg_value_pointer pointer
+
+  ctypedef struct grpc_arg:
+    grpc_arg_type type
+    char *key
+    grpc_arg_value value
+
+  ctypedef struct grpc_channel_args:
+    size_t arguments_length "num_args"
+    grpc_arg *arguments "args"
+
+  ctypedef enum grpc_call_error:
+    GRPC_CALL_OK
+    GRPC_CALL_ERROR
+    GRPC_CALL_ERROR_NOT_ON_SERVER
+    GRPC_CALL_ERROR_NOT_ON_CLIENT
+    GRPC_CALL_ERROR_ALREADY_ACCEPTED
+    GRPC_CALL_ERROR_ALREADY_INVOKED
+    GRPC_CALL_ERROR_NOT_INVOKED
+    GRPC_CALL_ERROR_ALREADY_FINISHED
+    GRPC_CALL_ERROR_TOO_MANY_OPERATIONS
+    GRPC_CALL_ERROR_INVALID_FLAGS
+    GRPC_CALL_ERROR_INVALID_METADATA
+
+  ctypedef struct grpc_metadata:
+    const char *key
+    const char *value
+    size_t value_length
+    # ignore the 'internal_data.obfuscated' fields.
+
+  ctypedef enum grpc_completion_type:
+    GRPC_QUEUE_SHUTDOWN
+    GRPC_QUEUE_TIMEOUT
+    GRPC_OP_COMPLETE
+
+  ctypedef struct grpc_event:
+    grpc_completion_type type
+    int success
+    void *tag
+
+  ctypedef struct grpc_metadata_array:
+    size_t count
+    size_t capacity
+    grpc_metadata *metadata
+
+  void grpc_metadata_array_init(grpc_metadata_array *array)
+  void grpc_metadata_array_destroy(grpc_metadata_array *array)
+
+  ctypedef struct grpc_call_details:
+    char *method
+    size_t method_capacity
+    char *host
+    size_t host_capacity
+    gpr_timespec deadline
+
+  void grpc_call_details_init(grpc_call_details *details)
+  void grpc_call_details_destroy(grpc_call_details *details)
+
+  ctypedef enum grpc_op_type:
+    GRPC_OP_SEND_INITIAL_METADATA
+    GRPC_OP_SEND_MESSAGE
+    GRPC_OP_SEND_CLOSE_FROM_CLIENT
+    GRPC_OP_SEND_STATUS_FROM_SERVER
+    GRPC_OP_RECV_INITIAL_METADATA
+    GRPC_OP_RECV_MESSAGE
+    GRPC_OP_RECV_STATUS_ON_CLIENT
+    GRPC_OP_RECV_CLOSE_ON_SERVER
+
+  ctypedef struct grpc_op_data_send_initial_metadata:
+    size_t count
+    grpc_metadata *metadata
+
+  ctypedef struct grpc_op_data_send_status_from_server:
+    size_t trailing_metadata_count
+    grpc_metadata *trailing_metadata
+    grpc_status_code status
+    const char *status_details
+
+  ctypedef struct grpc_op_data_recv_status_on_client:
+    grpc_metadata_array *trailing_metadata
+    grpc_status_code *status
+    char **status_details
+    size_t *status_details_capacity
+
+  ctypedef struct grpc_op_data_recv_close_on_server:
+    int *cancelled
+
+  union grpc_op_data:
+    grpc_op_data_send_initial_metadata send_initial_metadata
+    grpc_byte_buffer *send_message
+    grpc_op_data_send_status_from_server send_status_from_server
+    grpc_metadata_array *receive_initial_metadata "recv_initial_metadata"
+    grpc_byte_buffer **receive_message "recv_message"
+    grpc_op_data_recv_status_on_client receive_status_on_client "recv_status_on_client"
+    grpc_op_data_recv_close_on_server receive_close_on_server "recv_close_on_server"
+
+  ctypedef struct grpc_op:
+    grpc_op_type type "op"
+    gpr_uint32 flags
+    grpc_op_data data
+
+  void grpc_init()
+  void grpc_shutdown()
+
+  grpc_completion_queue *grpc_completion_queue_create()
+  grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
+                                        gpr_timespec deadline) nogil
+  void grpc_completion_queue_shutdown(grpc_completion_queue *cq)
+  void grpc_completion_queue_destroy(grpc_completion_queue *cq)
+
+  grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
+                                        size_t nops, void *tag)
+  grpc_call_error grpc_call_cancel(grpc_call *call)
+  grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
+                                               grpc_status_code status,
+                                               const char *description)
+  void grpc_call_destroy(grpc_call *call)
+
+
+  grpc_channel *grpc_channel_create(const char *target,
+                                    const grpc_channel_args *args)
+  grpc_call *grpc_channel_create_call(grpc_channel *channel,
+                                      grpc_completion_queue *completion_queue,
+                                      const char *method, const char *host,
+                                      gpr_timespec deadline)
+  void grpc_channel_destroy(grpc_channel *channel)
+
+  grpc_server *grpc_server_create(const grpc_channel_args *args)
+  grpc_call_error grpc_server_request_call(
+      grpc_server *server, grpc_call **call, grpc_call_details *details,
+      grpc_metadata_array *request_metadata, grpc_completion_queue
+      *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void
+      *tag_new)
+  void grpc_server_register_completion_queue(grpc_server *server,
+                                             grpc_completion_queue *cq)
+  int grpc_server_add_http2_port(grpc_server *server, const char *addr)
+  void grpc_server_start(grpc_server *server)
+  void grpc_server_shutdown_and_notify(
+      grpc_server *server, grpc_completion_queue *cq, void *tag)
+  void grpc_server_cancel_all_calls(grpc_server *server)
+  void grpc_server_destroy(grpc_server *server)
+
+
+cdef extern from "grpc/grpc_security.h":
+
+  ctypedef struct grpc_ssl_pem_key_cert_pair:
+    const char *private_key
+    const char *certificate_chain "cert_chain"
+
+  ctypedef struct grpc_credentials:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  grpc_credentials *grpc_google_default_credentials_create()
+  grpc_credentials *grpc_ssl_credentials_create(
+      const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair)
+
+  grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
+                                                      grpc_credentials *creds2)
+  grpc_credentials *grpc_compute_engine_credentials_create()
+  grpc_credentials *grpc_service_account_credentials_create(
+      const char *json_key, const char *scope, gpr_timespec token_lifetime)
+  grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
+                                                gpr_timespec token_lifetime)
+  grpc_credentials *grpc_refresh_token_credentials_create(
+      const char *json_refresh_token)
+  grpc_credentials *grpc_fake_transport_security_credentials_create()
+  grpc_credentials *grpc_iam_credentials_create(const char *authorization_token,
+                                                const char *authority_selector)
+  void grpc_credentials_release(grpc_credentials *creds)
+
+  grpc_channel *grpc_secure_channel_create(
+      grpc_credentials *creds, const char *target,
+      const grpc_channel_args *args)
+
+  ctypedef struct grpc_server_credentials:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  grpc_server_credentials *grpc_ssl_server_credentials_create(
+      const char *pem_root_certs,
+      grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
+      size_t num_key_cert_pairs);
+  grpc_server_credentials *grpc_fake_transport_security_server_credentials_create()
+  void grpc_server_credentials_release(grpc_server_credentials *creds)
+
+  int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
+                                        grpc_server_credentials *creds)
+
+  grpc_call_error grpc_call_set_credentials(grpc_call *call,
+                                            grpc_credentials *creds)
diff --git a/src/python/src/grpc/_cython/_cygrpc/records.pxd b/src/python/src/grpc/_cython/_cygrpc/records.pxd
new file mode 100644
index 0000000..9ee4878
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/records.pxd
@@ -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.
+
+from grpc._cython._cygrpc cimport grpc
+from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport server
+
+
+cdef class Timespec:
+
+  cdef grpc.gpr_timespec c_time
+
+
+cdef class CallDetails:
+
+  cdef grpc.grpc_call_details c_details
+
+
+cdef class OperationTag:
+
+  cdef object user_tag
+  cdef list references
+  # This allows CompletionQueue to notify the Python Server object that the
+  # underlying GRPC core server has shutdown
+  cdef server.Server shutting_down_server
+  cdef call.Call operation_call
+  cdef CallDetails request_call_details
+  cdef Metadata request_metadata
+  cdef Operations batch_operations
+  cdef bint is_new_request
+
+
+cdef class Event:
+
+  cdef readonly grpc.grpc_completion_type type
+  cdef readonly bint success
+  cdef readonly object tag
+
+  # For operations with calls
+  cdef readonly call.Call operation_call
+
+  # For Server.request_call
+  cdef readonly CallDetails request_call_details
+  cdef readonly Metadata request_metadata
+
+  # For Call.start_batch
+  cdef readonly Operations batch_operations
+
+
+cdef class ByteBuffer:
+
+  cdef grpc.grpc_byte_buffer *c_byte_buffer
+
+
+cdef class SslPemKeyCertPair:
+
+  cdef grpc.grpc_ssl_pem_key_cert_pair c_pair
+  cdef readonly object private_key, certificate_chain
+
+
+cdef class ChannelArg:
+
+  cdef grpc.grpc_arg c_arg
+  cdef readonly object key, value
+
+
+cdef class ChannelArgs:
+
+  cdef grpc.grpc_channel_args c_args
+  cdef list args
+
+
+cdef class Metadatum:
+
+  cdef grpc.grpc_metadata c_metadata
+  cdef object _key, _value
+
+
+cdef class Metadata:
+
+  cdef grpc.grpc_metadata_array c_metadata_array
+  cdef object metadata
+
+
+cdef class Operation:
+
+  cdef grpc.grpc_op c_op
+  cdef ByteBuffer _received_message
+  cdef Metadata _received_metadata
+  cdef grpc.grpc_status_code _received_status_code
+  cdef char *_received_status_details
+  cdef size_t _received_status_details_capacity
+  cdef int _received_cancelled
+  cdef readonly bint is_valid
+  cdef object references
+
+
+cdef class Operations:
+
+  cdef grpc.grpc_op *c_ops
+  cdef size_t c_nops
+  cdef list operations
+
diff --git a/src/python/src/grpc/_cython/_cygrpc/records.pyx b/src/python/src/grpc/_cython/_cygrpc/records.pyx
new file mode 100644
index 0000000..4814769
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/records.pyx
@@ -0,0 +1,575 @@
+# 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.
+
+from grpc._cython._cygrpc cimport grpc
+from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport server
+
+
+class StatusCode:
+  ok = grpc.GRPC_STATUS_OK
+  cancelled = grpc.GRPC_STATUS_CANCELLED
+  unknown = grpc.GRPC_STATUS_UNKNOWN
+  invalid_argument = grpc.GRPC_STATUS_INVALID_ARGUMENT
+  deadline_exceeded = grpc.GRPC_STATUS_DEADLINE_EXCEEDED
+  not_found = grpc.GRPC_STATUS_NOT_FOUND
+  already_exists = grpc.GRPC_STATUS_ALREADY_EXISTS
+  permission_denied = grpc.GRPC_STATUS_PERMISSION_DENIED
+  unauthenticated = grpc.GRPC_STATUS_UNAUTHENTICATED
+  resource_exhausted = grpc.GRPC_STATUS_RESOURCE_EXHAUSTED
+  failed_precondition = grpc.GRPC_STATUS_FAILED_PRECONDITION
+  aborted = grpc.GRPC_STATUS_ABORTED
+  out_of_range = grpc.GRPC_STATUS_OUT_OF_RANGE
+  unimplemented = grpc.GRPC_STATUS_UNIMPLEMENTED
+  internal = grpc.GRPC_STATUS_INTERNAL
+  unavailable = grpc.GRPC_STATUS_UNAVAILABLE
+  data_loss = grpc.GRPC_STATUS_DATA_LOSS
+
+
+class CallError:
+  ok = grpc.GRPC_CALL_OK
+  error = grpc.GRPC_CALL_ERROR
+  not_on_server = grpc.GRPC_CALL_ERROR_NOT_ON_SERVER
+  not_on_client = grpc.GRPC_CALL_ERROR_NOT_ON_CLIENT
+  already_accepted = grpc.GRPC_CALL_ERROR_ALREADY_ACCEPTED
+  already_invoked = grpc.GRPC_CALL_ERROR_ALREADY_INVOKED
+  not_invoked = grpc.GRPC_CALL_ERROR_NOT_INVOKED
+  already_finished = grpc.GRPC_CALL_ERROR_ALREADY_FINISHED
+  too_many_operations = grpc.GRPC_CALL_ERROR_TOO_MANY_OPERATIONS
+  invalid_flags = grpc.GRPC_CALL_ERROR_INVALID_FLAGS
+  invalid_metadata = grpc.GRPC_CALL_ERROR_INVALID_METADATA
+
+
+class CompletionType:
+  queue_shutdown = grpc.GRPC_QUEUE_SHUTDOWN
+  queue_timeout = grpc.GRPC_QUEUE_TIMEOUT
+  operation_complete = grpc.GRPC_OP_COMPLETE
+
+
+class OperationType:
+  send_initial_metadata = grpc.GRPC_OP_SEND_INITIAL_METADATA
+  send_message = grpc.GRPC_OP_SEND_MESSAGE
+  send_close_from_client = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT
+  send_status_from_server = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER
+  receive_initial_metadata = grpc.GRPC_OP_RECV_INITIAL_METADATA
+  receive_message = grpc.GRPC_OP_RECV_MESSAGE
+  receive_status_on_client = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+  receive_close_on_server = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER
+
+
+cdef class Timespec:
+
+  def __cinit__(self, time):
+    if time is None:
+      self.c_time = grpc.gpr_now()
+    elif isinstance(time, float):
+      if time == float("+inf"):
+        self.c_time = grpc.gpr_inf_future
+      elif time == float("-inf"):
+        self.c_time = grpc.gpr_inf_past
+      else:
+        self.c_time.seconds = time
+        self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
+    else:
+      raise TypeError("expected time to be float")
+
+  @property
+  def seconds(self):
+    return self.c_time.seconds
+
+  @property
+  def nanoseconds(self):
+    return self.c_time.nanoseconds
+
+  def __float__(self):
+    return <double>self.c_time.seconds + <double>self.c_time.nanoseconds / 1e9
+
+  infinite_future = Timespec(float("+inf"))
+  infinite_past = Timespec(float("-inf"))
+
+
+cdef class CallDetails:
+
+  def __cinit__(self):
+    grpc.grpc_call_details_init(&self.c_details)
+
+  def __dealloc__(self):
+    grpc.grpc_call_details_destroy(&self.c_details)
+
+  @property
+  def method(self):
+    if self.c_details.method != NULL:
+      return <bytes>self.c_details.method
+    else:
+      return None
+
+  @property
+  def host(self):
+    if self.c_details.host != NULL:
+      return <bytes>self.c_details.host
+    else:
+      return None
+
+  @property
+  def deadline(self):
+    timespec = Timespec(float("-inf"))
+    timespec.c_time = self.c_details.deadline
+    return timespec
+
+
+cdef class OperationTag:
+
+  def __cinit__(self, user_tag):
+    self.user_tag = user_tag
+    self.references = []
+
+
+cdef class Event:
+
+  def __cinit__(self, grpc.grpc_completion_type type, bint success,
+                object tag, call.Call operation_call,
+                CallDetails request_call_details,
+                Metadata request_metadata,
+                Operations batch_operations):
+    self.type = type
+    self.success = success
+    self.tag = tag
+    self.operation_call = operation_call
+    self.request_call_details = request_call_details
+    self.request_metadata = request_metadata
+    self.batch_operations = batch_operations
+
+
+cdef class ByteBuffer:
+
+  def __cinit__(self, data):
+    if data is None:
+      self.c_byte_buffer = NULL
+      return
+    if isinstance(data, bytes):
+      pass
+    elif isinstance(data, basestring):
+      data = data.encode()
+    else:
+      raise TypeError("expected value to be of type str or bytes")
+
+    cdef char *c_data = data
+    data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
+    self.c_byte_buffer = grpc.grpc_raw_byte_buffer_create(
+        &data_slice, 1)
+    grpc.gpr_slice_unref(data_slice)
+
+  def bytes(self):
+    cdef grpc.grpc_byte_buffer_reader reader
+    cdef grpc.gpr_slice data_slice
+    cdef size_t data_slice_length
+    cdef void *data_slice_pointer
+    if self.c_byte_buffer != NULL:
+      grpc.grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer)
+      result = b""
+      while grpc.grpc_byte_buffer_reader_next(&reader, &data_slice):
+        data_slice_pointer = grpc.gpr_slice_start_ptr(data_slice)
+        data_slice_length = grpc.gpr_slice_length(data_slice)
+        result += (<char *>data_slice_pointer)[:data_slice_length]
+      grpc.grpc_byte_buffer_reader_destroy(&reader)
+      return result
+    else:
+      return None
+
+  def __len__(self):
+    if self.c_byte_buffer != NULL:
+      return grpc.grpc_byte_buffer_length(self.c_byte_buffer)
+    else:
+      return 0
+
+  def __str__(self):
+    return self.bytes()
+
+  def __dealloc__(self):
+    if self.c_byte_buffer != NULL:
+      grpc.grpc_byte_buffer_destroy(self.c_byte_buffer)
+
+
+cdef class SslPemKeyCertPair:
+
+  def __cinit__(self, private_key, certificate_chain):
+    if isinstance(private_key, bytes):
+      self.private_key = private_key
+    elif isinstance(private_key, basestring):
+      self.private_key = private_key.encode()
+    else:
+      raise TypeError("expected private_key to be of type str or bytes")
+    if isinstance(certificate_chain, bytes):
+      self.certificate_chain = certificate_chain
+    elif isinstance(certificate_chain, basestring):
+      self.certificate_chain = certificate_chain.encode()
+    else:
+      raise TypeError("expected certificate_chain to be of type str or bytes "
+                      "or int")
+    self.c_pair.private_key = self.private_key
+    self.c_pair.certificate_chain = self.certificate_chain
+
+
+cdef class ChannelArg:
+
+  def __cinit__(self, key, value):
+    if isinstance(key, bytes):
+      self.key = key
+    elif isinstance(key, basestring):
+      self.key = key.encode()
+    else:
+      raise TypeError("expected key to be of type str or bytes")
+    if isinstance(value, bytes):
+      self.value = value
+      self.c_arg.type = grpc.GRPC_ARG_STRING
+      self.c_arg.value.string = self.value
+    elif isinstance(value, basestring):
+      self.value = value.encode()
+      self.c_arg.type = grpc.GRPC_ARG_STRING
+      self.c_arg.value.string = self.value
+    elif isinstance(value, int):
+      self.value = int(value)
+      self.c_arg.type = grpc.GRPC_ARG_INTEGER
+      self.c_arg.value.integer = self.value
+    else:
+      raise TypeError("expected value to be of type str or bytes or int")
+    self.c_arg.key = self.key
+
+
+cdef class ChannelArgs:
+
+  def __cinit__(self, args):
+    self.args = list(args)
+    for arg in self.args:
+      if not isinstance(arg, ChannelArg):
+        raise TypeError("expected list of ChannelArg")
+    self.c_args.arguments_length = len(self.args)
+    self.c_args.arguments = <grpc.grpc_arg *>grpc.gpr_malloc(
+        self.c_args.arguments_length*sizeof(grpc.grpc_arg)
+    )
+    for i in range(self.c_args.arguments_length):
+      self.c_args.arguments[i] = (<ChannelArg>self.args[i]).c_arg
+
+  def __dealloc__(self):
+    grpc.gpr_free(self.c_args.arguments)
+
+  def __len__(self):
+    # self.args is never stale; it's only updated from this file
+    return len(self.args)
+
+  def __getitem__(self, size_t i):
+    # self.args is never stale; it's only updated from this file
+    return self.args[i]
+
+
+cdef class Metadatum:
+
+  def __cinit__(self, key, value):
+    if isinstance(key, bytes):
+      self._key = key
+    elif isinstance(key, basestring):
+      self._key = key.encode()
+    else:
+      raise TypeError("expected key to be of type str or bytes")
+    if isinstance(value, bytes):
+      self._value = value
+    elif isinstance(value, basestring):
+      self._value = value.encode()
+    else:
+      raise TypeError("expected value to be of type str or bytes")
+    self.c_metadata.key = self._key
+    self.c_metadata.value = self._value
+    self.c_metadata.value_length = len(self._value)
+
+  @property
+  def key(self):
+    return <bytes>self.c_metadata.key
+
+  @property
+  def value(self):
+    return <bytes>self.c_metadata.value[:self.c_metadata.value_length]
+
+  def __len__(self):
+    return 2
+
+  def __getitem__(self, size_t i):
+    if i == 0:
+      return self.key
+    elif i == 1:
+      return self.value
+    else:
+      raise IndexError("index must be 0 (key) or 1 (value)")
+
+  def __iter__(self):
+    return iter((self.key, self.value))
+
+
+cdef class _MetadataIterator:
+
+  cdef size_t i
+  cdef Metadata metadata
+
+  def __cinit__(self, Metadata metadata not None):
+    self.i = 0
+    self.metadata = metadata
+
+  def __next__(self):
+    if self.i < len(self.metadata):
+      result = self.metadata[self.i]
+      self.i = self.i + 1
+      return result
+    else:
+      raise StopIteration()
+
+
+cdef class Metadata:
+
+  def __cinit__(self, metadata):
+    self.metadata = list(metadata)
+    for metadatum in metadata:
+      if not isinstance(metadatum, Metadatum):
+        raise TypeError("expected list of Metadatum")
+    grpc.grpc_metadata_array_init(&self.c_metadata_array)
+    self.c_metadata_array.count = len(self.metadata)
+    self.c_metadata_array.capacity = len(self.metadata)
+    self.c_metadata_array.metadata = <grpc.grpc_metadata *>grpc.gpr_malloc(
+        self.c_metadata_array.count*sizeof(grpc.grpc_metadata)
+    )
+    for i in range(self.c_metadata_array.count):
+      self.c_metadata_array.metadata[i] = (
+          (<Metadatum>self.metadata[i]).c_metadata)
+
+  def __dealloc__(self):
+    # this frees the allocated memory for the grpc_metadata_array (although
+    # it'd be nice if that were documented somewhere...) TODO(atash): document
+    # this in the C core
+    grpc.grpc_metadata_array_destroy(&self.c_metadata_array)
+
+  def __len__(self):
+    return self.c_metadata_array.count
+
+  def __getitem__(self, size_t i):
+    return Metadatum(
+        key=<bytes>self.c_metadata_array.metadata[i].key,
+        value=<bytes>self.c_metadata_array.metadata[i].value[
+            :self.c_metadata_array.metadata[i].value_length])
+
+  def __iter__(self):
+    return _MetadataIterator(self)
+
+
+cdef class Operation:
+
+  def __cinit__(self):
+    self.references = []
+    self._received_status_details = NULL
+    self._received_status_details_capacity = 0
+    self.is_valid = False
+
+  @property
+  def type(self):
+    return self.c_op.type
+
+  @property
+  def received_message(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
+      raise TypeError("self must be an operation receiving a message")
+    return self._received_message
+
+  @property
+  def received_metadata(self):
+    if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
+        self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
+      raise TypeError("self must be an operation receiving metadata")
+    return self._received_metadata
+
+  @property
+  def received_status_code(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      raise TypeError("self must be an operation receiving a status code")
+    return self._received_status_code
+
+  @property
+  def received_status_details(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      raise TypeError("self must be an operation receiving status details")
+    if self._received_status_details:
+      return self._received_status_details
+    else:
+      return None
+
+  @property
+  def received_cancelled(self):
+    if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
+      raise TypeError("self must be an operation receiving cancellation "
+                      "information")
+    return False if self._received_cancelled == 0 else True
+
+  def __dealloc__(self):
+    # We *almost* don't need to do anything; most of the objects are handled by
+    # Python. The remaining one(s) are primitive fields filled in by GRPC core.
+    # This means that we need to clean up after receive_status_on_client.
+    if self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+      grpc.gpr_free(self._received_status_details)
+
+def operation_send_initial_metadata(Metadata metadata):
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_SEND_INITIAL_METADATA
+  op.c_op.data.send_initial_metadata.count = metadata.c_metadata_array.count
+  op.c_op.data.send_initial_metadata.metadata = (
+      metadata.c_metadata_array.metadata)
+  op.references.append(metadata)
+  op.is_valid = True
+  return op
+
+def operation_send_message(data):
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_SEND_MESSAGE
+  byte_buffer = ByteBuffer(data)
+  op.c_op.data.send_message = byte_buffer.c_byte_buffer
+  op.references.append(byte_buffer)
+  op.is_valid = True
+  return op
+
+def operation_send_close_from_client():
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_SEND_CLOSE_FROM_CLIENT
+  op.is_valid = True
+  return op
+
+def operation_send_status_from_server(
+    Metadata metadata, grpc.grpc_status_code code, details):
+  if isinstance(details, bytes):
+    pass
+  elif isinstance(details, basestring):
+    details = details.encode()
+  else:
+    raise TypeError("expected a str or bytes object for details")
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_SEND_STATUS_FROM_SERVER
+  op.c_op.data.send_status_from_server.trailing_metadata_count = (
+      metadata.c_metadata_array.count)
+  op.c_op.data.send_status_from_server.trailing_metadata = (
+      metadata.c_metadata_array.metadata)
+  op.c_op.data.send_status_from_server.status = code
+  op.c_op.data.send_status_from_server.status_details = details
+  op.references.append(metadata)
+  op.references.append(details)
+  op.is_valid = True
+  return op
+
+def operation_receive_initial_metadata():
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_RECV_INITIAL_METADATA
+  op._received_metadata = Metadata([])
+  op.c_op.data.receive_initial_metadata = (
+      &op._received_metadata.c_metadata_array)
+  op.is_valid = True
+  return op
+
+def operation_receive_message():
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_RECV_MESSAGE
+  op._received_message = ByteBuffer(None)
+  # n.b. the c_op.data.receive_message field needs to be deleted by us,
+  # anyway, so we just let that be handled by the ByteBuffer() we allocated
+  # the line before.
+  op.c_op.data.receive_message = &op._received_message.c_byte_buffer
+  op.is_valid = True
+  return op
+
+def operation_receive_status_on_client():
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+  op._received_metadata = Metadata([])
+  op.c_op.data.receive_status_on_client.trailing_metadata = (
+      &op._received_metadata.c_metadata_array)
+  op.c_op.data.receive_status_on_client.status = (
+      &op._received_status_code)
+  op.c_op.data.receive_status_on_client.status_details = (
+      &op._received_status_details)
+  op.c_op.data.receive_status_on_client.status_details_capacity = (
+      &op._received_status_details_capacity)
+  op.is_valid = True
+  return op
+
+def operation_receive_close_on_server():
+  cdef Operation op = Operation()
+  op.c_op.type = grpc.GRPC_OP_RECV_CLOSE_ON_SERVER
+  op.c_op.data.receive_close_on_server.cancelled = &op._received_cancelled
+  op.is_valid = True
+  return op
+
+
+cdef class _OperationsIterator:
+
+  cdef size_t i
+  cdef Operations operations
+
+  def __cinit__(self, Operations operations not None):
+    self.i = 0
+    self.operations = operations
+
+  def __next__(self):
+    if self.i < len(self.operations):
+      result = self.operations[self.i]
+      self.i = self.i + 1
+      return result
+    else:
+      raise StopIteration()
+
+
+cdef class Operations:
+
+  def __cinit__(self, operations):
+    self.operations = list(operations)  # normalize iterable
+    self.c_ops = NULL
+    self.c_nops = 0
+    for operation in self.operations:
+      if not isinstance(operation, Operation):
+        raise TypeError("expected operations to be iterable of Operation")
+    self.c_nops = len(self.operations)
+    self.c_ops = <grpc.grpc_op *>grpc.gpr_malloc(
+        sizeof(grpc.grpc_op)*self.c_nops)
+    for i in range(self.c_nops):
+      self.c_ops[i] = (<Operation>(self.operations[i])).c_op
+
+  def __len__(self):
+    return self.c_nops
+
+  def __getitem__(self, size_t i):
+    # self.operations is never stale; it's only updated from this file
+    return self.operations[i]
+
+  def __dealloc__(self):
+    grpc.gpr_free(self.c_ops)
+
+  def __iter__(self):
+    return _OperationsIterator(self)
+
diff --git a/src/python/src/grpc/_cython/_cygrpc/server.pxd b/src/python/src/grpc/_cython/_cygrpc/server.pxd
new file mode 100644
index 0000000..0257542
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/server.pxd
@@ -0,0 +1,45 @@
+# 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.
+
+from grpc._cython._cygrpc cimport grpc
+from grpc._cython._cygrpc cimport completion_queue
+
+
+cdef class Server:
+
+  cdef grpc.grpc_server *c_server
+  cdef bint is_started  # start has been called
+  cdef bint is_shutting_down  # shutdown has been called
+  cdef bint is_shutdown  # notification of complete shutdown received
+  # used at dealloc when user forgets to shutdown
+  cdef completion_queue.CompletionQueue backup_shutdown_queue
+  cdef list references
+  cdef list registered_completion_queues
+
+  cdef notify_shutdown_complete(self)
diff --git a/src/python/src/grpc/_cython/_cygrpc/server.pyx b/src/python/src/grpc/_cython/_cygrpc/server.pyx
new file mode 100644
index 0000000..dcf9d38
--- /dev/null
+++ b/src/python/src/grpc/_cython/_cygrpc/server.pyx
@@ -0,0 +1,158 @@
+# 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.
+
+cimport cpython
+
+from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport completion_queue
+from grpc._cython._cygrpc cimport credentials
+from grpc._cython._cygrpc cimport records
+
+import time
+
+
+cdef class Server:
+
+  def __cinit__(self, records.ChannelArgs arguments=None):
+    cdef grpc.grpc_channel_args *c_arguments = NULL
+    self.references = []
+    self.registered_completion_queues = []
+    if arguments is not None:
+      c_arguments = &arguments.c_args
+      self.references.append(arguments)
+    self.c_server = grpc.grpc_server_create(c_arguments)
+    self.is_started = False
+    self.is_shutting_down = False
+    self.is_shutdown = False
+
+  def request_call(
+      self, completion_queue.CompletionQueue call_queue not None,
+      completion_queue.CompletionQueue server_queue not None, tag):
+    if not self.is_started or self.is_shutting_down:
+      raise ValueError("server must be started and not shutting down")
+    if server_queue not in self.registered_completion_queues:
+      raise ValueError("server_queue must be a registered completion queue")
+    cdef records.OperationTag operation_tag = records.OperationTag(tag)
+    operation_tag.operation_call = call.Call()
+    operation_tag.request_call_details = records.CallDetails()
+    operation_tag.request_metadata = records.Metadata([])
+    operation_tag.references.extend([self, call_queue, server_queue])
+    operation_tag.is_new_request = True
+    operation_tag.batch_operations = records.Operations([])
+    cpython.Py_INCREF(operation_tag)
+    return grpc.grpc_server_request_call(
+        self.c_server, &operation_tag.operation_call.c_call,
+        &operation_tag.request_call_details.c_details,
+        &operation_tag.request_metadata.c_metadata_array,
+        call_queue.c_completion_queue, server_queue.c_completion_queue,
+        <cpython.PyObject *>operation_tag)
+
+  def register_completion_queue(
+      self, completion_queue.CompletionQueue queue not None):
+    if self.is_started:
+      raise ValueError("cannot register completion queues after start")
+    grpc.grpc_server_register_completion_queue(
+        self.c_server, queue.c_completion_queue)
+    self.registered_completion_queues.append(queue)
+
+  def start(self):
+    if self.is_started:
+      raise ValueError("the server has already started")
+    self.backup_shutdown_queue = completion_queue.CompletionQueue()
+    self.register_completion_queue(self.backup_shutdown_queue)
+    self.is_started = True
+    grpc.grpc_server_start(self.c_server)
+
+  def add_http2_port(self, address,
+                     credentials.ServerCredentials server_credentials=None):
+    if isinstance(address, bytes):
+      pass
+    elif isinstance(address, basestring):
+      address = address.encode()
+    else:
+      raise TypeError("expected address to be a str or bytes")
+    self.references.append(address)
+    if server_credentials is not None:
+      self.references.append(server_credentials)
+      return grpc.grpc_server_add_secure_http2_port(
+          self.c_server, address, server_credentials.c_credentials)
+    else:
+      return grpc.grpc_server_add_http2_port(self.c_server, address)
+
+  def shutdown(self, completion_queue.CompletionQueue queue not None, tag):
+    cdef records.OperationTag operation_tag
+    if queue.is_shutting_down:
+      raise ValueError("queue must be live")
+    elif not self.is_started:
+      raise ValueError("the server hasn't started yet")
+    elif self.is_shutting_down:
+      return
+    elif queue not in self.registered_completion_queues:
+      raise ValueError("expected registered completion queue")
+    else:
+      self.is_shutting_down = True
+      operation_tag = records.OperationTag(tag)
+      operation_tag.shutting_down_server = self
+      operation_tag.references.extend([self, queue])
+      cpython.Py_INCREF(operation_tag)
+      grpc.grpc_server_shutdown_and_notify(
+          self.c_server, queue.c_completion_queue,
+          <cpython.PyObject *>operation_tag)
+
+  cdef notify_shutdown_complete(self):
+    # called only by a completion queue on receiving our shutdown operation tag
+    self.is_shutdown = True
+
+  def cancel_all_calls(self):
+    if not self.is_shutting_down:
+      raise ValueError("the server must be shutting down to cancel all calls")
+    elif self.is_shutdown:
+      return
+    else:
+      grpc.grpc_server_cancel_all_calls(self.c_server)
+
+  def __dealloc__(self):
+    if self.c_server != NULL:
+      if not self.is_started:
+        pass
+      elif self.is_shutdown:
+        pass
+      elif not self.is_shutting_down:
+        # the user didn't call shutdown - use our backup queue
+        self.shutdown(self.backup_shutdown_queue, None)
+        # and now we wait
+        while not self.is_shutdown:
+          self.backup_shutdown_queue.poll()
+      else:
+        # We're in the process of shutting down, but have not shutdown; can't do
+        # much but repeatedly release the GIL and wait
+        while not self.is_shutdown:
+          time.sleep(0)
+      grpc.grpc_server_destroy(self.c_server)
+
diff --git a/src/python/src/grpc/_cython/adapter_low.py b/src/python/src/grpc/_cython/adapter_low.py
new file mode 100644
index 0000000..7546dd1
--- /dev/null
+++ b/src/python/src/grpc/_cython/adapter_low.py
@@ -0,0 +1,114 @@
+# 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.
+
+
+# Adapter from grpc._cython.types to the surface expected by
+# grpc._adapter._intermediary_low.
+#
+# TODO(atash): Once this is plugged into grpc._adapter._intermediary_low, remove
+# both grpc._adapter._intermediary_low and this file. The fore and rear links in
+# grpc._adapter should be able to use grpc._cython.types directly.
+
+from grpc._adapter import _types as type_interfaces
+from grpc._cython import cygrpc
+
+
+class ClientCredentials(object):
+  def __init__(self):
+    raise NotImplementedError()
+
+  @staticmethod
+  def google_default():
+    raise NotImplementedError()
+
+  @staticmethod
+  def ssl():
+    raise NotImplementedError()
+
+  @staticmethod
+  def composite():
+    raise NotImplementedError()
+
+  @staticmethod
+  def compute_engine():
+    raise NotImplementedError()
+
+  @staticmethod
+  def service_account():
+    raise NotImplementedError()
+
+  @staticmethod
+  def jwt():
+    raise NotImplementedError()
+
+  @staticmethod
+  def refresh_token():
+    raise NotImplementedError()
+
+  @staticmethod
+  def fake_transport_security():
+    raise NotImplementedError()
+
+  @staticmethod
+  def iam():
+    raise NotImplementedError()
+
+
+class ServerCredentials(object):
+  def __init__(self):
+    raise NotImplementedError()
+
+  @staticmethod
+  def ssl():
+    raise NotImplementedError()
+
+  @staticmethod
+  def fake_transport_security():
+    raise NotImplementedError()
+
+
+class CompletionQueue(type_interfaces.CompletionQueue):
+  def __init__(self):
+    raise NotImplementedError()
+
+
+class Call(type_interfaces.Call):
+  def __init__(self):
+    raise NotImplementedError()
+
+
+class Channel(type_interfaces.Channel):
+  def __init__(self):
+    raise NotImplementedError()
+
+
+class Server(type_interfaces.Server):
+  def __init__(self):
+    raise NotImplementedError()
+
diff --git a/src/python/src/grpc/_cython/adapter_low_test.py b/src/python/src/grpc/_cython/adapter_low_test.py
new file mode 100644
index 0000000..9bab930
--- /dev/null
+++ b/src/python/src/grpc/_cython/adapter_low_test.py
@@ -0,0 +1,187 @@
+# 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.
+
+# Fork of grpc._adapter._low_test; the grpc._cython.types adapter in
+# grpc._cython.low should transparently support the semantics expected of
+# grpc._adapter._low.
+
+import time
+import unittest
+
+from grpc._adapter import _types
+from grpc._cython import adapter_low as _low
+
+
+class InsecureServerInsecureClient(unittest.TestCase):
+
+  def setUp(self):
+    self.server_completion_queue = _low.CompletionQueue()
+    self.server = _low.Server(self.server_completion_queue, [])
+    self.port = self.server.add_http2_port('[::]:0')
+    self.client_completion_queue = _low.CompletionQueue()
+    self.client_channel = _low.Channel('localhost:%d'%self.port, [])
+
+    self.server.start()
+
+  def tearDown(self):
+    self.server.shutdown()
+    del self.client_channel
+
+    self.client_completion_queue.shutdown()
+    while (self.client_completion_queue.next().type !=
+               _types.EventType.QUEUE_SHUTDOWN):
+      pass
+    self.server_completion_queue.shutdown()
+    while (self.server_completion_queue.next().type !=
+               _types.EventType.QUEUE_SHUTDOWN):
+      pass
+
+    del self.client_completion_queue
+    del self.server_completion_queue
+    del self.server
+
+  @unittest.skip('TODO(atash): implement grpc._cython.adapter_low')
+  def testEcho(self):
+    DEADLINE = time.time()+5
+    DEADLINE_TOLERANCE = 0.25
+    CLIENT_METADATA_ASCII_KEY = 'key'
+    CLIENT_METADATA_ASCII_VALUE = 'val'
+    CLIENT_METADATA_BIN_KEY = 'key-bin'
+    CLIENT_METADATA_BIN_VALUE = b'\0'*1000
+    SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
+    SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
+    SERVER_TRAILING_METADATA_KEY = 'California_is_in_a_drought'
+    SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
+    SERVER_STATUS_CODE = _types.StatusCode.OK
+    SERVER_STATUS_DETAILS = 'our work is never over'
+    REQUEST = 'in death a member of project mayhem has a name'
+    RESPONSE = 'his name is robert paulson'
+    METHOD = 'twinkies'
+    HOST = 'hostess'
+    server_request_tag = object()
+    request_call_result = self.server.request_call(self.server_completion_queue,
+                                                   server_request_tag)
+
+    self.assertEqual(_types.CallError.OK, request_call_result)
+
+    client_call_tag = object()
+    client_call = self.client_channel.create_call(self.client_completion_queue,
+                                                  METHOD, HOST, DEADLINE)
+    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_close_from_client(),
+        _types.OpArgs.recv_initial_metadata(),
+        _types.OpArgs.recv_message(),
+        _types.OpArgs.recv_status_on_client()
+    ], client_call_tag)
+    self.assertEqual(_types.CallError.OK, client_start_batch_result)
+
+    request_event = self.server_completion_queue.next(DEADLINE)
+    self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type)
+    self.assertIsInstance(request_event.call, _low.Call)
+    self.assertIs(server_request_tag, request_event.tag)
+    self.assertEqual(1, len(request_event.results))
+    self.assertEqual(dict(client_initial_metadata),
+                      dict(request_event.results[0].initial_metadata))
+    self.assertEqual(METHOD, request_event.call_details.method)
+    self.assertEqual(HOST, request_event.call_details.host)
+    self.assertLess(abs(DEADLINE - request_event.call_details.deadline),
+                    DEADLINE_TOLERANCE)
+
+    server_call_tag = object()
+    server_call = request_event.call
+    server_initial_metadata = [
+        (SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE)]
+    server_trailing_metadata = [
+        (SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE)]
+    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.recv_close_on_server(),
+        _types.OpArgs.send_status_from_server(
+            server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
+    ], server_call_tag)
+    self.assertEqual(_types.CallError.OK, server_start_batch_result)
+
+    client_event = self.client_completion_queue.next(DEADLINE)
+    server_event = self.server_completion_queue.next(DEADLINE)
+
+    self.assertEqual(6, len(client_event.results))
+    found_client_op_types = set()
+    for client_result in client_event.results:
+      # we expect each op type to be unique
+      self.assertNotIn(client_result.type, found_client_op_types)
+      found_client_op_types.add(client_result.type)
+      if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
+        self.assertEqual(dict(server_initial_metadata),
+                          dict(client_result.initial_metadata))
+      elif client_result.type == _types.OpType.RECV_MESSAGE:
+        self.assertEqual(RESPONSE, client_result.message)
+      elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
+        self.assertEqual(dict(server_trailing_metadata),
+                          dict(client_result.trailing_metadata))
+        self.assertEqual(SERVER_STATUS_DETAILS, client_result.status.details)
+        self.assertEqual(SERVER_STATUS_CODE, client_result.status.code)
+    self.assertEqual(set([
+          _types.OpType.SEND_INITIAL_METADATA,
+          _types.OpType.SEND_MESSAGE,
+          _types.OpType.SEND_CLOSE_FROM_CLIENT,
+          _types.OpType.RECV_INITIAL_METADATA,
+          _types.OpType.RECV_MESSAGE,
+          _types.OpType.RECV_STATUS_ON_CLIENT
+      ]), found_client_op_types)
+
+    self.assertEqual(5, len(server_event.results))
+    found_server_op_types = set()
+    for server_result in server_event.results:
+      self.assertNotIn(client_result.type, found_server_op_types)
+      found_server_op_types.add(server_result.type)
+      if server_result.type == _types.OpType.RECV_MESSAGE:
+        self.assertEqual(REQUEST, server_result.message)
+      elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
+        self.assertFalse(server_result.cancelled)
+    self.assertEqual(set([
+          _types.OpType.SEND_INITIAL_METADATA,
+          _types.OpType.RECV_MESSAGE,
+          _types.OpType.SEND_MESSAGE,
+          _types.OpType.RECV_CLOSE_ON_SERVER,
+          _types.OpType.SEND_STATUS_FROM_SERVER
+      ]), found_server_op_types)
+
+    del client_call
+    del server_call
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/src/grpc/_cython/cygrpc.pyx b/src/python/src/grpc/_cython/cygrpc.pyx
new file mode 100644
index 0000000..dcb06f3
--- /dev/null
+++ b/src/python/src/grpc/_cython/cygrpc.pyx
@@ -0,0 +1,111 @@
+# 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.
+
+cimport cpython
+
+from grpc._cython._cygrpc cimport grpc
+from grpc._cython._cygrpc cimport call
+from grpc._cython._cygrpc cimport channel
+from grpc._cython._cygrpc cimport credentials
+from grpc._cython._cygrpc cimport completion_queue
+from grpc._cython._cygrpc cimport records
+from grpc._cython._cygrpc cimport server
+
+from grpc._cython._cygrpc import call
+from grpc._cython._cygrpc import channel
+from grpc._cython._cygrpc import credentials
+from grpc._cython._cygrpc import completion_queue
+from grpc._cython._cygrpc import records
+from grpc._cython._cygrpc import server
+
+StatusCode = records.StatusCode
+CallError = records.CallError
+CompletionType = records.CompletionType
+OperationType = records.OperationType
+Timespec = records.Timespec
+CallDetails = records.CallDetails
+Event = records.Event
+ByteBuffer = records.ByteBuffer
+SslPemKeyCertPair = records.SslPemKeyCertPair
+ChannelArg = records.ChannelArg
+ChannelArgs = records.ChannelArgs
+Metadatum = records.Metadatum
+Metadata = records.Metadata
+Operation = records.Operation
+
+operation_send_initial_metadata = records.operation_send_initial_metadata
+operation_send_message = records.operation_send_message
+operation_send_close_from_client = records.operation_send_close_from_client
+operation_send_status_from_server = records.operation_send_status_from_server
+operation_receive_initial_metadata = records.operation_receive_initial_metadata
+operation_receive_message = records.operation_receive_message
+operation_receive_status_on_client = records.operation_receive_status_on_client
+operation_receive_close_on_server = records.operation_receive_close_on_server
+
+Operations = records.Operations
+
+ClientCredentials = credentials.ClientCredentials
+ServerCredentials = credentials.ServerCredentials
+
+client_credentials_google_default = (
+    credentials.client_credentials_google_default)
+client_credentials_ssl = credentials.client_credentials_ssl
+client_credentials_composite_credentials = (
+    credentials.client_credentials_composite_credentials)
+client_credentials_compute_engine = (
+    credentials.client_credentials_compute_engine)
+client_credentials_jwt = credentials.client_credentials_jwt
+client_credentials_refresh_token = credentials.client_credentials_refresh_token
+client_credentials_fake_transport_security = (
+    credentials.client_credentials_fake_transport_security)
+client_credentials_iam = credentials.client_credentials_iam
+server_credentials_ssl = credentials.server_credentials_ssl
+server_credentials_fake_transport_security = (
+    credentials.server_credentials_fake_transport_security)
+
+CompletionQueue = completion_queue.CompletionQueue
+Channel = channel.Channel
+Server = server.Server
+Call = call.Call
+
+
+#
+# Global state
+#
+
+cdef class _ModuleState:
+
+  def __cinit__(self):
+    grpc.grpc_init()
+
+  def __dealloc__(self):
+    grpc.grpc_shutdown()
+
+_module_state = _ModuleState()
+
diff --git a/src/python/src/grpc/_cython/cygrpc_test.py b/src/python/src/grpc/_cython/cygrpc_test.py
new file mode 100644
index 0000000..838e1e2
--- /dev/null
+++ b/src/python/src/grpc/_cython/cygrpc_test.py
@@ -0,0 +1,276 @@
+# 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.
+
+import time
+import unittest
+
+from grpc._cython import cygrpc
+from grpc._cython import test_utilities
+
+
+class TypeSmokeTest(unittest.TestCase):
+
+  def testStringsInUtilitiesUpDown(self):
+    self.assertEqual(0, cygrpc.StatusCode.ok)
+    metadatum = cygrpc.Metadatum('a', 'b')
+    self.assertEqual('a'.encode(), metadatum.key)
+    self.assertEqual('b'.encode(), metadatum.value)
+    metadata = cygrpc.Metadata([metadatum])
+    self.assertEqual(1, len(metadata))
+    self.assertEqual(metadatum.key, metadata[0].key)
+
+  def testMetadataIteration(self):
+    metadata = cygrpc.Metadata([
+        cygrpc.Metadatum('a', 'b'), cygrpc.Metadatum('c', 'd')])
+    iterator = iter(metadata)
+    metadatum = next(iterator)
+    self.assertIsInstance(metadatum, cygrpc.Metadatum)
+    self.assertEqual(metadatum.key, 'a'.encode())
+    self.assertEqual(metadatum.value, 'b'.encode())
+    metadatum = next(iterator)
+    self.assertIsInstance(metadatum, cygrpc.Metadatum)
+    self.assertEqual(metadatum.key, 'c'.encode())
+    self.assertEqual(metadatum.value, 'd'.encode())
+    with self.assertRaises(StopIteration):
+      next(iterator)
+
+  def testOperationsIteration(self):
+    operations = cygrpc.Operations([
+        cygrpc.operation_send_message('asdf')])
+    iterator = iter(operations)
+    operation = next(iterator)
+    self.assertIsInstance(operation, cygrpc.Operation)
+    # `Operation`s are write-only structures; can't directly debug anything out
+    # of them. Just check that we stop iterating.
+    with self.assertRaises(StopIteration):
+      next(iterator)
+
+  def testTimespec(self):
+    now = time.time()
+    timespec = cygrpc.Timespec(now)
+    self.assertAlmostEqual(now, float(timespec), places=8)
+
+  def testClientCredentialsUpDown(self):
+    credentials = cygrpc.client_credentials_fake_transport_security()
+    del credentials
+
+  def testServerCredentialsUpDown(self):
+    credentials = cygrpc.server_credentials_fake_transport_security()
+    del credentials
+
+  def testCompletionQueueUpDown(self):
+    completion_queue = cygrpc.CompletionQueue()
+    del completion_queue
+
+  def testServerUpDown(self):
+    server = cygrpc.Server(cygrpc.ChannelArgs([]))
+    del server
+
+  def testChannelUpDown(self):
+    channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([]))
+    del channel
+
+  def testSecureChannelUpDown(self):
+    channel = cygrpc.Channel(
+        '[::]:0', cygrpc.ChannelArgs([]),
+        cygrpc.client_credentials_fake_transport_security())
+    del channel
+
+  @unittest.skip('TODO(atash): undo skip after #2229 is merged')
+  def testServerStartNoExplicitShutdown(self):
+    server = cygrpc.Server()
+    completion_queue = cygrpc.CompletionQueue()
+    server.register_completion_queue(completion_queue)
+    port = server.add_http2_port('[::]:0')
+    self.assertIsInstance(port, int)
+    server.start()
+    del server
+
+  @unittest.skip('TODO(atash): undo skip after #2229 is merged')
+  def testServerStartShutdown(self):
+    completion_queue = cygrpc.CompletionQueue()
+    server = cygrpc.Server()
+    server.add_http2_port('[::]:0')
+    server.register_completion_queue(completion_queue)
+    server.start()
+    shutdown_tag = object()
+    server.shutdown(completion_queue, shutdown_tag)
+    event = completion_queue.poll()
+    self.assertEqual(cygrpc.CompletionType.operation_complete, event.type)
+    self.assertIs(shutdown_tag, event.tag)
+    del server
+    del completion_queue
+
+
+class InsecureServerInsecureClient(unittest.TestCase):
+
+  def setUp(self):
+    self.server_completion_queue = cygrpc.CompletionQueue()
+    self.server = cygrpc.Server()
+    self.server.register_completion_queue(self.server_completion_queue)
+    self.port = self.server.add_http2_port('[::]:0')
+    self.server.start()
+    self.client_completion_queue = cygrpc.CompletionQueue()
+    self.client_channel = cygrpc.Channel('localhost:{}'.format(self.port))
+
+  def tearDown(self):
+    del self.server
+    del self.client_completion_queue
+    del self.server_completion_queue
+
+  def testEcho(self):
+    DEADLINE = time.time()+5
+    DEADLINE_TOLERANCE = 0.25
+    CLIENT_METADATA_ASCII_KEY = b'key'
+    CLIENT_METADATA_ASCII_VALUE = b'val'
+    CLIENT_METADATA_BIN_KEY = b'key-bin'
+    CLIENT_METADATA_BIN_VALUE = b'\0'*1000
+    SERVER_INITIAL_METADATA_KEY = b'init_me_me_me'
+    SERVER_INITIAL_METADATA_VALUE = b'whodawha?'
+    SERVER_TRAILING_METADATA_KEY = b'California_is_in_a_drought'
+    SERVER_TRAILING_METADATA_VALUE = b'zomg it is'
+    SERVER_STATUS_CODE = cygrpc.StatusCode.ok
+    SERVER_STATUS_DETAILS = b'our work is never over'
+    REQUEST = b'in death a member of project mayhem has a name'
+    RESPONSE = b'his name is robert paulson'
+    METHOD = b'twinkies'
+    HOST = b'hostess'
+
+    cygrpc_deadline = cygrpc.Timespec(DEADLINE)
+
+    server_request_tag = object()
+    request_call_result = self.server.request_call(
+        self.server_completion_queue, self.server_completion_queue,
+        server_request_tag)
+
+    self.assertEqual(cygrpc.CallError.ok, request_call_result)
+
+    client_call_tag = object()
+    client_call = self.client_channel.create_call(self.client_completion_queue,
+                                                  METHOD, HOST, cygrpc_deadline)
+    client_initial_metadata = cygrpc.Metadata([
+        cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY,
+                         CLIENT_METADATA_ASCII_VALUE),
+        cygrpc.Metadatum(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)])
+    client_start_batch_result = client_call.start_batch(cygrpc.Operations([
+        cygrpc.operation_send_initial_metadata(client_initial_metadata),
+        cygrpc.operation_send_message(REQUEST),
+        cygrpc.operation_send_close_from_client(),
+        cygrpc.operation_receive_initial_metadata(),
+        cygrpc.operation_receive_message(),
+        cygrpc.operation_receive_status_on_client()
+    ]), client_call_tag)
+    self.assertEqual(cygrpc.CallError.ok, client_start_batch_result)
+    client_event_future = test_utilities.CompletionQueuePollFuture(
+        self.client_completion_queue, cygrpc_deadline)
+
+    request_event = self.server_completion_queue.poll(cygrpc_deadline)
+    self.assertEqual(cygrpc.CompletionType.operation_complete,
+                      request_event.type)
+    self.assertIsInstance(request_event.operation_call, cygrpc.Call)
+    self.assertIs(server_request_tag, request_event.tag)
+    self.assertEqual(0, len(request_event.batch_operations))
+    self.assertEqual(dict(client_initial_metadata),
+                      dict(request_event.request_metadata))
+    self.assertEqual(METHOD, request_event.request_call_details.method)
+    self.assertEqual(HOST, request_event.request_call_details.host)
+    self.assertLess(
+        abs(DEADLINE - float(request_event.request_call_details.deadline)),
+        DEADLINE_TOLERANCE)
+
+    server_call_tag = object()
+    server_call = request_event.operation_call
+    server_initial_metadata = cygrpc.Metadata([
+        cygrpc.Metadatum(SERVER_INITIAL_METADATA_KEY,
+                         SERVER_INITIAL_METADATA_VALUE)])
+    server_trailing_metadata = cygrpc.Metadata([
+        cygrpc.Metadatum(SERVER_TRAILING_METADATA_KEY,
+                         SERVER_TRAILING_METADATA_VALUE)])
+    server_start_batch_result = server_call.start_batch([
+        cygrpc.operation_send_initial_metadata(server_initial_metadata),
+        cygrpc.operation_receive_message(),
+        cygrpc.operation_send_message(RESPONSE),
+        cygrpc.operation_receive_close_on_server(),
+        cygrpc.operation_send_status_from_server(
+            server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
+    ], server_call_tag)
+    self.assertEqual(cygrpc.CallError.ok, server_start_batch_result)
+
+    client_event = client_event_future.result()
+    server_event = self.server_completion_queue.poll(cygrpc_deadline)
+
+    self.assertEqual(6, len(client_event.batch_operations))
+    found_client_op_types = set()
+    for client_result in client_event.batch_operations:
+      # we expect each op type to be unique
+      self.assertNotIn(client_result.type, found_client_op_types)
+      found_client_op_types.add(client_result.type)
+      if client_result.type == cygrpc.OperationType.receive_initial_metadata:
+        self.assertEqual(dict(server_initial_metadata),
+                         dict(client_result.received_metadata))
+      elif client_result.type == cygrpc.OperationType.receive_message:
+        self.assertEqual(RESPONSE, client_result.received_message.bytes())
+      elif client_result.type == cygrpc.OperationType.receive_status_on_client:
+        self.assertEqual(dict(server_trailing_metadata),
+                         dict(client_result.received_metadata))
+        self.assertEqual(SERVER_STATUS_DETAILS,
+                         client_result.received_status_details)
+        self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code)
+    self.assertEqual(set([
+          cygrpc.OperationType.send_initial_metadata,
+          cygrpc.OperationType.send_message,
+          cygrpc.OperationType.send_close_from_client,
+          cygrpc.OperationType.receive_initial_metadata,
+          cygrpc.OperationType.receive_message,
+          cygrpc.OperationType.receive_status_on_client
+      ]), found_client_op_types)
+
+    self.assertEqual(5, len(server_event.batch_operations))
+    found_server_op_types = set()
+    for server_result in server_event.batch_operations:
+      self.assertNotIn(client_result.type, found_server_op_types)
+      found_server_op_types.add(server_result.type)
+      if server_result.type == cygrpc.OperationType.receive_message:
+        self.assertEqual(REQUEST, server_result.received_message.bytes())
+      elif server_result.type == cygrpc.OperationType.receive_close_on_server:
+        self.assertFalse(server_result.received_cancelled)
+    self.assertEqual(set([
+          cygrpc.OperationType.send_initial_metadata,
+          cygrpc.OperationType.receive_message,
+          cygrpc.OperationType.send_message,
+          cygrpc.OperationType.receive_close_on_server,
+          cygrpc.OperationType.send_status_from_server
+      ]), found_server_op_types)
+
+    del client_call
+    del server_call
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/src/grpc/_cython/test_utilities.py b/src/python/src/grpc/_cython/test_utilities.py
new file mode 100644
index 0000000..21ea307
--- /dev/null
+++ b/src/python/src/grpc/_cython/test_utilities.py
@@ -0,0 +1,46 @@
+# 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.
+
+import threading
+
+from grpc._cython._cygrpc import completion_queue
+
+
+class CompletionQueuePollFuture:
+
+  def __init__(self, completion_queue, deadline):
+    def poller_function():
+      self._event_result = completion_queue.poll(deadline)
+    self._event_result = None
+    self._thread = threading.Thread(target=poller_function)
+    self._thread.start()
+
+  def result(self):
+    self._thread.join()
+    return self._event_result
diff --git a/src/python/src/grpc/_links/__init__.py b/src/python/src/grpc/_links/__init__.py
new file mode 100644
index 0000000..7086519
--- /dev/null
+++ b/src/python/src/grpc/_links/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/src/grpc/_links/_lonely_invocation_link_test.py b/src/python/src/grpc/_links/_lonely_invocation_link_test.py
new file mode 100644
index 0000000..3d629f4
--- /dev/null
+++ b/src/python/src/grpc/_links/_lonely_invocation_link_test.py
@@ -0,0 +1,88 @@
+# 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.
+
+"""A test of invocation-side code unconnected to an RPC server."""
+
+import unittest
+
+from grpc._adapter import _intermediary_low
+from grpc._links import invocation
+from grpc.framework.common import test_constants
+from grpc.framework.interfaces.links import links
+from grpc.framework.interfaces.links import test_cases
+from grpc.framework.interfaces.links import test_utilities
+
+_NULL_BEHAVIOR = lambda unused_argument: None
+
+
+class LonelyInvocationLinkTest(unittest.TestCase):
+
+  def testUpAndDown(self):
+    channel = _intermediary_low.Channel('nonexistent:54321', None)
+    invocation_link = invocation.invocation_link(channel, 'nonexistent', {}, {})
+
+    invocation_link.start()
+    invocation_link.stop()
+
+  def _test_lonely_invocation_with_termination(self, termination):
+    test_operation_id = object()
+    test_group = 'test package.Test Service'
+    test_method = 'test method'
+    invocation_link_mate = test_utilities.RecordingLink()
+
+    channel = _intermediary_low.Channel('nonexistent:54321', None)
+    invocation_link = invocation.invocation_link(
+        channel, 'nonexistent', {(test_group, test_method): _NULL_BEHAVIOR},
+        {(test_group, test_method): _NULL_BEHAVIOR})
+    invocation_link.join_link(invocation_link_mate)
+    invocation_link.start()
+
+    ticket = links.Ticket(
+        test_operation_id, 0, test_group, test_method,
+        links.Ticket.Subscription.FULL, test_constants.SHORT_TIMEOUT, 1, None,
+        None, None, None, None, termination)
+    invocation_link.accept_ticket(ticket)
+    invocation_link_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    invocation_link.stop()
+
+    self.assertIsNot(
+        invocation_link_mate.tickets()[-1].termination,
+        links.Ticket.Termination.COMPLETION)
+
+  def testLonelyInvocationLinkWithCommencementTicket(self):
+    self._test_lonely_invocation_with_termination(None)
+
+  def testLonelyInvocationLinkWithEntireTicket(self):
+    self._test_lonely_invocation_with_termination(
+        links.Ticket.Termination.COMPLETION)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/python/src/grpc/_links/_proto_scenarios.py b/src/python/src/grpc/_links/_proto_scenarios.py
new file mode 100644
index 0000000..ccf3c29
--- /dev/null
+++ b/src/python/src/grpc/_links/_proto_scenarios.py
@@ -0,0 +1,261 @@
+# 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 scenarios using protocol buffers."""
+
+import abc
+import threading
+
+from grpc._junkdrawer import math_pb2
+
+
+class ProtoScenario(object):
+  """An RPC test scenario using protocol buffers."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def group_and_method(self):
+    """Access the test group and method.
+
+    Returns:
+      The test group and method as a pair.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def serialize_request(self, request):
+    """Serialize a request protocol buffer.
+
+    Args:
+      request: A request protocol buffer.
+
+    Returns:
+      The bytestring serialization of the given request protocol buffer.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def deserialize_request(self, request_bytestring):
+    """Deserialize a request protocol buffer.
+
+    Args:
+      request_bytestring: The bytestring serialization of a request protocol
+        buffer.
+
+    Returns:
+      The request protocol buffer deserialized from the given byte string.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def serialize_response(self, response):
+    """Serialize a response protocol buffer.
+
+    Args:
+      response: A response protocol buffer.
+
+    Returns:
+      The bytestring serialization of the given response protocol buffer.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def deserialize_response(self, response_bytestring):
+    """Deserialize a response protocol buffer.
+
+    Args:
+      response_bytestring: The bytestring serialization of a response protocol
+        buffer.
+
+    Returns:
+      The response protocol buffer deserialized from the given byte string.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def requests(self):
+    """Access the sequence of requests for this scenario.
+
+    Returns:
+      A sequence of request protocol buffers.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def response_for_request(self, request):
+    """Access the response for a particular request.
+
+    Args:
+      request: A request protocol buffer.
+
+    Returns:
+      The response protocol buffer appropriate for the given request.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def verify_requests(self, experimental_requests):
+    """Verify the requests transmitted through the system under test.
+
+    Args:
+      experimental_requests: The request protocol buffers transmitted through
+        the system under test.
+
+    Returns:
+      True if the requests satisfy this test scenario; False otherwise.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def verify_responses(self, experimental_responses):
+    """Verify the responses transmitted through the system under test.
+
+    Args:
+      experimental_responses: The response protocol buffers transmitted through
+        the system under test.
+
+    Returns:
+      True if the responses satisfy this test scenario; False otherwise.
+    """
+    raise NotImplementedError()
+
+
+class EmptyScenario(ProtoScenario):
+  """A scenario that transmits no protocol buffers in either direction."""
+
+  def group_and_method(self):
+    return 'math.Math', 'DivMany'
+
+  def serialize_request(self, request):
+    raise ValueError('This should not be necessary to call!')
+
+  def deserialize_request(self, request_bytestring):
+    raise ValueError('This should not be necessary to call!')
+
+  def serialize_response(self, response):
+    raise ValueError('This should not be necessary to call!')
+
+  def deserialize_response(self, response_bytestring):
+    raise ValueError('This should not be necessary to call!')
+
+  def requests(self):
+    return ()
+
+  def response_for_request(self, request):
+    raise ValueError('This should not be necessary to call!')
+
+  def verify_requests(self, experimental_requests):
+    return not experimental_requests
+
+  def verify_responses(self, experimental_responses):
+    return not experimental_responses
+
+
+class BidirectionallyUnaryScenario(ProtoScenario):
+  """A scenario that transmits no protocol buffers in either direction."""
+
+  _DIVIDEND = 59
+  _DIVISOR = 7
+  _QUOTIENT = 8
+  _REMAINDER = 3
+
+  _REQUEST = math_pb2.DivArgs(dividend=_DIVIDEND, divisor=_DIVISOR)
+  _RESPONSE = math_pb2.DivReply(quotient=_QUOTIENT, remainder=_REMAINDER)
+
+  def group_and_method(self):
+    return 'math.Math', 'Div'
+
+  def serialize_request(self, request):
+    return request.SerializeToString()
+
+  def deserialize_request(self, request_bytestring):
+    return math_pb2.DivArgs.FromString(request_bytestring)
+
+  def serialize_response(self, response):
+    return response.SerializeToString()
+
+  def deserialize_response(self, response_bytestring):
+    return math_pb2.DivReply.FromString(response_bytestring)
+
+  def requests(self):
+    return [self._REQUEST]
+
+  def response_for_request(self, request):
+    return self._RESPONSE
+
+  def verify_requests(self, experimental_requests):
+    return tuple(experimental_requests) == (self._REQUEST,)
+
+  def verify_responses(self, experimental_responses):
+    return tuple(experimental_responses) == (self._RESPONSE,)
+
+
+class BidirectionallyStreamingScenario(ProtoScenario):
+  """A scenario that transmits no protocol buffers in either direction."""
+
+  _STREAM_LENGTH = 200
+  _REQUESTS = tuple(
+      math_pb2.DivArgs(dividend=59 + index, divisor=7 + index)
+      for index in range(_STREAM_LENGTH))
+
+  def __init__(self):
+    self._lock = threading.Lock()
+    self._responses = []
+
+  def group_and_method(self):
+    return 'math.Math', 'DivMany'
+
+  def serialize_request(self, request):
+    return request.SerializeToString()
+
+  def deserialize_request(self, request_bytestring):
+    return math_pb2.DivArgs.FromString(request_bytestring)
+
+  def serialize_response(self, response):
+    return response.SerializeToString()
+
+  def deserialize_response(self, response_bytestring):
+    return math_pb2.DivReply.FromString(response_bytestring)
+
+  def requests(self):
+    return self._REQUESTS
+
+  def response_for_request(self, request):
+    quotient, remainder = divmod(request.dividend, request.divisor)
+    response = math_pb2.DivReply(quotient=quotient, remainder=remainder)
+    with self._lock:
+      self._responses.append(response)
+    return response
+
+  def verify_requests(self, experimental_requests):
+    return tuple(experimental_requests) == self._REQUESTS
+
+  def verify_responses(self, experimental_responses):
+    with self._lock:
+      return tuple(experimental_responses) == tuple(self._responses)
diff --git a/src/python/src/grpc/_links/_transmission_test.py b/src/python/src/grpc/_links/_transmission_test.py
new file mode 100644
index 0000000..c5ef1ed
--- /dev/null
+++ b/src/python/src/grpc/_links/_transmission_test.py
@@ -0,0 +1,226 @@
+# 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.
+
+"""Tests transmission of tickets across gRPC-on-the-wire."""
+
+import unittest
+
+from grpc._adapter import _intermediary_low
+from grpc._links import _proto_scenarios
+from grpc._links import invocation
+from grpc._links import service
+from grpc.framework.common import test_constants
+from grpc.framework.interfaces.links import links
+from grpc.framework.interfaces.links import test_cases
+from grpc.framework.interfaces.links import test_utilities
+
+_IDENTITY = lambda x: x
+
+
+class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
+
+  def create_transmitting_links(self):
+    service_link = service.service_link(
+        {self.group_and_method(): self.deserialize_request},
+        {self.group_and_method(): self.serialize_response})
+    port = service_link.add_port(0, None)
+    service_link.start()
+    channel = _intermediary_low.Channel('localhost:%d' % port, None)
+    invocation_link = invocation.invocation_link(
+        channel, 'localhost',
+        {self.group_and_method(): self.serialize_request},
+        {self.group_and_method(): self.deserialize_response})
+    invocation_link.start()
+    return invocation_link, service_link
+
+  def destroy_transmitting_links(self, invocation_side_link, service_side_link):
+    invocation_side_link.stop()
+    service_side_link.stop_gracefully()
+
+  def create_invocation_initial_metadata(self):
+    return (
+        ('first invocation initial metadata key', 'just a string value'),
+        ('second invocation initial metadata key', '0123456789'),
+        ('third invocation initial metadata key-bin', '\x00\x57' * 100),
+    )
+
+  def create_invocation_terminal_metadata(self):
+    return None
+
+  def create_service_initial_metadata(self):
+    return (
+        ('first service initial metadata key', 'just another string value'),
+        ('second service initial metadata key', '9876543210'),
+        ('third service initial metadata key-bin', '\x00\x59\x02' * 100),
+    )
+
+  def create_service_terminal_metadata(self):
+    return (
+        ('first service terminal metadata key', 'yet another string value'),
+        ('second service terminal metadata key', 'abcdefghij'),
+        ('third service terminal metadata key-bin', '\x00\x37' * 100),
+    )
+
+  def create_invocation_completion(self):
+    return None, None
+
+  def create_service_completion(self):
+    return _intermediary_low.Code.OK, 'An exuberant test "details" message!'
+
+  def assertMetadataEqual(self, original_metadata, transmitted_metadata):
+    self.assertSequenceEqual(original_metadata, transmitted_metadata)
+
+
+class RoundTripTest(unittest.TestCase):
+
+  def testZeroMessageRoundTrip(self):
+    test_operation_id = object()
+    test_group = 'test package.Test Group'
+    test_method = 'test method'
+    identity_transformation = {(test_group, test_method): _IDENTITY}
+    test_code = _intermediary_low.Code.OK
+    test_message = 'a test message'
+
+    service_link = service.service_link(
+        identity_transformation, identity_transformation)
+    service_mate = test_utilities.RecordingLink()
+    service_link.join_link(service_mate)
+    port = service_link.add_port(0, None)
+    service_link.start()
+    channel = _intermediary_low.Channel('localhost:%d' % port, None)
+    invocation_link = invocation.invocation_link(
+        channel, 'localhost', identity_transformation, identity_transformation)
+    invocation_mate = test_utilities.RecordingLink()
+    invocation_link.join_link(invocation_mate)
+    invocation_link.start()
+
+    invocation_ticket = links.Ticket(
+        test_operation_id, 0, test_group, test_method,
+        links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
+        None, None, None, None, links.Ticket.Termination.COMPLETION)
+    invocation_link.accept_ticket(invocation_ticket)
+    service_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    service_ticket = links.Ticket(
+        service_mate.tickets()[-1].operation_id, 0, None, None, None, None,
+        None, None, None, None, test_code, test_message,
+        links.Ticket.Termination.COMPLETION)
+    service_link.accept_ticket(service_ticket)
+    invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    invocation_link.stop()
+    service_link.stop_gracefully()
+
+    self.assertIs(
+        service_mate.tickets()[-1].termination,
+        links.Ticket.Termination.COMPLETION)
+    self.assertIs(
+        invocation_mate.tickets()[-1].termination,
+        links.Ticket.Termination.COMPLETION)
+
+  def _perform_scenario_test(self, scenario):
+    test_operation_id = object()
+    test_group, test_method = scenario.group_and_method()
+    test_code = _intermediary_low.Code.OK
+    test_message = 'a scenario test message'
+
+    service_link = service.service_link(
+        {(test_group, test_method): scenario.deserialize_request},
+        {(test_group, test_method): scenario.serialize_response})
+    service_mate = test_utilities.RecordingLink()
+    service_link.join_link(service_mate)
+    port = service_link.add_port(0, None)
+    service_link.start()
+    channel = _intermediary_low.Channel('localhost:%d' % port, None)
+    invocation_link = invocation.invocation_link(
+        channel, 'localhost',
+        {(test_group, test_method): scenario.serialize_request},
+        {(test_group, test_method): scenario.deserialize_response})
+    invocation_mate = test_utilities.RecordingLink()
+    invocation_link.join_link(invocation_mate)
+    invocation_link.start()
+
+    invocation_ticket = links.Ticket(
+        test_operation_id, 0, test_group, test_method,
+        links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
+        None, None, None, None, None)
+    invocation_link.accept_ticket(invocation_ticket)
+    requests = scenario.requests()
+    for request_index, request in enumerate(requests):
+      request_ticket = links.Ticket(
+          test_operation_id, 1 + request_index, None, None, None, None, 1, None,
+          request, None, None, None, None)
+      invocation_link.accept_ticket(request_ticket)
+      service_mate.block_until_tickets_satisfy(
+          test_cases.at_least_n_payloads_received_predicate(1 + request_index))
+      response_ticket = links.Ticket(
+          service_mate.tickets()[0].operation_id, request_index, None, None,
+          None, None, 1, None, scenario.response_for_request(request), None,
+          None, None, None)
+      service_link.accept_ticket(response_ticket)
+      invocation_mate.block_until_tickets_satisfy(
+          test_cases.at_least_n_payloads_received_predicate(1 + request_index))
+    request_count = len(requests)
+    invocation_completion_ticket = links.Ticket(
+        test_operation_id, request_count + 1, None, None, None, None, None,
+        None, None, None, None, None, links.Ticket.Termination.COMPLETION)
+    invocation_link.accept_ticket(invocation_completion_ticket)
+    service_mate.block_until_tickets_satisfy(test_cases.terminated)
+    service_completion_ticket = links.Ticket(
+        service_mate.tickets()[0].operation_id, request_count, None, None, None,
+        None, None, None, None, None, test_code, test_message,
+        links.Ticket.Termination.COMPLETION)
+    service_link.accept_ticket(service_completion_ticket)
+    invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    invocation_link.stop()
+    service_link.stop_gracefully()
+
+    observed_requests = tuple(
+        ticket.payload for ticket in service_mate.tickets()
+        if ticket.payload is not None)
+    observed_responses = tuple(
+        ticket.payload for ticket in invocation_mate.tickets()
+        if ticket.payload is not None)
+    self.assertTrue(scenario.verify_requests(observed_requests))
+    self.assertTrue(scenario.verify_responses(observed_responses))
+
+  def testEmptyScenario(self):
+    self._perform_scenario_test(_proto_scenarios.EmptyScenario())
+
+  def testBidirectionallyUnaryScenario(self):
+    self._perform_scenario_test(_proto_scenarios.BidirectionallyUnaryScenario())
+
+  def testBidirectionallyStreamingScenario(self):
+    self._perform_scenario_test(
+        _proto_scenarios.BidirectionallyStreamingScenario())
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/src/grpc/_links/invocation.py b/src/python/src/grpc/_links/invocation.py
new file mode 100644
index 0000000..0058ae9
--- /dev/null
+++ b/src/python/src/grpc/_links/invocation.py
@@ -0,0 +1,363 @@
+# 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 RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire."""
+
+import abc
+import enum
+import logging
+import threading
+import time
+
+from grpc._adapter import _intermediary_low
+from grpc.framework.foundation import activated
+from grpc.framework.foundation import logging_pool
+from grpc.framework.foundation import relay
+from grpc.framework.interfaces.links import links
+
+
+@enum.unique
+class _Read(enum.Enum):
+  AWAITING_METADATA = 'awaiting metadata'
+  READING = 'reading'
+  AWAITING_ALLOWANCE = 'awaiting allowance'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _HighWrite(enum.Enum):
+  OPEN = 'open'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _LowWrite(enum.Enum):
+  OPEN = 'OPEN'
+  ACTIVE = 'ACTIVE'
+  CLOSED = 'CLOSED'
+
+
+class _RPCState(object):
+
+  def __init__(
+      self, call, request_serializer, response_deserializer, sequence_number,
+      read, allowance, high_write, low_write):
+    self.call = call
+    self.request_serializer = request_serializer
+    self.response_deserializer = response_deserializer
+    self.sequence_number = sequence_number
+    self.read = read
+    self.allowance = allowance
+    self.high_write = high_write
+    self.low_write = low_write
+
+
+class _Kernel(object):
+
+  def __init__(
+      self, channel, host, request_serializers, response_deserializers,
+      ticket_relay):
+    self._lock = threading.Lock()
+    self._channel = channel
+    self._host = host
+    self._request_serializers = request_serializers
+    self._response_deserializers = response_deserializers
+    self._relay = ticket_relay
+
+    self._completion_queue = None
+    self._rpc_states = None
+    self._pool = None
+
+  def _on_write_event(self, operation_id, unused_event, rpc_state):
+    if rpc_state.high_write is _HighWrite.CLOSED:
+      rpc_state.call.complete(operation_id)
+      rpc_state.low_write = _LowWrite.CLOSED
+    else:
+      ticket = links.Ticket(
+          operation_id, rpc_state.sequence_number, None, None, None, None, 1,
+          None, None, None, None, None, None)
+      rpc_state.sequence_number += 1
+      self._relay.add_value(ticket)
+      rpc_state.low_write = _LowWrite.OPEN
+
+  def _on_read_event(self, operation_id, event, rpc_state):
+    if event.bytes is None:
+      rpc_state.read = _Read.CLOSED
+    else:
+      if 0 < rpc_state.allowance:
+        rpc_state.allowance -= 1
+        rpc_state.call.read(operation_id)
+      else:
+        rpc_state.read = _Read.AWAITING_ALLOWANCE
+      ticket = links.Ticket(
+          operation_id, rpc_state.sequence_number, None, None, None, None, None,
+          None, rpc_state.response_deserializer(event.bytes), None, None, None,
+          None)
+      rpc_state.sequence_number += 1
+      self._relay.add_value(ticket)
+
+  def _on_metadata_event(self, operation_id, event, rpc_state):
+    rpc_state.allowance -= 1
+    rpc_state.call.read(operation_id)
+    rpc_state.read = _Read.READING
+    ticket = links.Ticket(
+        operation_id, rpc_state.sequence_number, None, None,
+        links.Ticket.Subscription.FULL, None, None, event.metadata, None, None,
+        None, None, None)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _on_finish_event(self, operation_id, event, rpc_state):
+    self._rpc_states.pop(operation_id, None)
+    if event.status.code is _intermediary_low.Code.OK:
+      termination = links.Ticket.Termination.COMPLETION
+    elif event.status.code is _intermediary_low.Code.CANCELLED:
+      termination = links.Ticket.Termination.CANCELLATION
+    elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+      termination = links.Ticket.Termination.EXPIRATION
+    else:
+      termination = links.Ticket.Termination.TRANSMISSION_FAILURE
+    ticket = links.Ticket(
+        operation_id, rpc_state.sequence_number, None, None, None, None, None,
+        None, None, event.metadata, event.status.code, event.status.details,
+        termination)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _spin(self, completion_queue):
+    while True:
+      event = completion_queue.get(None)
+      if event.kind is _intermediary_low.Event.Kind.STOP:
+        return
+      operation_id = event.tag
+      with self._lock:
+        if self._completion_queue is None:
+          continue
+        rpc_state = self._rpc_states.get(operation_id)
+        if rpc_state is not None:
+          if event.kind is _intermediary_low.Event.Kind.WRITE_ACCEPTED:
+            self._on_write_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.METADATA_ACCEPTED:
+            self._on_metadata_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.READ_ACCEPTED:
+            self._on_read_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.FINISH:
+            self._on_finish_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.COMPLETE_ACCEPTED:
+            pass
+          else:
+            logging.error('Illegal RPC event! %s', (event,))
+
+  def _invoke(
+      self, operation_id, group, method, initial_metadata, payload, termination,
+      timeout, allowance):
+    """Invoke an RPC.
+
+    Args:
+      operation_id: Any object to be used as an operation ID for the RPC.
+      group: The group to which the RPC method belongs.
+      method: The RPC method name.
+      initial_metadata: The initial metadata object for the RPC.
+      payload: A payload object for the RPC or None if no payload was given at
+        invocation-time.
+      termination: A links.Ticket.Termination value or None indicated whether or
+        not more writes will follow from this side of the RPC.
+      timeout: A duration of time in seconds to allow for the RPC.
+      allowance: The number of payloads (beyond the free first one) that the
+        local ticket exchange mate has granted permission to be read.
+    """
+    if termination is links.Ticket.Termination.COMPLETION:
+      high_write = _HighWrite.CLOSED
+    elif termination is None:
+      high_write = _HighWrite.OPEN
+    else:
+      return
+
+    request_serializer = self._request_serializers.get((group, method))
+    response_deserializer = self._response_deserializers.get((group, method))
+    if request_serializer is None or response_deserializer is None:
+      cancellation_ticket = links.Ticket(
+          operation_id, 0, None, None, None, None, None, None, None, None, None,
+          None, links.Ticket.Termination.CANCELLATION)
+      self._relay.add_value(cancellation_ticket)
+      return
+
+    call = _intermediary_low.Call(
+        self._channel, self._completion_queue, '/%s/%s' % (group, method),
+        self._host, time.time() + timeout)
+    if initial_metadata is not None:
+      for metadata_key, metadata_value in initial_metadata:
+        call.add_metadata(metadata_key, metadata_value)
+    call.invoke(self._completion_queue, operation_id, operation_id)
+    if payload is None:
+      if high_write is _HighWrite.CLOSED:
+        call.complete(operation_id)
+        low_write = _LowWrite.CLOSED
+      else:
+        low_write = _LowWrite.OPEN
+    else:
+      call.write(request_serializer(payload), operation_id)
+      low_write = _LowWrite.ACTIVE
+    self._rpc_states[operation_id] = _RPCState(
+        call, request_serializer, response_deserializer, 0,
+        _Read.AWAITING_METADATA, 1 if allowance is None else (1 + allowance),
+        high_write, low_write)
+
+  def _advance(self, operation_id, rpc_state, payload, termination, allowance):
+    if payload is not None:
+      rpc_state.call.write(rpc_state.request_serializer(payload), operation_id)
+      rpc_state.low_write = _LowWrite.ACTIVE
+
+    if allowance is not None:
+      if rpc_state.read is _Read.AWAITING_ALLOWANCE:
+        rpc_state.allowance += allowance - 1
+        rpc_state.call.read(operation_id)
+        rpc_state.read = _Read.READING
+      else:
+        rpc_state.allowance += allowance
+
+    if termination is links.Ticket.Termination.COMPLETION:
+      rpc_state.high_write = _HighWrite.CLOSED
+      if rpc_state.low_write is _LowWrite.OPEN:
+        rpc_state.call.complete(operation_id)
+        rpc_state.low_write = _LowWrite.CLOSED
+    elif termination is not None:
+      rpc_state.call.cancel()
+
+  def add_ticket(self, ticket):
+    with self._lock:
+      if self._completion_queue is None:
+        return
+      if ticket.sequence_number == 0:
+        self._invoke(
+            ticket.operation_id, ticket.group, ticket.method,
+            ticket.initial_metadata, ticket.payload, ticket.termination,
+            ticket.timeout, ticket.allowance)
+      else:
+        rpc_state = self._rpc_states.get(ticket.operation_id)
+        if rpc_state is not None:
+          self._advance(
+              ticket.operation_id, rpc_state, ticket.payload,
+              ticket.termination, ticket.allowance)
+
+  def start(self):
+    """Starts this object.
+
+    This method must be called before attempting to exchange tickets with this
+    object.
+    """
+    with self._lock:
+      self._completion_queue = _intermediary_low.CompletionQueue()
+      self._rpc_states = {}
+      self._pool = logging_pool.pool(1)
+      self._pool.submit(self._spin, self._completion_queue)
+
+  def stop(self):
+    """Stops this object.
+
+    This method must be called for proper termination of this object, and no
+    attempts to exchange tickets with this object may be made after this method
+    has been called.
+    """
+    with self._lock:
+      self._completion_queue.stop()
+      self._completion_queue = None
+      pool = self._pool
+      self._pool = None
+      self._rpc_states = None
+    pool.shutdown(wait=True)
+
+
+class InvocationLink(links.Link, activated.Activated):
+  """A links.Link for use on the invocation-side of a gRPC connection.
+
+  Implementations of this interface are only valid for use when activated.
+  """
+  __metaclass__ = abc.ABCMeta
+
+
+class _InvocationLink(InvocationLink):
+
+  def __init__(
+      self, channel, host, request_serializers, response_deserializers):
+    self._relay = relay.relay(None)
+    self._kernel = _Kernel(
+        channel, host, request_serializers, response_deserializers, self._relay)
+
+  def _start(self):
+    self._relay.start()
+    self._kernel.start()
+    return self
+
+  def _stop(self):
+    self._kernel.stop()
+    self._relay.stop()
+
+  def accept_ticket(self, ticket):
+    """See links.Link.accept_ticket for specification."""
+    self._kernel.add_ticket(ticket)
+
+  def join_link(self, link):
+    """See links.Link.join_link for specification."""
+    self._relay.set_behavior(link.accept_ticket)
+
+  def __enter__(self):
+    """See activated.Activated.__enter__ for specification."""
+    return self._start()
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """See activated.Activated.__exit__ for specification."""
+    self._stop()
+    return False
+
+  def start(self):
+    """See activated.Activated.start for specification."""
+    return self._start()
+
+  def stop(self):
+    """See activated.Activated.stop for specification."""
+    self._stop()
+
+
+def invocation_link(channel, host, request_serializers, response_deserializers):
+  """Creates an InvocationLink.
+
+  Args:
+    channel: A channel for use by the link.
+    host: The host to specify when invoking RPCs.
+    request_serializers: A dict from group-method pair to request object
+      serialization behavior.
+    response_deserializers: A dict from group-method pair to response object
+      deserialization behavior.
+
+  Returns:
+    An InvocationLink.
+  """
+  return _InvocationLink(
+      channel, host, request_serializers, response_deserializers)
diff --git a/src/python/src/grpc/_links/service.py b/src/python/src/grpc/_links/service.py
new file mode 100644
index 0000000..7783e91
--- /dev/null
+++ b/src/python/src/grpc/_links/service.py
@@ -0,0 +1,402 @@
+# 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 RPC-service-side bridge between RPC Framework and GRPC-on-the-wire."""
+
+import abc
+import enum
+import logging
+import threading
+import time
+
+from grpc._adapter import _intermediary_low
+from grpc.framework.foundation import logging_pool
+from grpc.framework.foundation import relay
+from grpc.framework.interfaces.links import links
+
+
+@enum.unique
+class _Read(enum.Enum):
+  READING = 'reading'
+  AWAITING_ALLOWANCE = 'awaiting allowance'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _HighWrite(enum.Enum):
+  OPEN = 'open'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _LowWrite(enum.Enum):
+  """The possible categories of low-level write state."""
+
+  OPEN = 'OPEN'
+  ACTIVE = 'ACTIVE'
+  CLOSED = 'CLOSED'
+
+
+class _RPCState(object):
+
+  def __init__(
+      self, request_deserializer, response_serializer, sequence_number, 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
+    self.allowance = allowance
+    self.high_write = high_write
+    self.low_write = low_write
+    self.premetadataed = premetadataed
+    self.terminal_metadata = terminal_metadata
+    self.code = code
+    self.message = message
+
+
+def _metadatafy(call, metadata):
+  for metadata_key, metadata_value in metadata:
+    call.add_metadata(metadata_key, metadata_value)
+
+
+class _Kernel(object):
+
+  def __init__(self, request_deserializers, response_serializers, ticket_relay):
+    self._lock = threading.Lock()
+    self._request_deserializers = request_deserializers
+    self._response_serializers = response_serializers
+    self._relay = ticket_relay
+
+    self._completion_queue = None
+    self._server = None
+    self._rpc_states = {}
+    self._pool = None
+
+  def _on_service_acceptance_event(self, event, server):
+    server.service(None)
+
+    service_acceptance = event.service_acceptance
+    call = service_acceptance.call
+    call.accept(self._completion_queue, call)
+    try:
+      group, method = service_acceptance.method.split('/')[1:3]
+    except ValueError:
+      logging.info('Illegal path "%s"!', service_acceptance.method)
+      return
+    request_deserializer = self._request_deserializers.get((group, method))
+    response_serializer = self._response_serializers.get((group, method))
+    if request_deserializer is None or response_serializer is None:
+      # TODO(nathaniel): Terminate the RPC with code NOT_FOUND.
+      call.cancel()
+      return
+
+    call.read(call)
+    self._rpc_states[call] = _RPCState(
+        request_deserializer, response_serializer, 1, _Read.READING, 0,
+        _HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None)
+    ticket = links.Ticket(
+        call, 0, group, method, links.Ticket.Subscription.FULL,
+        service_acceptance.deadline - time.time(), None, event.metadata, None,
+        None, None, None, None)
+    self._relay.add_value(ticket)
+
+  def _on_read_event(self, event):
+    call = event.tag
+    rpc_state = self._rpc_states.get(call, None)
+    if rpc_state is None:
+      return
+
+    if event.bytes is None:
+      rpc_state.read = _Read.CLOSED
+      payload = None
+      termination = links.Ticket.Termination.COMPLETION
+    else:
+      if 0 < rpc_state.allowance:
+        rpc_state.allowance -= 1
+        call.read(call)
+      else:
+        rpc_state.read = _Read.AWAITING_ALLOWANCE
+      payload = rpc_state.request_deserializer(event.bytes)
+      termination = None
+    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)
+
+  def _on_write_event(self, event):
+    call = event.tag
+    rpc_state = self._rpc_states.get(call, None)
+    if rpc_state is None:
+      return
+
+    if rpc_state.high_write is _HighWrite.CLOSED:
+      if rpc_state.terminal_metadata is not None:
+        _metadatafy(call, rpc_state.terminal_metadata)
+      call.status(
+          _intermediary_low.Status(rpc_state.code, rpc_state.message), call)
+      rpc_state.low_write = _LowWrite.CLOSED
+    else:
+      ticket = links.Ticket(
+          call, rpc_state.sequence_number, None, None, None, None, 1, None,
+          None, None, None, None, None)
+      rpc_state.sequence_number += 1
+      self._relay.add_value(ticket)
+      rpc_state.low_write = _LowWrite.OPEN
+
+  def _on_finish_event(self, event):
+    call = event.tag
+    rpc_state = self._rpc_states.pop(call, None)
+    if rpc_state is None:
+      return
+    code = event.status.code
+    if code is _intermediary_low.Code.OK:
+      return
+
+    if code is _intermediary_low.Code.CANCELLED:
+      termination = links.Ticket.Termination.CANCELLATION
+    elif code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+      termination = links.Ticket.Termination.EXPIRATION
+    else:
+      termination = links.Ticket.Termination.TRANSMISSION_FAILURE
+    ticket = links.Ticket(
+        call, rpc_state.sequence_number, None, None, None, None, None, None,
+        None, None, None, None, termination)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _spin(self, completion_queue, server):
+    while True:
+      event = completion_queue.get(None)
+      if event.kind is _intermediary_low.Event.Kind.STOP:
+        return
+      with self._lock:
+        if self._server is None:
+          continue
+        elif event.kind is _intermediary_low.Event.Kind.SERVICE_ACCEPTED:
+          self._on_service_acceptance_event(event, server)
+        elif event.kind is _intermediary_low.Event.Kind.READ_ACCEPTED:
+          self._on_read_event(event)
+        elif event.kind is _intermediary_low.Event.Kind.WRITE_ACCEPTED:
+          self._on_write_event(event)
+        elif event.kind is _intermediary_low.Event.Kind.COMPLETE_ACCEPTED:
+          pass
+        elif event.kind is _intermediary_low.Event.Kind.FINISH:
+          self._on_finish_event(event)
+        else:
+          logging.error('Illegal event! %s', (event,))
+
+  def add_ticket(self, ticket):
+    with self._lock:
+      if self._server is None:
+        return
+      call = ticket.operation_id
+      rpc_state = self._rpc_states.get(call)
+      if rpc_state is None:
+        return
+
+      if ticket.initial_metadata is not None:
+        _metadatafy(call, ticket.initial_metadata)
+        call.premetadata()
+        rpc_state.premetadataed = True
+      elif not rpc_state.premetadataed:
+        if (ticket.terminal_metadata is not None or
+            ticket.payload is not None or
+            ticket.termination is links.Ticket.Termination.COMPLETION or
+            ticket.code is not None or
+            ticket.message is not None):
+          call.premetadata()
+          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:
+          rpc_state.allowance += ticket.allowance
+
+      if ticket.payload is not None:
+        call.write(rpc_state.response_serializer(ticket.payload), call)
+        rpc_state.low_write = _LowWrite.ACTIVE
+
+      if ticket.terminal_metadata is not None:
+        rpc_state.terminal_metadata = ticket.terminal_metadata
+      if ticket.code is not None:
+        rpc_state.code = ticket.code
+      if ticket.message is not None:
+        rpc_state.message = ticket.message
+
+      if ticket.termination is links.Ticket.Termination.COMPLETION:
+        rpc_state.high_write = _HighWrite.CLOSED
+        if rpc_state.low_write is _LowWrite.OPEN:
+          if rpc_state.terminal_metadata is not None:
+            _metadatafy(call, rpc_state.terminal_metadata)
+          status = _intermediary_low.Status(
+              _intermediary_low.Code.OK
+              if rpc_state.code is None else rpc_state.code,
+              '' if rpc_state.message is None else rpc_state.message)
+          call.status(status, call)
+          rpc_state.low_write = _LowWrite.CLOSED
+      elif ticket.termination is not None:
+        call.cancel()
+        self._rpc_states.pop(call, None)
+
+  def add_port(self, port, server_credentials):
+    with self._lock:
+      address = '[::]:%d' % port
+      if self._server is None:
+        self._completion_queue = _intermediary_low.CompletionQueue()
+        self._server = _intermediary_low.Server(self._completion_queue)
+      if server_credentials is None:
+        return self._server.add_http2_addr(address)
+      else:
+        return self._server.add_secure_http2_addr(address, server_credentials)
+
+  def start(self):
+    with self._lock:
+      if self._server is None:
+        self._completion_queue = _intermediary_low.CompletionQueue()
+        self._server = _intermediary_low.Server(self._completion_queue)
+      self._pool = logging_pool.pool(1)
+      self._pool.submit(self._spin, self._completion_queue, self._server)
+      self._server.start()
+      self._server.service(None)
+
+  def graceful_stop(self):
+    with self._lock:
+      self._server.stop()
+      self._server = None
+      self._completion_queue.stop()
+      self._completion_queue = None
+      pool = self._pool
+      self._pool = None
+      self._rpc_states = None
+    pool.shutdown(wait=True)
+
+  def immediate_stop(self):
+    # TODO(nathaniel): Implementation.
+    raise NotImplementedError(
+        'TODO(nathaniel): after merge of rewritten lower layers')
+
+
+class ServiceLink(links.Link):
+  """A links.Link for use on the service-side of a gRPC connection.
+
+  Implementations of this interface are only valid for use between calls to
+  their start method and one of their stop methods.
+  """
+
+  @abc.abstractmethod
+  def add_port(self, port, server_credentials):
+    """Adds a port on which to service RPCs after this link has been started.
+
+    Args:
+      port: The port on which to service RPCs, or zero to request that a port be
+        automatically selected and used.
+      server_credentials: A ServerCredentials object, or None for insecure
+        service.
+
+    Returns:
+      A port on which RPCs will be serviced after this link has been started.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def start(self):
+    """Starts this object.
+
+    This method must be called before attempting to use this Link in ticket
+    exchange.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop_gracefully(self):
+    """Stops this link.
+
+    New RPCs will be rejected as soon as this method is called, but ongoing RPCs
+    will be allowed to continue until they terminate. This method blocks until
+    all RPCs have terminated.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop_immediately(self):
+    """Stops this link.
+
+    All in-progress RPCs will be terminated immediately.
+    """
+    raise NotImplementedError()
+
+
+class _ServiceLink(ServiceLink):
+
+  def __init__(self, request_deserializers, response_serializers):
+    self._relay = relay.relay(None)
+    self._kernel = _Kernel(
+        request_deserializers, response_serializers, self._relay)
+
+  def accept_ticket(self, ticket):
+    self._kernel.add_ticket(ticket)
+
+  def join_link(self, link):
+    self._relay.set_behavior(link.accept_ticket)
+
+  def add_port(self, port, server_credentials):
+    return self._kernel.add_port(port, server_credentials)
+
+  def start(self):
+    self._relay.start()
+    return self._kernel.start()
+
+  def stop_gracefully(self):
+    self._kernel.graceful_stop()
+    self._relay.stop()
+
+  def stop_immediately(self):
+    self._kernel.immediate_stop()
+    self._relay.stop()
+
+
+def service_link(request_deserializers, response_serializers):
+  """Creates a ServiceLink.
+
+  Args:
+    request_deserializers: A dict from group-method pair to request object
+      deserialization behavior.
+    response_serializers: A dict from group-method pair to response ojbect
+      serialization behavior.
+
+  Returns:
+    A ServiceLink.
+  """
+  return _ServiceLink(request_deserializers, response_serializers)
diff --git a/src/python/src/grpc/framework/common/test_constants.py b/src/python/src/grpc/framework/common/test_constants.py
new file mode 100644
index 0000000..237b875
--- /dev/null
+++ b/src/python/src/grpc/framework/common/test_constants.py
@@ -0,0 +1,37 @@
+# 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.
+
+"""Constants shared among tests throughout RPC Framework."""
+
+# Value for maximum duration in seconds of RPCs that may time out as part of a
+# test.
+SHORT_TIMEOUT = 4
+# Absurdly large value for maximum duration in seconds for should-not-time-out
+# RPCs made during tests.
+LONG_TIMEOUT = 3000
diff --git a/src/python/src/grpc/framework/common/test_control.py b/src/python/src/grpc/framework/common/test_control.py
new file mode 100644
index 0000000..3960c4e
--- /dev/null
+++ b/src/python/src/grpc/framework/common/test_control.py
@@ -0,0 +1,87 @@
+# 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.
+
+"""Code for instructing systems under test to block or fail."""
+
+import abc
+import contextlib
+import threading
+
+
+class Control(object):
+  """An object that accepts program control from a system under test.
+
+  Systems under test passed a Control should call its control() method
+  frequently during execution. The control() method may block, raise an
+  exception, or do nothing, all according to the enclosing test's desire for
+  the system under test to simulate hanging, failing, or functioning.
+  """
+
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def control(self):
+    """Potentially does anything."""
+    raise NotImplementedError()
+
+
+class PauseFailControl(Control):
+  """A Control that can be used to pause or fail code under control."""
+
+  def __init__(self):
+    self._condition = threading.Condition()
+    self._paused = False
+    self._fail = False
+
+  def control(self):
+    with self._condition:
+      if self._fail:
+        raise ValueError()
+
+      while self._paused:
+        self._condition.wait()
+
+  @contextlib.contextmanager
+  def pause(self):
+    """Pauses code under control while controlling code is in context."""
+    with self._condition:
+      self._paused = True
+    yield
+    with self._condition:
+      self._paused = False
+      self._condition.notify_all()
+
+  @contextlib.contextmanager
+  def fail(self):
+    """Fails code under control while controlling code is in context."""
+    with self._condition:
+      self._fail = True
+    yield
+    with self._condition:
+      self._fail = False
diff --git a/src/python/src/grpc/framework/common/test_coverage.py b/src/python/src/grpc/framework/common/test_coverage.py
new file mode 100644
index 0000000..a7ed358
--- /dev/null
+++ b/src/python/src/grpc/framework/common/test_coverage.py
@@ -0,0 +1,116 @@
+# 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.
+
+"""Governs coverage for tests of RPCs throughout RPC Framework."""
+
+import abc
+
+# This code is designed for use with the unittest module.
+# pylint: disable=invalid-name
+
+
+class Coverage(object):
+  """Specification of test coverage."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def testSuccessfulUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSuccessfulUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSuccessfulStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSuccessfulStreamRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSequentialInvocations(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testParallelInvocations(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testWaitingForSomeButNotAllParallelInvocations(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledStreamRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredStreamRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedStreamRequestStreamResponse(self):
+    raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/foundation/relay.py b/src/python/src/grpc/framework/foundation/relay.py
new file mode 100644
index 0000000..9c23946
--- /dev/null
+++ b/src/python/src/grpc/framework/foundation/relay.py
@@ -0,0 +1,175 @@
+# 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.
+
+"""Implementations of in-order work deference."""
+
+import abc
+import enum
+import threading
+
+from grpc.framework.foundation import activated
+from grpc.framework.foundation import logging_pool
+
+_NULL_BEHAVIOR = lambda unused_value: None
+
+
+class Relay(object):
+  """Performs work submitted to it in another thread.
+
+  Performs work in the order in which work was submitted to it; otherwise there
+  would be no reason to use an implementation of this interface instead of a
+  thread pool.
+  """
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def add_value(self, value):
+    """Adds a value to be passed to the behavior registered with this Relay.
+
+    Args:
+      value: A value that will be passed to a call made in another thread to the
+        behavior registered with this Relay.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def set_behavior(self, behavior):
+    """Sets the behavior that this Relay should call when passed values.
+
+    Args:
+      behavior: The behavior that this Relay should call in another thread when
+        passed a value, or None to have passed values ignored.
+    """
+    raise NotImplementedError()
+
+
+class _PoolRelay(activated.Activated, Relay):
+
+  @enum.unique
+  class _State(enum.Enum):
+    INACTIVE = 'inactive'
+    IDLE = 'idle'
+    SPINNING = 'spinning'
+
+  def __init__(self, pool, behavior):
+    self._condition = threading.Condition()
+    self._pool = pool
+    self._own_pool = pool is None
+    self._state = _PoolRelay._State.INACTIVE
+    self._activated = False
+    self._spinning = False
+    self._values = []
+    self._behavior = _NULL_BEHAVIOR if behavior is None else behavior
+
+  def _spin(self, behavior, value):
+    while True:
+      behavior(value)
+      with self._condition:
+        if self._values:
+          value = self._values.pop(0)
+          behavior = self._behavior
+        else:
+          self._state = _PoolRelay._State.IDLE
+          self._condition.notify_all()
+          break
+
+  def add_value(self, value):
+    with self._condition:
+      if self._state is _PoolRelay._State.INACTIVE:
+        raise ValueError('add_value not valid on inactive Relay!')
+      elif self._state is _PoolRelay._State.IDLE:
+        self._pool.submit(self._spin, self._behavior, value)
+        self._state = _PoolRelay._State.SPINNING
+      else:
+        self._values.append(value)
+
+  def set_behavior(self, behavior):
+    with self._condition:
+      self._behavior = _NULL_BEHAVIOR if behavior is None else behavior
+
+  def _start(self):
+    with self._condition:
+      self._state = _PoolRelay._State.IDLE
+      if self._own_pool:
+        self._pool = logging_pool.pool(1)
+      return self
+
+  def _stop(self):
+    with self._condition:
+      while self._state is _PoolRelay._State.SPINNING:
+        self._condition.wait()
+      if self._own_pool:
+        self._pool.shutdown(wait=True)
+      self._state = _PoolRelay._State.INACTIVE
+
+  def __enter__(self):
+    return self._start()
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    self._stop()
+    return False
+
+  def start(self):
+    return self._start()
+
+  def stop(self):
+    self._stop()
+
+
+def relay(behavior):
+  """Creates a Relay.
+
+  Args:
+    behavior: The behavior to be called by the created Relay, or None to have
+      passed values dropped until a different behavior is given to the returned
+      Relay later.
+
+  Returns:
+    An object that is both an activated.Activated and a Relay. The object is
+      only valid for use as a Relay when activated.
+  """
+  return _PoolRelay(None, behavior)
+
+
+def pool_relay(pool, behavior):
+  """Creates a Relay that uses a given thread pool.
+
+  This object will make use of at most one thread in the given pool.
+
+  Args:
+    pool: A futures.ThreadPoolExecutor for use by the created Relay.
+    behavior: The behavior to be called by the created Relay, or None to have
+      passed values dropped until a different behavior is given to the returned
+      Relay later.
+
+  Returns:
+    An object that is both an activated.Activated and a Relay. The object is
+      only valid for use as a Relay when activated.
+  """
+  return _PoolRelay(pool, behavior)
diff --git a/src/python/src/grpc/framework/interfaces/__init__.py b/src/python/src/grpc/framework/interfaces/__init__.py
new file mode 100644
index 0000000..7086519
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/src/grpc/framework/interfaces/links/__init__.py b/src/python/src/grpc/framework/interfaces/links/__init__.py
new file mode 100644
index 0000000..7086519
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/src/grpc/framework/interfaces/links/links.py b/src/python/src/grpc/framework/interfaces/links/links.py
new file mode 100644
index 0000000..5ebbac8
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/links.py
@@ -0,0 +1,124 @@
+# 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 low-level ticket-exchanging-links interface of RPC Framework."""
+
+import abc
+import collections
+import enum
+
+
+class Ticket(
+    collections.namedtuple(
+        'Ticket',
+        ['operation_id', 'sequence_number', 'group', 'method', 'subscription',
+         'timeout', 'allowance', 'initial_metadata', 'payload',
+         'terminal_metadata', 'code', 'message', 'termination'])):
+  """A sum type for all values sent from a front to a back.
+
+  Attributes:
+    operation_id: A unique-with-respect-to-equality hashable object identifying
+      a particular operation.
+    sequence_number: A zero-indexed integer sequence number identifying the
+      ticket's place in the stream of tickets sent in one direction for the
+      particular operation.
+    group: The group to which the method of the operation belongs. Must be
+      present in the first ticket from invocation side to service side. Ignored
+      for all other tickets exchanged during the operation.
+    method: The name of an operation. Must be present in the first ticket from
+      invocation side to service side. Ignored for all other tickets exchanged
+      during the operation.
+    subscription: A Subscription value describing the interest one side has in
+      receiving information from the other side. Must be present in the first
+      ticket from either side. Ignored for all other tickets exchanged during
+      the operation.
+    timeout: A nonzero length of time (measured from the beginning of the
+      operation) to allow for the entire operation. Must be present in the first
+      ticket from invocation side to service side. Optional for all other
+      tickets exchanged during the operation. Receipt of a value from the other
+      side of the operation indicates the value in use by that side. Setting a
+      value on a later ticket allows either side to request time extensions (or
+      even time reductions!) on in-progress operations.
+    allowance: A positive integer granting permission for a number of payloads
+      to be transmitted to the communicating side of the operation, or None if
+      no additional allowance is being granted with this ticket.
+    initial_metadata: An optional metadata value communicated from one side to
+      the other at the beginning of the operation. May be non-None in at most
+      one ticket from each side. Any non-None value must appear no later than
+      the first payload value.
+    payload: A customer payload object. May be None.
+    terminal_metadata: A metadata value comminicated from one side to the other
+      at the end of the operation. May be non-None in the same ticket as
+      the code and message, but must be None for all earlier tickets.
+    code: A value communicated at operation completion. May be None.
+    message: A value communicated at operation completion. May be None.
+    termination: A Termination value describing the end of the operation, or
+      None if the operation has not yet terminated. If set, no further tickets
+      may be sent in the same direction.
+  """
+
+  @enum.unique
+  class Subscription(enum.Enum):
+    """Identifies the level of subscription of a side of an operation."""
+
+    NONE = 'none'
+    TERMINATION = 'termination'
+    FULL = 'full'
+
+  @enum.unique
+  class Termination(enum.Enum):
+    """Identifies the termination of an operation."""
+
+    COMPLETION = 'completion'
+    CANCELLATION = 'cancellation'
+    EXPIRATION = 'expiration'
+    LOCAL_SHUTDOWN = 'local shutdown'
+    RECEPTION_FAILURE = 'reception failure'
+    TRANSMISSION_FAILURE = 'transmission failure'
+    LOCAL_FAILURE = 'local failure'
+    REMOTE_FAILURE = 'remote failure'
+
+
+class Link(object):
+  """Accepts and emits tickets."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def accept_ticket(self, ticket):
+    """Accept a Ticket.
+
+    Args:
+      ticket: Any Ticket.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def join_link(self, link):
+    """Mates this object with a peer with which it will exchange tickets."""
+    raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/interfaces/links/test_cases.py b/src/python/src/grpc/framework/interfaces/links/test_cases.py
new file mode 100644
index 0000000..3ac212e
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/test_cases.py
@@ -0,0 +1,332 @@
+# 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.
+
+"""Tests of the links interface of RPC Framework."""
+
+# unittest is referenced from specification in this module.
+import abc
+import unittest  # pylint: disable=unused-import
+
+from grpc.framework.common import test_constants
+from grpc.framework.interfaces.links import links
+from grpc.framework.interfaces.links import test_utilities
+
+
+def at_least_n_payloads_received_predicate(n):
+  def predicate(ticket_sequence):
+    payload_count = 0
+    for ticket in ticket_sequence:
+      if ticket.payload is not None:
+        payload_count += 1
+        if n <= payload_count:
+          return True
+    else:
+      return False
+  return predicate
+
+
+def terminated(ticket_sequence):
+  return ticket_sequence and ticket_sequence[-1].termination is not None
+
+_TRANSMISSION_GROUP = 'test.Group'
+_TRANSMISSION_METHOD = 'TestMethod'
+
+
+class TransmissionTest(object):
+  """Tests ticket transmission between two connected links.
+
+  This class must be mixed into a unittest.TestCase that implements the abstract
+  methods it provides.
+  """
+  __metaclass__ = abc.ABCMeta
+
+  # This is a unittest.TestCase mix-in.
+  # pylint: disable=invalid-name
+
+  @abc.abstractmethod
+  def create_transmitting_links(self):
+    """Creates two connected links for use in this test.
+
+    Returns:
+      Two links.Links, the first of which will be used on the invocation side
+        of RPCs and the second of which will be used on the service side of
+        RPCs.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def destroy_transmitting_links(self, invocation_side_link, service_side_link):
+    """Destroys the two connected links created for this test.
+
+
+    Args:
+      invocation_side_link: The link used on the invocation side of RPCs in
+        this test.
+      service_side_link: The link used on the service side of RPCs in this
+        test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_invocation_initial_metadata(self):
+    """Creates a value for use as invocation-side initial metadata.
+
+    Returns:
+      A metadata value appropriate for use as invocation-side initial metadata
+        or None if invocation-side initial metadata transmission is not
+        supported by the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_invocation_terminal_metadata(self):
+    """Creates a value for use as invocation-side terminal metadata.
+
+    Returns:
+      A metadata value appropriate for use as invocation-side terminal
+        metadata or None if invocation-side terminal metadata transmission is
+        not supported by the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_service_initial_metadata(self):
+    """Creates a value for use as service-side initial metadata.
+
+    Returns:
+      A metadata value appropriate for use as service-side initial metadata or
+        None if service-side initial metadata transmission is not supported by
+        the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_service_terminal_metadata(self):
+    """Creates a value for use as service-side terminal metadata.
+
+    Returns:
+      A metadata value appropriate for use as service-side terminal metadata or
+        None if service-side terminal metadata transmission is not supported by
+        the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_invocation_completion(self):
+    """Creates values for use as invocation-side code and message.
+
+    Returns:
+      An invocation-side code value and an invocation-side message value.
+        Either or both may be None if invocation-side code and/or
+        invocation-side message transmission is not supported by the links
+        under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_service_completion(self):
+    """Creates values for use as service-side code and message.
+
+    Returns:
+      A service-side code value and a service-side message value. Either or
+        both may be None if service-side code and/or service-side message
+        transmission is not supported by the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def assertMetadataEqual(self, original_metadata, transmitted_metadata):
+    """Asserts that two metadata objects are equal.
+
+    Args:
+      original_metadata: A metadata object used in this test.
+      transmitted_metadata: A metadata object obtained after transmission
+        through the system under test.
+
+    Raises:
+      AssertionError: if the two metadata objects are not equal.
+    """
+    raise NotImplementedError()
+
+  def group_and_method(self):
+    """Returns the group and method used in this test case.
+
+    Returns:
+      A pair of the group and method used in this test case.
+    """
+    return _TRANSMISSION_GROUP, _TRANSMISSION_METHOD
+
+  def serialize_request(self, request):
+    """Serializes a request value used in this test case.
+
+    Args:
+      request: A request value created by this test case.
+
+    Returns:
+      A bytestring that is the serialization of the given request.
+    """
+    return request
+
+  def deserialize_request(self, serialized_request):
+    """Deserializes a request value used in this test case.
+
+    Args:
+      serialized_request: A bytestring that is the serialization of some request
+        used in this test case.
+
+    Returns:
+      The request value encoded by the given bytestring.
+    """
+    return serialized_request
+
+  def serialize_response(self, response):
+    """Serializes a response value used in this test case.
+
+    Args:
+      response: A response value created by this test case.
+
+    Returns:
+      A bytestring that is the serialization of the given response.
+    """
+    return response
+
+  def deserialize_response(self, serialized_response):
+    """Deserializes a response value used in this test case.
+
+    Args:
+      serialized_response: A bytestring that is the serialization of some
+        response used in this test case.
+
+    Returns:
+      The response value encoded by the given bytestring.
+    """
+    return serialized_response
+
+  def _assert_is_valid_metadata_payload_sequence(
+      self, ticket_sequence, payloads, initial_metadata, terminal_metadata):
+    initial_metadata_seen = False
+    seen_payloads = []
+    terminal_metadata_seen = False
+
+    for ticket in ticket_sequence:
+      if ticket.initial_metadata is not None:
+        self.assertFalse(initial_metadata_seen)
+        self.assertFalse(seen_payloads)
+        self.assertFalse(terminal_metadata_seen)
+        self.assertMetadataEqual(initial_metadata, ticket.initial_metadata)
+        initial_metadata_seen = True
+
+      if ticket.payload is not None:
+        self.assertFalse(terminal_metadata_seen)
+        seen_payloads.append(ticket.payload)
+
+      if ticket.terminal_metadata is not None:
+        self.assertFalse(terminal_metadata_seen)
+        self.assertMetadataEqual(terminal_metadata, ticket.terminal_metadata)
+        terminal_metadata_seen = True
+    self.assertSequenceEqual(payloads, seen_payloads)
+
+  def _assert_is_valid_invocation_sequence(
+      self, ticket_sequence, group, method, payloads, initial_metadata,
+      terminal_metadata, termination):
+    self.assertLess(0, len(ticket_sequence))
+    self.assertEqual(group, ticket_sequence[0].group)
+    self.assertEqual(method, ticket_sequence[0].method)
+    self._assert_is_valid_metadata_payload_sequence(
+        ticket_sequence, payloads, initial_metadata, terminal_metadata)
+    self.assertIs(termination, ticket_sequence[-1].termination)
+
+  def _assert_is_valid_service_sequence(
+      self, ticket_sequence, payloads, initial_metadata, terminal_metadata,
+      code, message, termination):
+    self.assertLess(0, len(ticket_sequence))
+    self._assert_is_valid_metadata_payload_sequence(
+        ticket_sequence, payloads, initial_metadata, terminal_metadata)
+    self.assertEqual(code, ticket_sequence[-1].code)
+    self.assertEqual(message, ticket_sequence[-1].message)
+    self.assertIs(termination, ticket_sequence[-1].termination)
+
+  def setUp(self):
+    self._invocation_link, self._service_link = self.create_transmitting_links()
+    self._invocation_mate = test_utilities.RecordingLink()
+    self._service_mate = test_utilities.RecordingLink()
+    self._invocation_link.join_link(self._invocation_mate)
+    self._service_link.join_link(self._service_mate)
+
+  def tearDown(self):
+    self.destroy_transmitting_links(self._invocation_link, self._service_link)
+
+  def testSimplestRoundTrip(self):
+    """Tests transmission of one ticket in each direction."""
+    invocation_operation_id = object()
+    invocation_payload = b'\x07' * 1023
+    timeout = test_constants.LONG_TIMEOUT
+    invocation_initial_metadata = self.create_invocation_initial_metadata()
+    invocation_terminal_metadata = self.create_invocation_terminal_metadata()
+    invocation_code, invocation_message = self.create_invocation_completion()
+    service_payload = b'\x08' * 1025
+    service_initial_metadata = self.create_service_initial_metadata()
+    service_terminal_metadata = self.create_service_terminal_metadata()
+    service_code, service_message = self.create_service_completion()
+
+    original_invocation_ticket = links.Ticket(
+        invocation_operation_id, 0, _TRANSMISSION_GROUP, _TRANSMISSION_METHOD,
+        links.Ticket.Subscription.FULL, timeout, 0, invocation_initial_metadata,
+        invocation_payload, invocation_terminal_metadata, invocation_code,
+        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(
+        self._service_mate.tickets(), _TRANSMISSION_GROUP, _TRANSMISSION_METHOD,
+        (invocation_payload,), invocation_initial_metadata,
+        invocation_terminal_metadata, links.Ticket.Termination.COMPLETION)
+
+    original_service_ticket = links.Ticket(
+        service_operation_id, 1, None, None, links.Ticket.Subscription.FULL,
+        timeout, 0, service_initial_metadata, service_payload,
+        service_terminal_metadata, service_code, service_message,
+        links.Ticket.Termination.COMPLETION)
+    self._service_link.accept_ticket(original_service_ticket)
+    self._invocation_mate.block_until_tickets_satisfy(terminated)
+    self._assert_is_valid_service_sequence(
+        self._invocation_mate.tickets(), (service_payload,),
+        service_initial_metadata, service_terminal_metadata, service_code,
+        service_message, links.Ticket.Termination.COMPLETION)
diff --git a/src/python/src/grpc/framework/interfaces/links/test_utilities.py b/src/python/src/grpc/framework/interfaces/links/test_utilities.py
new file mode 100644
index 0000000..6c2e334
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/test_utilities.py
@@ -0,0 +1,66 @@
+# 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.
+
+"""State and behavior appropriate for use in tests."""
+
+import threading
+
+from grpc.framework.interfaces.links import links
+
+
+class RecordingLink(links.Link):
+  """A Link that records every ticket passed to it."""
+
+  def __init__(self):
+    self._condition = threading.Condition()
+    self._tickets = []
+
+  def accept_ticket(self, ticket):
+    with self._condition:
+      self._tickets.append(ticket)
+      self._condition.notify_all()
+
+  def join_link(self, link):
+    pass
+
+  def block_until_tickets_satisfy(self, predicate):
+    """Blocks until the received tickets satisfy the given predicate.
+
+    Args:
+      predicate: A callable that takes a sequence of tickets and returns a
+        boolean value.
+    """
+    with self._condition:
+      while not predicate(self._tickets):
+        self._condition.wait()
+
+  def tickets(self):
+    """Returns a copy of the list of all tickets received by this Link."""
+    with self._condition:
+      return tuple(self._tickets)
diff --git a/src/python/src/grpc/framework/interfaces/links/utilities.py b/src/python/src/grpc/framework/interfaces/links/utilities.py
new file mode 100644
index 0000000..6e4fd76
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/utilities.py
@@ -0,0 +1,44 @@
+# 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 provided as part of the links interface."""
+
+from grpc.framework.interfaces.links import links
+
+
+class _NullLink(links.Link):
+  """A do-nothing links.Link."""
+
+  def accept_ticket(self, ticket):
+    pass
+
+  def join_link(self, link):
+    pass
+
+NULL_LINK = _NullLink()
diff --git a/src/python/src/setup.py b/src/python/src/setup.py
index 5398b09..a857ae9 100644
--- a/src/python/src/setup.py
+++ b/src/python/src/setup.py
@@ -29,11 +29,19 @@
 
 """A setup module for the GRPC Python package."""
 
-from distutils import core as _core
-import setuptools
+import os
 import sys
 
-_EXTENSION_SOURCES = (
+from distutils import core as _core
+import setuptools
+
+
+# Use environment variables to determine whether or not the Cython extension
+# should *use* Cython or use the generated C files. Note that this requires the
+# C files to have been generated by building first *with* Cython support.
+_BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+
+_C_EXTENSION_SOURCES = (
     'grpc/_adapter/_c/module.c',
     'grpc/_adapter/_c/types.c',
     'grpc/_adapter/_c/utility.c',
@@ -56,16 +64,19 @@
 if not "darwin" in sys.platform:
     _EXTENSION_LIBRARIES += ('rt',)
 
-_EXTENSION_MODULE = _core.Extension(
-    'grpc._adapter._c', sources=list(_EXTENSION_SOURCES),
+
+_C_EXTENSION_MODULE = _core.Extension(
+    'grpc._adapter._c', sources=list(_C_EXTENSION_SOURCES),
     include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES),
     libraries=list(_EXTENSION_LIBRARIES),
-    )
+)
+_EXTENSION_MODULES = [_C_EXTENSION_MODULE]
 
 _PACKAGES = (
     'grpc',
     'grpc._adapter',
     'grpc._junkdrawer',
+    'grpc._links',
     'grpc.early_adopter',
     'grpc.framework',
     'grpc.framework.alpha',
@@ -74,20 +85,23 @@
     'grpc.framework.face',
     'grpc.framework.face.testing',
     'grpc.framework.foundation',
+    'grpc.framework.interfaces',
+    'grpc.framework.interfaces.links',
 )
 
 _PACKAGE_DIRECTORIES = {
     'grpc': 'grpc',
     'grpc._adapter': 'grpc/_adapter',
     'grpc._junkdrawer': 'grpc/_junkdrawer',
+    'grpc._links': 'grpc/_links',
     'grpc.early_adopter': 'grpc/early_adopter',
     'grpc.framework': 'grpc/framework',
 }
 
 setuptools.setup(
     name='grpcio',
-    version='0.9.0a1',
-    ext_modules=[_EXTENSION_MODULE],
+    version='0.10.0a0',
+    ext_modules=_EXTENSION_MODULES,
     packages=list(_PACKAGES),
     package_dir=_PACKAGE_DIRECTORIES,
     install_requires=[
diff --git a/src/ruby/.rubocop_todo.yml b/src/ruby/.rubocop_todo.yml
index c35e970..05db404 100644
--- a/src/ruby/.rubocop_todo.yml
+++ b/src/ruby/.rubocop_todo.yml
@@ -12,7 +12,7 @@
 # Offense count: 3
 # Configuration parameters: CountComments.
 Metrics/ClassLength:
-  Max: 192
+  Max: 200
 
 # Offense count: 35
 # Configuration parameters: CountComments.
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
index 16fb1b1..da4caa8 100755
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/bin/interop/interop_client.rb
@@ -284,7 +284,8 @@
     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) }
-    assert(op.cancelled, 'call operation should be CANCELLED')
+    op.wait
+    assert(op.cancelled, 'call operation was not CANCELLED')
     p 'OK: cancel_after_first_response'
   end
 
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index 0ff8bb9..7972272 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -54,44 +54,55 @@
   LIBDIR
 ]
 
-# Check to see if GRPC_ROOT is defined or available
-grpc_root = ENV['GRPC_ROOT']
-if grpc_root.nil?
-  r = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
-  grpc_root = r if File.exist?(File.join(r, 'include/grpc/grpc.h'))
-end
-
-# When grpc_root is available attempt to build the grpc core.
-unless grpc_root.nil?
-  grpc_config = ENV['GRPC_CONFIG'] || 'opt'
-  if ENV.key?('GRPC_LIB_DIR')
-    grpc_lib_dir = File.join(grpc_root, ENV['GRPC_LIB_DIR'])
-  else
-    grpc_lib_dir = File.join(File.join(grpc_root, 'libs'), grpc_config)
+def check_grpc_root
+  grpc_root = ENV['GRPC_ROOT']
+  if grpc_root.nil?
+    r = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
+    grpc_root = r if File.exist?(File.join(r, 'include/grpc/grpc.h'))
   end
-  unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a'))
-    system("make -C #{grpc_root} static_c CONFIG=#{grpc_config}")
+  grpc_root
+end
+
+grpc_pkg_config = system('pkg-config --exists grpc')
+
+if grpc_pkg_config
+  $CFLAGS << ' ' + `pkg-config --static --cflags grpc`.strip + ' '
+  $LDFLAGS << ' ' + `pkg-config --static --libs grpc`.strip + ' '
+else
+  dir_config('grpc', HEADER_DIRS, LIB_DIRS)
+  fail 'libdl not found' unless have_library('dl', 'dlopen')
+  fail 'zlib not found' unless have_library('z', 'inflate')
+  begin
+    fail 'Fail' unless have_library('gpr', 'gpr_now')
+    fail 'Fail' unless have_library('grpc', 'grpc_channel_destroy')
+  rescue
+    # Check to see if GRPC_ROOT is defined or available
+    grpc_root = check_grpc_root
+
+    # Stop if there is still no grpc_root
+    exit 1 if grpc_root.nil?
+
+    grpc_config = ENV['GRPC_CONFIG'] || 'opt'
+    if ENV.key?('GRPC_LIB_DIR')
+      grpc_lib_dir = File.join(grpc_root, ENV['GRPC_LIB_DIR'])
+    else
+      grpc_lib_dir = File.join(File.join(grpc_root, 'libs'), grpc_config)
+    end
+    unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a'))
+      print "Building internal gRPC\n"
+      system("make -C #{grpc_root} static_c CONFIG=#{grpc_config}")
+    end
+    $CFLAGS << ' -I' + File.join(grpc_root, 'include')
+    $LDFLAGS << ' -L' + grpc_lib_dir
+    raise 'gpr not found' unless have_library('gpr', 'gpr_now')
+    raise 'grpc not found' unless have_library('grpc', 'grpc_channel_destroy')
   end
-  HEADER_DIRS.unshift File.join(grpc_root, 'include')
-  LIB_DIRS.unshift grpc_lib_dir
 end
 
-def crash(msg)
-  print(" extconf failure: #{msg}\n")
-  exit 1
-end
-
-dir_config('grpc', HEADER_DIRS, LIB_DIRS)
-
-$CFLAGS << ' -Wno-implicit-function-declaration '
-$CFLAGS << ' -Wno-pointer-sign '
-$CFLAGS << ' -Wno-return-type '
+$CFLAGS << ' -std=c99 '
 $CFLAGS << ' -Wall '
+$CFLAGS << ' -Wextra '
 $CFLAGS << ' -pedantic '
+$CFLAGS << ' -Werror '
 
-$LDFLAGS << ' -lgrpc -lgpr -ldl'
-
-crash('need grpc lib') unless have_library('grpc', 'grpc_channel_destroy')
-have_library('grpc', 'grpc_channel_destroy')
-crash('need gpr lib') unless have_library('gpr', 'gpr_now')
 create_makefile('grpc/grpc')
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 33bfd00..bfb9f6f 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -131,7 +131,8 @@
 
 static const rb_data_type_t grpc_rb_md_ary_data_type = {
     "grpc_metadata_array",
-    {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize},
+    {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize,
+     {NULL, NULL}},
     NULL,
     NULL,
     0};
@@ -139,7 +140,8 @@
 /* Describes grpc_call struct for RTypedData */
 static const rb_data_type_t grpc_call_data_type = {
     "grpc_call",
-    {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE},
+    {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE,
+     {NULL, NULL}},
     NULL,
     NULL,
     /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
@@ -275,6 +277,8 @@
                                            VALUE md_ary_obj) {
   grpc_metadata_array *md_ary = NULL;
 
+  (void)key;
+
   /* Construct a metadata object from key and value and add it */
   TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
                        &grpc_rb_md_ary_data_type, md_ary);
@@ -348,6 +352,7 @@
 */
 static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val,
                                               VALUE ops_ary) {
+  (void)val;
   /* Update the capacity; the value is an array, add capacity for each value in
    * the array */
   if (TYPE(key) != T_FIXNUM) {
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index d6876bc..9bf1a9f 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -107,7 +107,8 @@
 
 static rb_data_type_t grpc_channel_data_type = {
     "grpc_channel",
-    {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE},
+    {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE,
+     {NULL, NULL}},
     NULL, NULL,
     RUBY_TYPED_FREE_IMMEDIATELY
 };
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 42ed3a1..1ba30b6 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -41,7 +41,8 @@
 
 static rb_data_type_t grpc_rb_channel_args_data_type = {
     "grpc_channel_args",
-    {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE},
+    {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE,
+     {NULL, NULL}},
     NULL, NULL,
     RUBY_TYPED_FREE_IMMEDIATELY
 };
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 8fb3949..b6674d7 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -82,7 +82,7 @@
   next_call.cq = cq;
   next_call.event.type = GRPC_QUEUE_TIMEOUT;
   /* TODO: the timeout should be a module level constant that defaults
-   * to gpr_inf_future.
+   * to gpr_inf_future(GPR_CLOCK_REALTIME).
    *
    * - at the moment this does not work, it stalls.  Using a small timeout like
    *   this one works, and leads to fast test run times; a longer timeout was
@@ -91,7 +91,8 @@
    * - investigate further, this is probably another example of C-level cleanup
    * not working consistently in all cases.
    */
-  next_call.timeout = gpr_time_add(gpr_now(), gpr_time_from_micros(5e3));
+  next_call.timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                   gpr_time_from_micros(5e3, GPR_TIMESPAN));
   do {
     rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil,
                                (void *)&next_call, NULL, NULL);
@@ -118,7 +119,7 @@
 static rb_data_type_t grpc_rb_completion_queue_data_type = {
     "grpc_completion_queue",
     {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
-     GRPC_RB_MEMSIZE_UNAVAILABLE},
+     GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
     NULL, NULL,
     /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain
      * calls rb_thread_call_without_gvl. */
@@ -143,7 +144,7 @@
   TypedData_Get_Struct(self, grpc_completion_queue,
                        &grpc_rb_completion_queue_data_type, next_call.cq);
   if (TYPE(timeout) == T_NIL) {
-    next_call.timeout = gpr_inf_future;
+    next_call.timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
   } else {
     next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
   }
diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c
index 3fca848..a9dcdbc 100644
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ b/src/ruby/ext/grpc/rb_credentials.c
@@ -89,7 +89,7 @@
 static rb_data_type_t grpc_rb_credentials_data_type = {
     "grpc_credentials",
     {grpc_rb_credentials_mark, grpc_rb_credentials_free,
-     GRPC_RB_MEMSIZE_UNAVAILABLE},
+     GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
     NULL,
     NULL,
     RUBY_TYPED_FREE_IMMEDIATELY};
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 699548b..829f825 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -51,7 +51,8 @@
 
 static rb_data_type_t grpc_rb_timespec_data_type = {
     "gpr_timespec",
-    {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE},
+    {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE,
+     {NULL, NULL}},
     NULL,
     NULL,
     RUBY_TYPED_FREE_IMMEDIATELY};
@@ -75,6 +76,7 @@
 
 /* Init/Clone func that fails by raising an exception. */
 VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) {
+  (void)self;
   rb_raise(rb_eTypeError,
            "initialization of %s only allowed from the gRPC native layer",
            rb_obj_classname(copy));
@@ -98,6 +100,7 @@
   const char *tstr = interval ? "time interval" : "time";
   const char *want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>";
 
+  t.clock_type = GPR_CLOCK_REALTIME;
   switch (TYPE(time)) {
     case T_DATA:
       if (CLASS_OF(time) == grpc_rb_cTimeVal) {
@@ -222,24 +225,31 @@
   return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0);
 }
 
+static gpr_timespec zero_realtime;
+static gpr_timespec inf_future_realtime;
+static gpr_timespec inf_past_realtime;
+
 /* Adds a module with constants that map to gpr's static timeval structs. */
 static void Init_grpc_time_consts() {
   VALUE grpc_rb_mTimeConsts =
       rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
   grpc_rb_cTimeVal =
       rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
+  zero_realtime = gpr_time_0(GPR_CLOCK_REALTIME);
+  inf_future_realtime = gpr_inf_future(GPR_CLOCK_REALTIME);
+  inf_past_realtime = gpr_inf_past(GPR_CLOCK_REALTIME);
   rb_define_const(
       grpc_rb_mTimeConsts, "ZERO",
       TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
-                            (void *)&gpr_time_0));
+                            (void *)&zero_realtime));
   rb_define_const(
       grpc_rb_mTimeConsts, "INFINITE_FUTURE",
       TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
-                            (void *)&gpr_inf_future));
+                            (void *)&inf_future_realtime));
   rb_define_const(
       grpc_rb_mTimeConsts, "INFINITE_PAST",
       TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
-                            (void *)&gpr_inf_past));
+                            (void *)&inf_past_realtime));
   rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
   rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
   rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
@@ -250,7 +260,10 @@
   id_tv_nsec = rb_intern("tv_nsec");
 }
 
-static void grpc_rb_shutdown(ruby_vm_t *vm) { grpc_shutdown(); }
+static void grpc_rb_shutdown(ruby_vm_t *vm) {
+  (void)vm;
+  grpc_shutdown();
+}
 
 /* Initialize the GRPC module structs */
 
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 9c0d24b..e3a0a5a 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -68,8 +68,12 @@
 
   /* Deletes the wrapped object if the mark object is Qnil, which indicates
      that no other object is the actual owner. */
+  /* grpc_server_shutdown does not exist. Change this to something that does
+     or delete it */
   if (svr->wrapped != NULL && svr->mark == Qnil) {
-    grpc_server_shutdown(svr->wrapped);
+    // grpc_server_shutdown(svr->wrapped);
+    // Aborting to indicate a bug
+    abort();
     grpc_server_destroy(svr->wrapped);
   }
 
@@ -90,7 +94,8 @@
 
 static const rb_data_type_t grpc_rb_server_data_type = {
     "grpc_server",
-    {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE},
+    {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE,
+     {NULL, NULL}},
     NULL,
     NULL,
     /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index 23271c4..5f40935 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -89,7 +89,7 @@
 static const rb_data_type_t grpc_rb_server_credentials_data_type = {
     "grpc_server_credentials",
     {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free,
-     GRPC_RB_MEMSIZE_UNAVAILABLE},
+     GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
     NULL, NULL,
     RUBY_TYPED_FREE_IMMEDIATELY
 };
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 319da94..dd4e27d 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -14,7 +14,7 @@
   s.license       = 'BSD-3-Clause'
 
   s.required_ruby_version = '>= 2.0.0'
-  s.requirements << 'libgrpc ~> 0.9.1 needs to be installed'
+  s.requirements << 'libgrpc ~> 0.10.0 needs to be installed'
 
   s.files         = `git ls-files`.split("\n")
   s.test_files    = `git ls-files -- spec/*`.split("\n")
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 3814ef3..215c006 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -120,6 +120,7 @@
       @started = started
       @unmarshal = unmarshal
       @metadata_tag = metadata_tag
+      @op_notifier = nil
     end
 
     # output_metadata are provides access to hash that can be used to
@@ -148,6 +149,7 @@
     # operation provides a restricted view of this ActiveCall for use as
     # a Operation.
     def operation
+      @op_notifier = Notifier.new
       Operation.new(self)
     end
 
@@ -167,6 +169,7 @@
       batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
       return unless assert_finished
       @call.status = batch_result.status
+      op_is_done
       batch_result.check_status
     end
 
@@ -184,6 +187,7 @@
         end
       end
       @call.status = batch_result.status
+      op_is_done
       batch_result.check_status
     end
 
@@ -415,7 +419,7 @@
     def bidi_streamer(requests, **kw, &blk)
       start_call(**kw) unless @started
       bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
-      bd.run_on_client(requests, &blk)
+      bd.run_on_client(requests, @op_notifier, &blk)
     end
 
     # run_server_bidi orchestrates a BiDi stream processing on a server.
@@ -434,6 +438,19 @@
       bd.run_on_server(gen_each_reply)
     end
 
+    # Waits till an operation completes
+    def wait
+      return if @op_notifier.nil?
+      GRPC.logger.debug("active_call.wait: on #{@op_notifier}")
+      @op_notifier.wait
+    end
+
+    # Signals that an operation is done
+    def op_is_done
+      return if @op_notifier.nil?
+      @op_notifier.notify(self)
+    end
+
     private
 
     # Starts the call if not already started
@@ -468,6 +485,6 @@
     # Operation limits access to an ActiveCall's methods for use as
     # a Operation on the client.
     Operation = view_class(:cancel, :cancelled, :deadline, :execute,
-                           :metadata, :status, :start_call)
+                           :metadata, :status, :start_call, :wait)
   end
 end
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 489dd51..3b0c713 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -66,6 +66,7 @@
       @cq = q
       @deadline = deadline
       @marshal = marshal
+      @op_notifier = nil  # signals completion on clients
       @readq = Queue.new
       @unmarshal = unmarshal
     end
@@ -76,8 +77,10 @@
     # block that can be invoked with each response.
     #
     # @param requests the Enumerable of requests to send
+    # @op_notifier a Notifier used to signal completion
     # @return an Enumerator of requests to yield
-    def run_on_client(requests, &blk)
+    def run_on_client(requests, op_notifier, &blk)
+      @op_notifier = op_notifier
       @enq_th = Thread.new { write_loop(requests) }
       @loop_th = start_read_loop
       each_queued_msg(&blk)
@@ -105,6 +108,13 @@
     END_OF_READS = :end_of_reads
     END_OF_WRITES = :end_of_writes
 
+    # signals that bidi operation is complete
+    def notify_done
+      return unless @op_notifier
+      GRPC.logger.debug("bidi-notify-done: notifying  #{@op_notifier}")
+      @op_notifier.notify(self)
+    end
+
     # each_queued_msg yields each message on this instances readq
     #
     # - messages are added to the readq by #read_loop
@@ -143,11 +153,13 @@
         @call.status = batch_result.status
         batch_result.check_status
         GRPC.logger.debug("bidi-write-loop: done status #{@call.status}")
+        notify_done
       end
       GRPC.logger.debug('bidi-write-loop: finished')
     rescue StandardError => e
       GRPC.logger.warn('bidi-write-loop: failed')
       GRPC.logger.warn(e)
+      notify_done
       raise e
     end
 
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index a7e20d6..67bf35c 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -398,14 +398,14 @@
       nil
     end
 
-    # Sends NOT_FOUND if the method can't be found
-    def found?(an_rpc)
+    # Sends UNIMPLEMENTED if the method is not implemented by this server
+    def implemented?(an_rpc)
       mth = an_rpc.method.to_sym
       return an_rpc if rpc_descs.key?(mth)
-      GRPC.logger.warn("NOT_FOUND: #{an_rpc}")
+      GRPC.logger.warn("UNIMPLEMENTED: #{an_rpc}")
       noop = proc { |x| x }
       c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
-      c.send_status(StatusCodes::NOT_FOUND, '')
+      c.send_status(StatusCodes::UNIMPLEMENTED, '')
       nil
     end
 
@@ -446,7 +446,7 @@
       an_rpc.call.run_batch(@cq, handle_call_tag, INFINITE_FUTURE,
                             SEND_INITIAL_METADATA => connect_md)
       return nil unless available?(an_rpc)
-      return nil unless found?(an_rpc)
+      return nil unless implemented?(an_rpc)
 
       # Create the ActiveCall
       GRPC.logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
diff --git a/src/ruby/lib/grpc/logconfig.rb b/src/ruby/lib/grpc/logconfig.rb
index 9681217..e9b4aa3 100644
--- a/src/ruby/lib/grpc/logconfig.rb
+++ b/src/ruby/lib/grpc/logconfig.rb
@@ -38,6 +38,6 @@
 Logging.logger.root.level = :info
 
 # TODO: provide command-line configuration for logging
-Logging.logger['GRPC'].level = :debug
+Logging.logger['GRPC'].level = :info
 Logging.logger['GRPC::ActiveCall'].level = :info
 Logging.logger['GRPC::BidiCall'].level = :info
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 53265c7..431e877 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '0.9.3'
+  VERSION = '0.10.0'
 end
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index b22e510..0e85441 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -71,6 +71,12 @@
 
   it 'servers receive requests from clients and can respond' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -81,7 +87,7 @@
     expect(batch_result.send_message).to be true
 
     # confirm the server can read the inbound message
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::RECV_MESSAGE => nil
     }
@@ -92,6 +98,12 @@
 
   it 'responses written by servers are received by the client' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -102,7 +114,7 @@
     expect(batch_result.send_message).to be true
 
     # confirm the server can read the inbound message
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::RECV_MESSAGE => nil,
       CallOps::SEND_MESSAGE => reply_text
@@ -115,6 +127,12 @@
 
   it 'servers can ignore a client write and send a status' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -126,7 +144,7 @@
 
     # confirm the server can read the inbound message
     the_status = Struct::Status.new(StatusCodes::OK, 'OK')
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::SEND_STATUS_FROM_SERVER => the_status
     }
@@ -138,6 +156,12 @@
 
   it 'completes calls by sending status to client and server' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -149,7 +173,7 @@
 
     # confirm the server can read the inbound message and respond
     the_status = Struct::Status.new(StatusCodes::OK, 'OK', {})
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::RECV_MESSAGE => nil,
       CallOps::SEND_MESSAGE => reply_text,
@@ -218,6 +242,11 @@
 
     it 'sends all the metadata pairs when keys and values are valid' do
       @valid_metadata.each do |md|
+        recvd_rpc = nil
+        rcv_thread = Thread.new do
+          recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        end
+
         call = new_client_call
         client_ops = {
           CallOps::SEND_INITIAL_METADATA => md
@@ -227,7 +256,7 @@
         expect(batch_result.send_metadata).to be true
 
         # confirm the server can receive the client metadata
-        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        rcv_thread.join
         expect(recvd_rpc).to_not eq nil
         recvd_md = recvd_rpc.metadata
         replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
@@ -254,6 +283,11 @@
 
     it 'raises an exception if a metadata key is invalid' do
       @bad_keys.each do |md|
+        recvd_rpc = nil
+        rcv_thread = Thread.new do
+          recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        end
+
         call = new_client_call
         # client signals that it's done sending metadata to allow server to
         # respond
@@ -263,7 +297,7 @@
         call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
         # server gets the invocation
-        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        rcv_thread.join
         expect(recvd_rpc).to_not eq nil
         server_ops = {
           CallOps::SEND_INITIAL_METADATA => md
@@ -277,6 +311,11 @@
     end
 
     it 'sends an empty hash if no metadata is added' do
+      recvd_rpc = nil
+      rcv_thread = Thread.new do
+        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+      end
+
       call = new_client_call
       # client signals that it's done sending metadata to allow server to
       # respond
@@ -286,7 +325,7 @@
       call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
       # server gets the invocation but sends no metadata back
-      recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+      rcv_thread.join
       expect(recvd_rpc).to_not eq nil
       server_call = recvd_rpc.call
       server_ops = {
@@ -305,6 +344,11 @@
 
     it 'sends all the pairs when keys and values are valid' do
       @valid_metadata.each do |md|
+        recvd_rpc = nil
+        rcv_thread = Thread.new do
+          recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        end
+
         call = new_client_call
         # client signals that it's done sending metadata to allow server to
         # respond
@@ -314,7 +358,7 @@
         call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
         # server gets the invocation but sends no metadata back
-        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        rcv_thread.join
         expect(recvd_rpc).to_not eq nil
         server_call = recvd_rpc.call
         server_ops = {
diff --git a/templates/BUILD.template b/templates/BUILD.template
index 075c399..4e9d8c3 100644
--- a/templates/BUILD.template
+++ b/templates/BUILD.template
@@ -1,7 +1,9 @@
 # GRPC Bazel BUILD file.
-# This currently builds C and C++ code.
+# This currently builds C, C++ and Objective-C code.
 # This file has been automatically generated from a template file.
 # Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
 
 # Copyright 2015, Google Inc.
 # All rights reserved.
@@ -61,6 +63,12 @@
 % endif
 % endfor
 
+% for lib in libs:
+% if lib.name in ("grpc", "gpr"):
+${objc_library(lib)}
+% endif
+% endfor
+
 % for tgt in targets:
 % if tgt.build == 'protoc':
 ${cc_binary(tgt)}
@@ -95,6 +103,40 @@
 )
 </%def>
 
+<%def name="objc_library(lib)">
+objc_library(
+  name = "${lib.name}_objc",
+  srcs = [
+% for src in lib.src:
+    "${src}",
+% endfor
+  ],
+  hdrs = [
+% for hdr in lib.get("public_headers", []):
+    "${hdr}",
+% endfor
+% for hdr in lib.get("headers", []):
+    "${hdr}",
+% endfor
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+% for dep in lib.get("deps", []):
+    ":${dep}_objc",
+% endfor
+% if lib.get('secure', 'no') == 'yes':
+    "//external:libssl_objc",
+% endif
+  ],
+% if lib.get("baselib", false):
+  sdk_dylibs = ["libz"],
+% endif
+)
+</%def>
+
 <%def name="cc_binary(tgt)">
 cc_binary(
   name = "${tgt.name}",
@@ -110,3 +152,74 @@
   ],
 )
 </%def>
+
+objc_path = "src/objective-c"
+
+rx_library_path = objc_path + "/RxLibrary"
+
+objc_library(
+  name = "rx_library",
+  hdrs = glob([
+    rx_library_path + "/*.h",
+    rx_library_path + "/transformations/*.h",
+  ]),
+  srcs = glob([
+    rx_library_path + "/*.m",
+    rx_library_path + "/transformations/*.m",
+  ]),
+  includes = [objc_path],
+  deps = [
+    ":rx_library_private",
+  ],
+)
+
+objc_library(
+  name = "rx_library_private",
+  hdrs = glob([rx_library_path + "/private/*.h"]),
+  srcs = glob([rx_library_path + "/private/*.m"]),
+  visibility = ["//visibility:private"],
+)
+
+objc_client_path = objc_path + "/GRPCClient"
+
+objc_library(
+  name = "grpc_client",
+  hdrs = glob([
+    objc_client_path + "/*.h",
+    objc_client_path + "/private/*.h",
+  ]),
+  srcs = glob([
+    objc_client_path + "/*.m",
+    objc_client_path + "/private/*.m",
+  ]),
+  includes = [objc_path],
+  bundles = [":gRPCCertificates"],
+  deps = [
+    ":grpc_objc",
+    ":rx_library",
+  ],
+)
+
+objc_bundle_library(
+    # The choice of name is signicant here, since it determines the bundle name.
+    name = "gRPCCertificates",
+    resources = ["etc/roots.pem"],
+)
+
+proto_objc_rpc_path = objc_path + "/ProtoRPC"
+
+objc_library(
+  name = "proto_objc_rpc",
+  hdrs = glob([
+    proto_objc_rpc_path + "/*.h",
+  ]),
+  srcs = glob([
+    proto_objc_rpc_path + "/*.m",
+  ]),
+  includes = [objc_path],
+  deps = [
+    ":grpc_client",
+    ":rx_library",
+    "//external:protobuf_objc",
+  ],
+)
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 3f8686f..044db4d 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -2,6 +2,8 @@
 # This currently builds C and C++ code.
 # This file has been automatically generated from a template file.
 # Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
 
 # Copyright 2015, Google Inc.
 # All rights reserved.
@@ -157,7 +159,7 @@
 CXX_tsan = clang++
 LD_tsan = clang
 LDXX_tsan = clang++
-CPPFLAGS_tsan = -O1 -fsanitize=thread -fno-omit-frame-pointer
+CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer
 LDFLAGS_tsan = -fsanitize=thread
 DEFINES_tsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
 
@@ -169,7 +171,7 @@
 LDXX_asan = clang++
 CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer
 LDFLAGS_asan = -fsanitize=address
-DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=5
+DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
 
 VALID_CONFIG_msan = 1
 REQUIRE_CUSTOM_LIBRARIES_msan = 1
@@ -180,7 +182,7 @@
 CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
 OPENSSL_CFLAGS_msan = -DPURIFY
 LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
-DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=20
+DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4
 
 VALID_CONFIG_ubsan = 1
 REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
@@ -191,7 +193,7 @@
 CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer
 OPENSSL_CFLAGS_ubsan = -DPURIFY
 LDFLAGS_ubsan = -fsanitize=undefined
-DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
+DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
 
 VALID_CONFIG_gcov = 1
 CC_gcov = gcc
@@ -227,6 +229,7 @@
 endif
 INSTALL = install
 RM = rm -f
+PKG_CONFIG = pkg-config
 
 ifndef VALID_CONFIG_$(CONFIG)
 $(error Invalid CONFIG value '$(CONFIG)')
@@ -343,6 +346,41 @@
 # These are automatically computed variables.
 # There shouldn't be any need to change anything from now on.
 
+-include cache.mk
+
+CACHE_MK =
+
+HAS_PKG_CONFIG ?= $(shell command -v $(PKG_CONFIG) >/dev/null 2>&1 && echo true || echo false)
+
+ifeq ($(HAS_PKG_CONFIG), true)
+CACHE_MK += HAS_PKG_CONFIG = true,
+endif
+
+PC_TEMPLATE = prefix=$(prefix),\
+exec_prefix=${'\$${prefix}'},\
+includedir=${'\$${prefix}'}/include,\
+libdir=${'\$${exec_prefix}'}/lib,\
+,\
+Name: $(PC_NAME),\
+Description: $(PC_DESCRIPTION),\
+Version: $(VERSION),\
+Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
+Requires.private: $(PC_REQUIRES_PRIVATE),\
+Libs: -L${'\$${libdir}'} $(PC_LIB),\
+Libs.private: $(PC_LIBS_PRIVATE)
+
+# gpr .pc file
+PC_NAME = gRPC Portable Runtime
+PC_DESCRIPTION = gRPC Portable Runtime
+PC_CFLAGS = -pthread
+PC_REQUIRES_PRIVATE =
+PC_LIBS_PRIVATE = -lpthread
+PC_LIB = -lgpr
+ifneq ($(SYSTEM),Darwin)
+PC_LIBS_PRIVATE += -lrt
+endif
+GPR_PC_FILE := $(PC_TEMPLATE)
+
 ifeq ($(SYSTEM),MINGW32)
 SHARED_EXT = dll
 endif
@@ -367,6 +405,13 @@
 OPENSSL_REQUIRES_DL = true
 endif
 
+ifeq ($(HAS_PKG_CONFIG),true)
+OPENSSL_ALPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.2 openssl
+OPENSSL_NPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.1 openssl
+ZLIB_CHECK_CMD = $(PKG_CONFIG) --exists zlib
+PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0-alpha-3 protobuf
+else # HAS_PKG_CONFIG
+
 ifeq ($(SYSTEM),MINGW32)
 OPENSSL_LIBS = ssl32 eay32
 else
@@ -374,41 +419,68 @@
 endif
 
 OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-alpn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
+OPENSSL_NPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-npn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
 ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
-PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
 PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
+
+ifeq ($(OPENSSL_REQUIRES_DL),true)
+OPENSSL_ALPN_CHECK_CMD += -ldl
+OPENSSL_NPN_CHECK_CMD += -ldl
+endif
+
+endif # HAS_PKG_CONFIG
+
+PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
+
 PROTOC_CHECK_CMD = which protoc > /dev/null
 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)
 
-ifeq ($(OPENSSL_REQUIRES_DL),true)
-OPENSSL_ALPN_CHECK_CMD += -ldl
-endif
-
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_PERFTOOLS = $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_SYSTEM_PERFTOOLS),true)
 DEFINES += GRPC_HAVE_PERFTOOLS
 LIBS += profiler
+CACHE_MK += HAS_SYSTEM_PERFTOOLS = true,
 endif
 endif
 
 HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
-HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
-HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY)
+HAS_SYSTEM_OPENSSL_ALPN ?= $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),true)
+HAS_SYSTEM_OPENSSL_NPN = true
+CACHE_MK += HAS_SYSTEM_OPENSSL_ALPN = true,
+else
+HAS_SYSTEM_OPENSSL_NPN ?= $(shell $(OPENSSL_NPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+endif
+ifeq ($(HAS_SYSTEM_OPENSSL_NPN),true)
+CACHE_MK += HAS_SYSTEM_OPENSSL_NPN = true,
+endif
+HAS_SYSTEM_ZLIB ?= $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_SYSTEM_ZLIB),true)
+CACHE_MK += HAS_SYSTEM_ZLIB = true,
+endif
+HAS_SYSTEM_PROTOBUF ?= $(HAS_SYSTEM_PROTOBUF_VERIFY)
+ifeq ($(HAS_SYSTEM_PROTOBUF),true)
+CACHE_MK += HAS_SYSTEM_PROTOBUF = true,
+endif
 else
 # override system libraries if the config requires a custom compiled library
 HAS_SYSTEM_OPENSSL_ALPN = false
+HAS_SYSTEM_OPENSSL_NPN = false
 HAS_SYSTEM_ZLIB = false
 HAS_SYSTEM_PROTOBUF = false
 endif
 
-HAS_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_PROTOC ?= $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_PROTOC),true)
-HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+CACHE_MK += HAS_PROTOC = true,
+HAS_VALID_PROTOC ?= $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_VALID_PROTOC),true)
+CACHE_MK += HAS_VALID_PROTOC = true,
+endif
 else
 HAS_VALID_PROTOC = false
 endif
@@ -416,6 +488,7 @@
 # Check for Systemtap (https://sourceware.org/systemtap/), first by making sure <sys/sdt.h> is present
 # in the system and secondly by checking for the "dtrace" binary (on Linux, this is part of the Systemtap
 # distribution. It's part of the base system on BSD/Solaris machines).
+ifndef HAS_SYSTEMTAP
 HAS_SYSTEMTAP_HEADERS = $(shell $(SYSTEMTAP_HEADERS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_DTRACE = $(shell $(DTRACE_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_SYSTEMTAP = false
@@ -424,7 +497,15 @@
 HAS_SYSTEMTAP = true
 endif
 endif
+endif
 
+ifeq ($(HAS_SYSTEMTAP),true)
+CACHE_MK += HAS_SYSTEMTAP = true,
+endif
+
+# 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.
 ifeq ($(wildcard third_party/openssl/ssl/ssl.h),)
 HAS_EMBEDDED_OPENSSL_ALPN = false
 else
@@ -446,6 +527,9 @@
 HAS_EMBEDDED_PROTOBUF = true
 endif
 
+PC_REQUIRES_GRPC = gpr
+PC_LIBS_GRPC =
+
 ifeq ($(HAS_SYSTEM_ZLIB),false)
 ifeq ($(HAS_EMBEDDED_ZLIB),true)
 ZLIB_DEP = $(LIBDIR)/$(CONFIG)/zlib/libz.a
@@ -454,10 +538,43 @@
 else
 DEP_MISSING += zlib
 endif
+else
+ifeq ($(HAS_PKG_CONFIG),true)
+CPPFLAGS += $(shell $(PKG_CONFIG) --cflags zlib)
+LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L zlib)
+PC_REQUIRES_GRPC += zlib
+else
+PC_LIBS_GRPC += -lz
+endif
 endif
 
-ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),false)
+OPENSSL_PKG_CONFIG = false
+
+PC_REQUIRES_SECURE =
+PC_LIBS_SECURE =
+
+ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),true)
+ifeq ($(HAS_PKG_CONFIG),true)
+OPENSSL_PKG_CONFIG = true
+PC_REQUIRES_SECURE = openssl
+CPPFLAGS := $(shell $(PKG_CONFIG) --cflags openssl) $(CPPFLAGS)
+LDFLAGS_OPENSSL_PKG_CONFIG = $(shell $(PKG_CONFIG) --libs-only-L openssl)
+ifeq ($(SYSTEM),Linux)
+ifneq ($(LDFLAGS_OPENSSL_PKG_CONFIG),)
+LDFLAGS_OPENSSL_PKG_CONFIG += $(shell $(PKG_CONFIG) --libs-only-L openssl | sed s/L/Wl,-rpath,/)
+endif
+endif
+LDFLAGS := $(LDFLAGS_OPENSSL_PKG_CONFIG) $(LDFLAGS)
+else
+LIBS_SECURE = $(OPENSSL_LIBS)
+ifeq ($(OPENSSL_REQUIRES_DL),true)
+LIBS_SECURE += dl
+PC_LIBS_SECURE = $(addprefix -l, $(LIBS_SECURE))
+endif
+endif
+else
 ifeq ($(HAS_EMBEDDED_OPENSSL_ALPN),true)
+USE_SYSTEM_OPENSSL = false
 OPENSSL_DEP = $(LIBDIR)/$(CONFIG)/openssl/libssl.a
 OPENSSL_MERGE_LIBS += $(LIBDIR)/$(CONFIG)/openssl/libssl.a $(LIBDIR)/$(CONFIG)/openssl/libcrypto.a
 # need to prefix these to ensure overriding system libraries
@@ -467,18 +584,63 @@
 LIBS_SECURE = dl
 endif
 else
-NO_SECURE = true
-endif
-else
+ifeq ($(HAS_SYSTEM_OPENSSL_NPN),true)
+USE_SYSTEM_OPENSSL = true
+CPPFLAGS += -DTSI_OPENSSL_ALPN_SUPPORT=0
 LIBS_SECURE = $(OPENSSL_LIBS)
 ifeq ($(OPENSSL_REQUIRES_DL),true)
 LIBS_SECURE += dl
 endif
+else
+NO_SECURE = true
+endif
+endif
 endif
 
+ifeq ($(OPENSSL_PKG_CONFIG),true)
+LDLIBS_SECURE += $(shell $(PKG_CONFIG) --libs-only-l openssl)
+else
 LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
+endif
 
-ifeq ($(HAS_SYSTEM_PROTOBUF),false)
+# grpc .pc file
+PC_NAME = gRPC
+PC_DESCRIPTION = high performance general RPC framework
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPC) $(PC_LIBS_SECURE)
+PC_LIB = -lgrpc
+GRPC_PC_FILE := $(PC_TEMPLATE)
+
+# gprc_unsecure .pc file
+PC_NAME = gRPC unsecure
+PC_DESCRIPTION = high performance general RPC framework without SSL
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
+PC_LIB = -lgrpc
+GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+
+PROTOBUF_PKG_CONFIG = false
+
+PC_REQUIRES_GRPCXX =
+PC_LIBS_GRPCXX =
+
+ifeq ($(HAS_SYSTEM_PROTOBUF),true)
+ifeq ($(HAS_PKG_CONFIG),true)
+PROTOBUF_PKG_CONFIG = true
+PC_REQUIRES_GRPCXX = protobuf
+CPPFLAGS := $(shell $(PKG_CONFIG) --cflags protobuf) $(CPPFLAGS)
+LDFLAGS_PROTOBUF_PKG_CONFIG = $(shell $(PKG_CONFIG) --libs-only-L protobuf)
+ifeq ($(SYSTEM),Linux)
+ifneq ($(LDFLAGS_PROTOBUF_PKG_CONFIG),)
+LDFLAGS_PROTOBUF_PKG_CONFIG += $(shell $(PKG_CONFIG) --libs-only-L protobuf | sed s/L/Wl,-rpath,/)
+endif
+endif
+else
+PC_LIBS_GRPCXX = -lprotobuf
+endif
+else
 ifeq ($(HAS_EMBEDDED_PROTOBUF),true)
 PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a
 CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS)
@@ -487,15 +649,37 @@
 else
 NO_PROTOBUF = true
 endif
-else
 endif
 
 LIBS_PROTOBUF = protobuf
 LIBS_PROTOC = protoc protobuf
 
-LDLIBS_PROTOBUF += $(addprefix -l, $(LIBS_PROTOBUF))
 HOST_LDLIBS_PROTOC += $(addprefix -l, $(LIBS_PROTOC))
 
+ifeq ($(PROTOBUF_PKG_CONFIG),true)
+LDLIBS_PROTOBUF += $(shell $(PKG_CONFIG) --libs-only-l protobuf)
+else
+LDLIBS_PROTOBUF += $(addprefix -l, $(LIBS_PROTOBUF))
+endif
+
+# grpc++ .pc file
+PC_NAME = gRPC++
+PC_DESCRIPTION = C++ wrapper for gRPC
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = grpc $(PC_REQUIRES_GRPCXX)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
+PC_LIB = -lgrpc++
+GRPCXX_PC_FILE := $(PC_TEMPLATE)
+
+# grpc++_unsecure .pc file
+PC_NAME = gRPC++ unsecure
+PC_DESCRIPTION = C++ wrapper for gRPC without SSL
+PC_CFLAGS =
+PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
+PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
+PC_LIB = -lgrpc++
+GRPCXX_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+
 ifeq ($(MAKECMDGOALS),clean)
 NO_DEPS = true
 endif
@@ -566,7 +750,7 @@
 	@echo
 	@echo "DEPENDENCY ERROR"
 	@echo
-	@echo "The target you are trying to run requires OpenSSL with ALPN support."
+	@echo "The target you are trying to run requires OpenSSL."
 	@echo "Your system doesn't have it, and neither does the third_party directory."
 	@echo
 	@echo "Please consult INSTALL to get more information."
@@ -624,6 +808,7 @@
 
 run_dep_checks:
 	$(OPENSSL_ALPN_CHECK_CMD) || true
+	$(OPENSSL_NPN_CHECK_CMD) || true
 	$(ZLIB_CHECK_CMD) || true
 	$(PERFTOOLS_CHECK_CMD) || true
 	$(PROTOBUF_CHECK_CMD) || true
@@ -644,7 +829,7 @@
 else
 ifeq ($(SYSTEM),MINGW32)
 	@echo "We currently don't have a good way to compile OpenSSL in-place under msys."
-	@echo "Please provide an ALPN-capable OpenSSL in your mingw32 system."
+	@echo "Please provide a OpenSSL in your mingw32 system."
 	@echo
 	@echo "Note that you can find a compatible version of the libraries here:"
 	@echo
@@ -686,7 +871,7 @@
 
 static: static_c static_cxx
 
-static_c: \
+static_c: pc_c pc_c_unsecure cache.mk \
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
@@ -694,7 +879,7 @@
 % endfor
 
 
-static_cxx: \
+static_cxx: pc_cxx pc_cxx_unsecure pc_gpr cache.mk \
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c++':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
@@ -704,7 +889,7 @@
 
 shared: shared_c shared_cxx
 
-shared_c: \
+shared_c: pc_c pc_c_unsecure pc_gpr  cache.mk\
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
@@ -712,7 +897,7 @@
 % endfor
 
 
-shared_cxx: \
+shared_cxx: pc_cxx pc_cxx_unsecure cache.mk\
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c++':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
@@ -740,6 +925,15 @@
 % endif
 % endfor
 
+pc_gpr: $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
+
+pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
+
+pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
+
+pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc
+
+pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 privatelibs_cxx: \
 % for lib in libs:
@@ -812,9 +1006,20 @@
 	$(Q) tools/run_tests/run_tests.py -lpython -c$(CONFIG)
 
 
-tools: privatelibs\
+tools: tools_c tools_cxx
+
+
+tools_c: privatelibs_c\
 % for tgt in targets:
-% if tgt.build == 'tool':
+% if tgt.build == 'tool' and not tgt.language=='c++':
+ $(BINDIR)/$(CONFIG)/${tgt.name}\
+% endif
+% endfor
+
+
+tools_cxx: privatelibs_cxx\
+% for tgt in targets:
+% if tgt.build == 'tool' and tgt.language=='c++':
  $(BINDIR)/$(CONFIG)/${tgt.name}\
 % endif
 % endfor
@@ -901,6 +1106,35 @@
 % endfor
 endif
 
+cache.mk::
+	$(E) "[MAKE]    Generating $@"
+	$(Q) echo "$(CACHE_MK)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GPR_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPC_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPC_UNSECURE_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPCXX_PC_FILE)" | tr , '\n' >$@
+
+$(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc:
+	$(E) "[MAKE]    Generating $@"
+	$(Q) mkdir -p $(@D)
+	$(Q) echo "$(GRPCXX_UNSECURE_PC_FILE)" | tr , '\n' >$@
+
 % for p in protos:
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/${p}.pb.cc: protoc_dep_error
@@ -975,7 +1209,7 @@
 
 install-static: install-static_c install-static_cxx
 
-install-static_c: static_c strip-static_c
+install-static_c: static_c strip-static_c install-pkg-config_c
 % for lib in libs:
 % if lib.language == "c":
 % if lib.build == "all":
@@ -986,7 +1220,7 @@
 % endif
 % endfor
 
-install-static_cxx: static_cxx strip-static_cxx
+install-static_cxx: static_cxx strip-static_cxx install-pkg-config_cxx
 % for lib in libs:
 % if lib.language == "c++":
 % if lib.build == "all":
@@ -1025,10 +1259,10 @@
 endif
 </%def>
 
-install-shared_c: shared_c strip-shared_c
+install-shared_c: shared_c strip-shared_c install-pkg-config_c
 ${install_shared("c")}
 
-install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c
+install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-config_cxx
 ${install_shared("c++")}
 
 install-shared_csharp: shared_csharp strip-shared_csharp
@@ -1047,6 +1281,19 @@
 % endfor
 endif
 
+install-pkg-config_c: pc_gpr pc_c pc_c_unsecure
+	$(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
+
+install-pkg-config_cxx: pc_cxx pc_cxx_unsecure
+	$(E) "[INSTALL] Installing C++ pkg-config files"
+	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
+	$(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
+
 install-certs: etc/roots.pem
 	$(E) "[INSTALL] Installing root certificates"
 	$(Q) $(INSTALL) -d $(prefix)/share/grpc
@@ -1074,7 +1321,7 @@
 
 clean:
 	$(E) "[CLEAN]   Cleaning build directories."
-	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR)
+	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) cache.mk
 
 
 # The various libraries
@@ -1114,11 +1361,11 @@
 
 LIB${lib.name.upper()}_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIB${lib.name.upper()}_SRC))))
 
-## If the library requires OpenSSL with ALPN, let's add some restrictions.
+## If the library requires OpenSSL, let's add some restrictions.
 % if lib.get('secure', 'check') == 'yes' or lib.get('secure', 'check') == 'check':
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure libraries if you don't have OpenSSL with ALPN.
+# You can't build secure libraries if you don't have OpenSSL.
 
 $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: openssl_dep_error
 
@@ -1258,7 +1505,7 @@
 % endif
 % if lib.get('secure', 'check') == 'yes' or lib.get('secure', 'check') == 'check':
 ## If the lib was secure, we have to close the Makefile's if that tested
-## the presence of an ALPN-capable OpenSSL.
+## the presence of OpenSSL.
 
 endif
 % endif
@@ -1299,7 +1546,7 @@
 % if tgt.get('secure', 'check') == 'yes' or tgt.get('secure', 'check') == 'check':
 ifeq ($(NO_SECURE),true)
 
-# You can't build secure targets if you don't have OpenSSL with ALPN.
+# You can't build secure targets if you don't have OpenSSL.
 
 $(BINDIR)/$(CONFIG)/${tgt.name}: openssl_dep_error
 
diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template
index c5513f1..d675a1a 100644
--- a/templates/gRPC.podspec.template
+++ b/templates/gRPC.podspec.template
@@ -1,75 +1,102 @@
+# GRPC CocoaPods podspec
+# This file has been automatically generated from a template file.
+# Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
+
+# 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.
+
 <%!
 bad_header_names = ('time.h', 'string.h')
 def fix_header_name(name):
   split_name = name.split('/')
   if split_name[-1] in bad_header_names:
-    return '/'.join(split_name[:-1] + ['grpc_' + split_name[-1]])
-  else:
-    return name
-%>
+    split_name[-1] = 'grpc_' + split_name[-1]
+  if split_name[0] == 'include':
+    split_name = split_name[1:]
+  return '/'.join(split_name)
 
+def grpc_files(libs):
+  out = []
+  for lib in libs:
+    if lib.name in ("grpc", "gpr"):
+      out.extend(fix_header_name(h) for h in lib.get('headers', []))
+      out.extend(fix_header_name(h) for h in lib.get('public_headers', []))
+      out.extend(lib.get('src', []))
+  return out;
+
+def grpc_private_headers(libs):
+  out = []
+  for lib in libs:
+    if lib.name in ("grpc", "gpr"):
+      out.extend(lib.get('headers', []))
+  return out
+%>
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  s.version  = '0.6.0'
+  s.version  = '0.7.0'
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'http://www.grpc.io'
   s.license  = 'New BSD'
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
 
   # s.source = { :git => 'https://github.com/grpc/grpc.git',
-  #              :tag => 'release-0_9_1-objectivec-0.5.1' }
+  #              :tag => 'release-0_10_0-objectivec-0.6.0' }
 
   s.ios.deployment_target = '6.0'
   s.osx.deployment_target = '10.8'
   s.requires_arc = true
 
+  objc_dir = 'src/objective-c'
+
   # Reactive Extensions library for iOS.
-  s.subspec 'RxLibrary' do |rs|
-    rs.source_files = 'src/objective-c/RxLibrary/*.{h,m}',
-                      'src/objective-c/RxLibrary/transformations/*.{h,m}',
-                      'src/objective-c/RxLibrary/private/*.{h,m}'
-    rs.private_header_files = 'src/objective-c/RxLibrary/private/*.h'
+  s.subspec 'RxLibrary' do |ss|
+    src_dir = "#{objc_dir}/RxLibrary"
+    ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
+    ss.private_header_files = "#{src_dir}/private/*.h"
+    ss.header_mappings_dir = "#{objc_dir}"
   end
 
   # Core cross-platform gRPC library, written in C.
-  s.subspec 'C-Core' do |cs|
-    cs.source_files = \
-% for lib in libs:
-% if lib.name in ("grpc", "gpr"):
-% for hdr in lib.get("headers", []):
-'${fix_header_name(hdr)}', \
-% endfor
-% for hdr in lib.get("public_headers", []):
-'${fix_header_name(hdr)}', \
-% endfor
-% for src in lib.src:
-'${src}', \
-% endfor
-% endif
-% endfor
+  s.subspec 'C-Core' do |ss|
+    ss.source_files = ${(',\n' + 22*' ').join('\'%s\'' % f for f in grpc_files(libs))}
 
-    cs.private_header_files = \
-% for lib in libs:
-% if lib.name in ("grpc", "gpr"):
-% for hdr in lib.get("headers", []):
-'${hdr}', \
-% endfor
-% endif
-% endfor
+    ss.private_header_files = ${(',\n' + 30*' ').join('\'%s\'' % f for f in grpc_private_headers(libs))}
 
-    cs.header_mappings_dir = '.'
-    # The core library includes its headers as either "src/core/..." or "grpc/...", meaning we have
-    # to tell XCode to look for headers under the "include" subdirectory too.
-    #
-    # TODO(jcanizales): Instead of doing this, during installation move everything under
-    # "include/grpc" one directory up. The directory names under PODS_ROOT are implementation
-    # details of Cocoapods, and have changed in the past, breaking this podspec.
-    cs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Private/gRPC" ' +
-                                             '"$(PODS_ROOT)/Headers/Private/gRPC/include"' }
+    ss.header_mappings_dir = '.'
 
-    cs.requires_arc = false
-    cs.libraries = 'z'
-    cs.dependency 'OpenSSL', '~> 1.0.200'
+    ss.requires_arc = false
+    ss.libraries = 'z'
+    ss.dependency 'OpenSSL', '~> 1.0.200'
+
+    # ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
   end
 
   # This is a workaround for Cocoapods Issue #1437.
@@ -77,21 +104,24 @@
   # It needs to be here (top-level) instead of in the C-Core subspec because Cocoapods doesn't run
   # prepare_command's of subspecs.
   #
-  # TODO(jcanizales): Try out Todd Reed's solution at Issue #1437.
+  # TODO(jcanizales): Try out others' solutions at Issue #1437.
   s.prepare_command = <<-CMD
+    # Move contents of include up a level to avoid manually specifying include paths
+    cp -r "include/grpc" "."
+
     DIR_TIME="grpc/support"
     BAD_TIME="$DIR_TIME/time.h"
     GOOD_TIME="$DIR_TIME/grpc_time.h"
-    grep -rl "$BAD_TIME" include/grpc src/core | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
-    if [ -f "include/$BAD_TIME" ];
+    grep -rl "$BAD_TIME" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
+    if [ -f "$BAD_TIME" ];
     then
-      mv -f "include/$BAD_TIME" "include/$GOOD_TIME"
+      mv -f "$BAD_TIME" "$GOOD_TIME"
     fi
 
     DIR_STRING="src/core/support"
     BAD_STRING="$DIR_STRING/string.h"
     GOOD_STRING="$DIR_STRING/grpc_string.h"
-    grep -rl "$BAD_STRING" include/grpc src/core | xargs sed -i '' -e s@$BAD_STRING@$GOOD_STRING@g
+    grep -rl "$BAD_STRING" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_STRING@$GOOD_STRING@g
     if [ -f "$BAD_STRING" ];
     then
       mv -f "$BAD_STRING" "$GOOD_STRING"
@@ -99,28 +129,27 @@
   CMD
 
   # Objective-C wrapper around the core gRPC library.
-  s.subspec 'GRPCClient' do |gs|
-    gs.source_files = 'src/objective-c/GRPCClient/*.{h,m}',
-                      'src/objective-c/GRPCClient/private/*.{h,m}'
-    gs.private_header_files = 'src/objective-c/GRPCClient/private/*.h'
-    gs.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
+  s.subspec 'GRPCClient' do |ss|
+    src_dir = "#{objc_dir}/GRPCClient"
+    ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
+    ss.private_header_files = "#{src_dir}/private/*.h"
+    ss.header_mappings_dir = "#{objc_dir}"
 
-    gs.dependency 'gRPC/C-Core'
-    # TODO(jcanizales): Remove this when the prepare_command moves everything under "include/grpc"
-    # one directory up.
-    gs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Public/gRPC/include"' }
-    gs.dependency 'gRPC/RxLibrary'
+    ss.dependency 'gRPC/C-Core'
+    ss.dependency 'gRPC/RxLibrary'
 
     # Certificates, to be able to establish TLS connections:
-    gs.resource_bundles = { 'gRPC' => ['etc/roots.pem'] }
+    ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
   end
 
   # RPC library for ProtocolBuffers, based on gRPC
-  s.subspec 'ProtoRPC' do |ps|
-    ps.source_files = 'src/objective-c/ProtoRPC/*.{h,m}'
+  s.subspec 'ProtoRPC' do |ss|
+    src_dir = "#{objc_dir}/ProtoRPC"
+    ss.source_files = "#{src_dir}/*.{h,m}"
+    ss.header_mappings_dir = "#{objc_dir}"
 
-    ps.dependency 'gRPC/GRPCClient'
-    ps.dependency 'gRPC/RxLibrary'
-    ps.dependency 'Protobuf', '~> 3.0.0-alpha-3'
+    ss.dependency 'gRPC/GRPCClient'
+    ss.dependency 'gRPC/RxLibrary'
+    ss.dependency 'Protobuf', '~> 3.0.0-alpha-3'
   end
 end
diff --git a/src/core/surface/client.h b/templates/src/core/surface/version.c.template
similarity index 84%
copy from src/core/surface/client.h
copy to templates/src/core/surface/version.c.template
index 9db2ccf..936341c 100644
--- a/src/core/surface/client.h
+++ b/templates/src/core/surface/version.c.template
@@ -31,11 +31,11 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+/* This file is autogenerated from:
+   templates/src/core/surface/version.c.template */
 
-#include "src/core/channel/channel_stack.h"
+#include <grpc/grpc.h>
 
-extern const grpc_channel_filter grpc_client_surface_filter;
-
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+const char *grpc_version_string(void) {
+	return "${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}";
+}
diff --git a/templates/tools/doxygen/Doxyfile.include b/templates/tools/doxygen/Doxyfile.include
index 1391016..2934ebe 100644
--- a/templates/tools/doxygen/Doxyfile.include
+++ b/templates/tools/doxygen/Doxyfile.include
@@ -778,7 +778,7 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = ${' '.join(
+INPUT                  = ${' \\\n'.join(
                                itertools.chain.from_iterable(
 			           target.public_headers +
 				   ([]
diff --git a/templates/tools/run_tests/sources_and_headers.json.template b/templates/tools/run_tests/sources_and_headers.json.template
new file mode 100644
index 0000000..1c0e042
--- /dev/null
+++ b/templates/tools/run_tests/sources_and_headers.json.template
@@ -0,0 +1,33 @@
+<%!
+import json
+import os
+
+def proto_headers(src):
+	out = []
+	for f in src:
+		name, ext = os.path.splitext(f)
+		if ext == '.proto':
+			out.extend(fmt % name for fmt in ['%s.grpc.pb.h', '%s.pb.h'])
+	return out
+
+def no_protos(src):
+	out = []
+	for f in src:
+		if os.path.splitext(f)[1] != '.proto':
+			out.append(f)
+	return out
+%>
+
+${json.dumps([{"name": tgt.name,
+               "language": tgt.language,
+               "src": sorted(
+                   no_protos(tgt.src) + 
+                   tgt.get('public_headers', []) + 
+                   tgt.get('headers', [])),
+               "headers": sorted(
+                   tgt.get('public_headers', []) + 
+                   tgt.get('headers', []) + 
+                   proto_headers(tgt.src)),
+               "deps": sorted(tgt.get('deps', []))}
+              for tgt in (targets + libs)],
+             sort_keys=True, indent=2)}
diff --git a/templates/vsprojects/Grpc.mak.template b/templates/vsprojects/Grpc.mak.template
index b75537d..9d85376 100644
--- a/templates/vsprojects/Grpc.mak.template
+++ b/templates/vsprojects/Grpc.mak.template
@@ -72,6 +72,12 @@
 
 all: buildtests
 
+tools:
+
+tools_c:
+
+tools_cxx:
+
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
diff --git a/src/core/surface/client.h b/test/build/openssl-npn.c
similarity index 76%
copy from src/core/surface/client.h
copy to test/build/openssl-npn.c
index 9db2ccf..90ae8ef 100644
--- a/src/core/surface/client.h
+++ b/test/build/openssl-npn.c
@@ -31,11 +31,15 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+/* This is just a compilation test, to see if we have a version of OpenSSL with
+   NPN support installed. It's not meant to be run, and all of the values and
+   function calls there are non-sensical. The code is only meant to test the
+   presence of symbols, and we're expecting a compilation failure otherwise. */
 
-#include "src/core/channel/channel_stack.h"
+#include <stdlib.h>
+#include <openssl/ssl.h>
 
-extern const grpc_channel_filter grpc_client_surface_filter;
-
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+int main() {
+  SSL_get0_next_proto_negotiated(NULL, NULL, NULL);
+  return OPENSSL_NPN_UNSUPPORTED;
+}
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index e9adcf3..b050227 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -41,6 +41,7 @@
 #include "src/core/support/string.h"
 #include "src/core/transport/chttp2_transport.h"
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 
@@ -63,14 +64,14 @@
   gpr_event_set(&a->done_write, (void *)1);
 }
 
-static grpc_transport_setup_result server_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void server_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   thd_args *a = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  return grpc_server_setup_transport(a->server, transport, extra_filters,
-                                     GPR_ARRAY_SIZE(extra_filters), mdctx,
-                                     grpc_server_get_channel_args(a->server));
+  grpc_server_setup_transport(a->server, transport, extra_filters,
+                              GPR_ARRAY_SIZE(extra_filters), mdctx,
+                              grpc_server_get_channel_args(a->server));
 }
 
 void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator,
@@ -80,15 +81,19 @@
   thd_args a;
   gpr_thd_id id;
   char *hex;
+  grpc_transport *transport;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
   gpr_slice slice =
       gpr_slice_from_copied_buffer(client_payload, client_payload_length);
 
-  hex =
-      gpr_hexdump(client_payload, client_payload_length, GPR_HEXDUMP_PLAINTEXT);
+  hex = gpr_dump(client_payload, client_payload_length,
+                 GPR_DUMP_HEX | GPR_DUMP_ASCII);
 
   /* Add a debug log */
   gpr_log(GPR_INFO, "TEST: %s", hex);
 
+  gpr_free(hex);
+
   /* Init grpc */
   grpc_init();
 
@@ -103,8 +108,9 @@
   a.validator = validator;
   grpc_server_register_completion_queue(a.server, a.cq);
   grpc_server_start(a.server);
-  grpc_create_chttp2_transport(server_setup_transport, &a, NULL, sfd.server,
-                               NULL, 0, grpc_mdctx_create(), 0);
+  transport = grpc_create_chttp2_transport(NULL, sfd.server, mdctx, 0);
+  server_setup_transport(&a, transport, mdctx);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 
   /* Bind everything into the same pollset */
   grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
diff --git a/test/core/bad_client/gen_build_json.py b/test/core/bad_client/gen_build_json.py
index a6fa266..33bf65a 100755
--- a/test/core/bad_client/gen_build_json.py
+++ b/test/core/bad_client/gen_build_json.py
@@ -54,6 +54,15 @@
             'language': 'c',
             'src': [
               'test/core/bad_client/bad_client.c'
+            ],
+            'headers': [
+              'test/core/bad_client/bad_client.h'
+            ],
+            'deps': [
+              'grpc_test_util_unsecure',
+              'grpc_unsecure',
+              'gpr_test_util',
+              'gpr'
             ]
           }],
       'targets': [
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index fe92f2f..eca2a40 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -39,7 +39,7 @@
 #include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
-static void channel_init_func(grpc_channel_element *elem,
+static void channel_init_func(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
                               int is_last) {
@@ -54,7 +54,7 @@
 
 static void call_init_func(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_op *initial_op) {
+                           grpc_transport_stream_op *initial_op) {
   ++*(int *)(elem->channel_data);
   *(int *)(elem->call_data) = 0;
 }
@@ -65,19 +65,19 @@
   ++*(int *)(elem->channel_data);
 }
 
-static void call_func(grpc_call_element *elem, grpc_transport_op *op) {
+static void call_func(grpc_call_element *elem, grpc_transport_stream_op *op) {
   ++*(int *)(elem->call_data);
 }
 
-static void channel_func(grpc_channel_element *elem,
-                         grpc_channel_element *from_elem, grpc_channel_op *op) {
+static void channel_func(grpc_channel_element *elem, grpc_transport_op *op) {
   ++*(int *)(elem->channel_data);
 }
 
 static void test_create_channel_stack(void) {
   const grpc_channel_filter filter = {
-      call_func, channel_func, sizeof(int), call_init_func, call_destroy_func,
-      sizeof(int), channel_init_func, channel_destroy_func, "some_test_filter"};
+      call_func,         channel_func,         sizeof(int),
+      call_init_func,    call_destroy_func,    sizeof(int),
+      channel_init_func, channel_destroy_func, "some_test_filter"};
   const grpc_channel_filter *filters = &filter;
   grpc_channel_stack *channel_stack;
   grpc_call_stack *call_stack;
@@ -99,7 +99,7 @@
   chan_args.args = &arg;
 
   channel_stack = gpr_malloc(grpc_channel_stack_size(&filters, 1));
-  grpc_channel_stack_init(&filters, 1, &chan_args, metadata_context,
+  grpc_channel_stack_init(&filters, 1, NULL, &chan_args, metadata_context,
                           channel_stack);
   GPR_ASSERT(channel_stack->count == 1);
   channel_elem = grpc_channel_stack_element(channel_stack, 0);
diff --git a/test/core/client_config/uri_parser_test.c b/test/core/client_config/uri_parser_test.c
new file mode 100644
index 0000000..3451ca1
--- /dev/null
+++ b/test/core/client_config/uri_parser_test.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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/uri_parser.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+
+#include "test/core/util/test_config.h"
+
+static void test_succeeds(const char *uri_text, const char *scheme,
+                          const char *authority, const char *path) {
+  grpc_uri *uri = grpc_uri_parse(uri_text, 0);
+  GPR_ASSERT(uri);
+  GPR_ASSERT(0 == strcmp(scheme, uri->scheme));
+  GPR_ASSERT(0 == strcmp(authority, uri->authority));
+  GPR_ASSERT(0 == strcmp(path, uri->path));
+  grpc_uri_destroy(uri);
+}
+
+static void test_fails(const char *uri_text) {
+  GPR_ASSERT(NULL == grpc_uri_parse(uri_text, 0));
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_succeeds("http://www.google.com", "http", "www.google.com", "");
+  test_succeeds("dns:///foo", "dns", "", "/foo");
+  test_succeeds("http://www.google.com:90", "http", "www.google.com:90", "");
+  test_succeeds("a192.4-df:foo.coom", "a192.4-df", "", "foo.coom");
+  test_succeeds("a+b:foo.coom", "a+b", "", "foo.coom");
+  test_succeeds("zookeeper://127.0.0.1:2181/foo/bar", "zookeeper", "127.0.0.1:2181", "/foo/bar");
+  test_fails("xyz");
+  test_fails("http://www.google.com?why-are-you-using-queries");
+  test_fails("dns:foo.com#fragments-arent-supported-here");
+  test_fails("http:?huh");
+  test_fails("unix:#yeah-right");
+  return 0;
+}
diff --git a/test/core/compression/message_compress_test.c b/test/core/compression/message_compress_test.c
index 4033c18..f5f21cf 100644
--- a/test/core/compression/message_compress_test.c
+++ b/test/core/compression/message_compress_test.c
@@ -61,13 +61,15 @@
   gpr_slice_buffer output;
   gpr_slice final;
   int was_compressed;
+  char *algorithm_name;
 
+  GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algorithm_name) != 0);
   gpr_log(GPR_INFO,
           "assert_passthrough: value_length=%d value_hash=0x%08x "
           "algorithm='%s' uncompressed_split='%s' compressed_split='%s'",
           GPR_SLICE_LENGTH(value), gpr_murmur_hash3(GPR_SLICE_START_PTR(value),
                                                     GPR_SLICE_LENGTH(value), 0),
-          grpc_compression_algorithm_name(algorithm),
+          algorithm_name,
           grpc_slice_split_mode_name(uncompressed_split_mode),
           grpc_slice_split_mode_name(compressed_split_mode));
 
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index 8a30e01..c28932c 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -40,6 +40,7 @@
 #include "src/core/surface/event_string.h"
 #include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
@@ -144,7 +145,17 @@
 }
 
 int byte_buffer_eq_string(grpc_byte_buffer *bb, const char *str) {
-  return byte_buffer_eq_slice(bb, gpr_slice_from_copied_string(str));
+  grpc_byte_buffer_reader reader;
+  grpc_byte_buffer* rbb;
+  int res;
+
+  grpc_byte_buffer_reader_init(&reader, bb);
+  rbb = grpc_raw_byte_buffer_from_reader(&reader);
+  res = byte_buffer_eq_slice(rbb, gpr_slice_from_copied_string(str));
+  grpc_byte_buffer_reader_destroy(&reader);
+  grpc_byte_buffer_destroy(rbb);
+
+  return res;
 }
 
 static void verify_matches(expectation *e, grpc_event *ev) {
@@ -167,6 +178,9 @@
 static void expectation_to_strvec(gpr_strvec *buf, expectation *e) {
   char *tmp;
 
+  gpr_asprintf(&tmp, "%p ", e->tag);
+  gpr_strvec_add(buf, tmp);
+
   switch (e->type) {
     case GRPC_OP_COMPLETE:
       gpr_asprintf(&tmp, "GRPC_OP_COMPLETE result=%d", e->success);
@@ -245,7 +259,8 @@
 }
 
 void cq_verify_empty(cq_verifier *v) {
-  gpr_timespec deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(1));
+  gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                       gpr_time_from_seconds(1, GPR_TIMESPAN));
   grpc_event ev;
 
   GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 06cbba2..7d3568c 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -62,12 +62,10 @@
   char *server_hostport;
   grpc_channel *client;
   grpc_server *server;
-  grpc_completion_queue *client_cq;
-  grpc_completion_queue *server_cq;
+  grpc_completion_queue *cq;
   grpc_call *c;
   grpc_call *s;
-  cq_verifier *v_client;
-  cq_verifier *v_server;
+  cq_verifier *cqv;
   gpr_timespec deadline;
   int got_port;
   grpc_op ops[6];
@@ -93,9 +91,9 @@
   grpc_call_details_init(&call_details);
 
   /* Create server. */
-  server_cq = grpc_completion_queue_create();
+  cq = grpc_completion_queue_create();
   server = grpc_server_create(NULL);
-  grpc_server_register_completion_queue(server, server_cq);
+  grpc_server_register_completion_queue(server, cq);
   GPR_ASSERT((got_port = grpc_server_add_http2_port(server, server_hostport)) >
              0);
   if (port == 0) {
@@ -104,13 +102,11 @@
     GPR_ASSERT(port == got_port);
   }
   grpc_server_start(server);
-  v_server = cq_verifier_create(server_cq);
+  cqv = cq_verifier_create(cq);
 
   /* Create client. */
   gpr_join_host_port(&client_hostport, client_host, port);
-  client_cq = grpc_completion_queue_create();
   client = grpc_channel_create(client_hostport, NULL);
-  v_client = cq_verifier_create(client_cq);
 
   gpr_log(GPR_INFO, "Testing with server=%s client=%s (expecting %s)",
           server_hostport, client_hostport, expect_ok ? "success" : "failure");
@@ -128,7 +124,7 @@
   }
 
   /* Send a trivial request. */
-  c = grpc_channel_create_call(client, client_cq, "/foo", "foo.test.google.fr",
+  c = grpc_channel_create_call(client, cq, "/foo", "foo.test.google.fr",
                                deadline);
   GPR_ASSERT(c);
 
@@ -155,12 +151,11 @@
 
   if (expect_ok) {
     /* Check for a successful request. */
-    GPR_ASSERT(GRPC_CALL_OK ==
-               grpc_server_request_call(server, &s, &call_details,
-                                        &request_metadata_recv, server_cq,
-                                        server_cq, tag(101)));
-    cq_expect_completion(v_server, tag(101), 1);
-    cq_verify(v_server);
+    GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                   server, &s, &call_details,
+                                   &request_metadata_recv, cq, cq, tag(101)));
+    cq_expect_completion(cqv, tag(101), 1);
+    cq_verify(cqv);
 
     op = ops;
     op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -180,45 +175,41 @@
     GPR_ASSERT(GRPC_CALL_OK ==
                grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-    cq_expect_completion(v_server, tag(102), 1);
-    cq_verify(v_server);
-
-    cq_expect_completion(v_client, tag(1), 1);
-    cq_verify(v_client);
+    cq_expect_completion(cqv, tag(102), 1);
+    cq_expect_completion(cqv, tag(1), 1);
+    cq_verify(cqv);
 
     GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
     GPR_ASSERT(0 == strcmp(details, "xyz"));
     GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
     GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
-    GPR_ASSERT(was_cancelled == 0);
+    GPR_ASSERT(was_cancelled == 1);
 
     grpc_call_destroy(s);
   } else {
     /* Check for a failed connection. */
-    cq_expect_completion(v_client, tag(1), 1);
-    cq_verify(v_client);
+    cq_expect_completion(cqv, tag(1), 1);
+    cq_verify(cqv);
 
     GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
   }
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   /* Destroy client. */
   grpc_channel_destroy(client);
-  grpc_completion_queue_shutdown(client_cq);
-  drain_cq(client_cq);
-  grpc_completion_queue_destroy(client_cq);
 
   /* Destroy server. */
-  grpc_server_shutdown_and_notify(server, server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  grpc_server_shutdown_and_notify(server, cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(cq, tag(1000),
+                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(server);
-  grpc_completion_queue_shutdown(server_cq);
-  drain_cq(server_cq);
-  grpc_completion_queue_destroy(server_cq);
+  grpc_completion_queue_shutdown(cq);
+  drain_cq(cq);
+  grpc_completion_queue_destroy(cq);
 
   grpc_call_details_destroy(&call_details);
   gpr_free(details);
diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h
index a61c725..a18c702 100644
--- a/test/core/end2end/end2end_tests.h
+++ b/test/core/end2end/end2end_tests.h
@@ -44,8 +44,7 @@
 #define FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS 4
 
 struct grpc_end2end_test_fixture {
-  grpc_completion_queue *server_cq;
-  grpc_completion_queue *client_cq;
+  grpc_completion_queue *cq;
   grpc_server *server;
   grpc_channel *client;
   void *fixture_data;
@@ -65,4 +64,4 @@
 
 void grpc_end2end_tests(grpc_end2end_test_config config);
 
-#endif  /* GRPC_TEST_CORE_END2END_END2END_TESTS_H */
+#endif /* GRPC_TEST_CORE_END2END_END2END_TESTS_H */
diff --git a/test/core/end2end/fixtures/chttp2_fake_security.c b/test/core/end2end/fixtures/chttp2_fake_security.c
index 5323e29..f879b43 100644
--- a/test/core/end2end/fixtures/chttp2_fake_security.c
+++ b/test/core/end2end/fixtures/chttp2_fake_security.c
@@ -60,8 +60,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -83,8 +82,9 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
-  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr, server_creds));
+  grpc_server_register_completion_queue(f->server, f->cq);
+  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
+                                               server_creds));
   grpc_server_credentials_release(server_creds);
   grpc_server_start(f->server);
 }
diff --git a/test/core/end2end/fixtures/chttp2_fullstack.c b/test/core/end2end/fixtures/chttp2_fullstack.c
index f92b40e..8a1530e 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack.c
@@ -39,7 +39,6 @@
 #include "src/core/channel/connected_channel.h"
 #include "src/core/channel/http_server_filter.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
@@ -65,8 +64,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -75,6 +73,7 @@
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
   f->client = grpc_channel_create(ffd->localaddr, client_args);
+  GPR_ASSERT(f->client);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
@@ -84,7 +83,7 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   GPR_ASSERT(grpc_server_add_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
new file mode 100644
index 0000000..0a9a312
--- /dev/null
+++ b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
@@ -0,0 +1,135 @@
+/*
+ *
+ * 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/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/client_channel.h"
+#include "src/core/channel/connected_channel.h"
+#include "src/core/channel/http_server_filter.h"
+#include "src/core/surface/channel.h"
+#include "src/core/surface/server.h"
+#include "src/core/transport/chttp2_transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+typedef struct fullstack_compression_fixture_data {
+  char *localaddr;
+  grpc_channel_args* client_args_compression;
+  grpc_channel_args* server_args_compression;
+} fullstack_compression_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_fullstack_compression(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_compression_fixture_data *ffd =
+      gpr_malloc(sizeof(fullstack_compression_fixture_data));
+  memset(ffd, 0, sizeof(fullstack_compression_fixture_data));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  memset(&f, 0, sizeof(f));
+  f.fixture_data = ffd;
+  f.cq = grpc_completion_queue_create();
+
+  return f;
+}
+
+void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *client_args) {
+  fullstack_compression_fixture_data *ffd = f->fixture_data;
+  if (ffd->client_args_compression != NULL) {
+    grpc_channel_args_destroy(ffd->client_args_compression);
+  }
+  ffd->client_args_compression = grpc_channel_args_set_compression_algorithm(
+      client_args, GRPC_COMPRESS_GZIP);
+  f->client = grpc_channel_create(ffd->localaddr, ffd->client_args_compression);
+}
+
+void chttp2_init_server_fullstack_compression(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *server_args) {
+  fullstack_compression_fixture_data *ffd = f->fixture_data;
+  if (ffd->server_args_compression != NULL) {
+    grpc_channel_args_destroy(ffd->server_args_compression);
+  }
+  ffd->server_args_compression = grpc_channel_args_set_compression_algorithm(
+      server_args, GRPC_COMPRESS_GZIP);
+  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);
+  GPR_ASSERT(grpc_server_add_http2_port(f->server, ffd->localaddr));
+  grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_fullstack_compression(grpc_end2end_test_fixture *f) {
+  fullstack_compression_fixture_data *ffd = f->fixture_data;
+  grpc_channel_args_destroy(ffd->client_args_compression);
+  grpc_channel_args_destroy(ffd->server_args_compression);
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/fullstack_compression", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_fullstack_compression,
+     chttp2_init_client_fullstack_compression,
+     chttp2_init_server_fullstack_compression,
+     chttp2_tear_down_fullstack_compression},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(configs[i]);
+  }
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
index 02aa575..351e1c5 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
@@ -42,7 +42,6 @@
 #include "src/core/channel/http_server_filter.h"
 #include "src/core/support/string.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
@@ -71,8 +70,7 @@
                unique++);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -90,7 +88,7 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   GPR_ASSERT(grpc_server_add_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 f92b40e..69860d0 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
@@ -39,7 +39,6 @@
 #include "src/core/channel/connected_channel.h"
 #include "src/core/channel/http_server_filter.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
@@ -65,8 +64,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -84,7 +82,7 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   GPR_ASSERT(grpc_server_add_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
 }
@@ -105,6 +103,8 @@
 int main(int argc, char **argv) {
   size_t i;
 
+  grpc_platform_become_multipoller = grpc_poll_become_multipoller;
+
   grpc_test_init(argc, argv);
   grpc_init();
 
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
index 6d1b7b5..73a3611 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
@@ -63,8 +63,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -86,8 +85,9 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
-  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr, server_creds));
+  grpc_server_register_completion_queue(f->server, f->cq);
+  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
+                                               server_creds));
   grpc_server_credentials_release(server_creds);
   grpc_server_start(f->server);
 }
@@ -105,7 +105,7 @@
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
   grpc_channel_args *new_client_args =
-      grpc_channel_args_copy_and_add(client_args, &ssl_name_override);
+      grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);
   grpc_channel_args_destroy(new_client_args);
 }
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 a5865d3..b1ac3e5 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,8 +63,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -86,7 +85,7 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
                                                server_creds));
   grpc_server_credentials_release(server_creds);
@@ -106,7 +105,7 @@
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
   grpc_channel_args *new_client_args =
-      grpc_channel_args_copy_and_add(client_args, &ssl_name_override);
+      grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);
   grpc_channel_args_destroy(new_client_args);
 }
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 4a15d50..de418bf 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
@@ -61,8 +61,7 @@
   gpr_join_host_port(&ffd->localaddr, "localhost", port);
 
   f.fixture_data = ffd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   return f;
 }
@@ -84,8 +83,9 @@
     grpc_server_destroy(f->server);
   }
   f->server = grpc_server_create(server_args);
-  grpc_server_register_completion_queue(f->server, f->server_cq);
-  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr, server_creds));
+  grpc_server_register_completion_queue(f->server, f->cq);
+  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
+                                               server_creds));
   grpc_server_credentials_release(server_creds);
   grpc_server_start(f->server);
 }
@@ -108,7 +108,7 @@
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
   grpc_channel_args *new_client_args =
-      grpc_channel_args_copy_and_add(client_args, &ssl_name_override);
+      grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_oauth2_creds);
   grpc_channel_args_destroy(new_client_args);
   grpc_credentials_release(ssl_creds);
diff --git a/test/core/end2end/fixtures/chttp2_socket_pair.c b/test/core/end2end/fixtures/chttp2_socket_pair.c
index 48c121c..37b61cf 100644
--- a/test/core/end2end/fixtures/chttp2_socket_pair.c
+++ b/test/core/end2end/fixtures/chttp2_socket_pair.c
@@ -36,13 +36,13 @@
 #include <string.h>
 
 #include "src/core/channel/client_channel.h"
+#include "src/core/channel/compress_filter.h"
 #include "src/core/channel/connected_channel.h"
 #include "src/core/channel/http_client_filter.h"
 #include "src/core/channel/http_server_filter.h"
 #include "src/core/iomgr/endpoint_pair.h"
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
@@ -56,14 +56,14 @@
 /* chttp2 transport that is immediately available (used for testing
    connected_channel without a client_channel */
 
-static grpc_transport_setup_result server_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void server_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   grpc_end2end_test_fixture *f = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  return grpc_server_setup_transport(f->server, transport, extra_filters,
-                                     GPR_ARRAY_SIZE(extra_filters), mdctx,
-                                     grpc_server_get_channel_args(f->server));
+  grpc_server_setup_transport(f->server, transport, extra_filters,
+                              GPR_ARRAY_SIZE(extra_filters), mdctx,
+                              grpc_server_get_channel_args(f->server));
 }
 
 typedef struct {
@@ -71,12 +71,12 @@
   grpc_channel_args *client_args;
 } sp_client_setup;
 
-static grpc_transport_setup_result client_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void client_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   sp_client_setup *cs = ts;
 
-  const grpc_channel_filter *filters[] = {&grpc_client_surface_filter,
-                                          &grpc_http_client_filter,
+  const grpc_channel_filter *filters[] = {&grpc_http_client_filter,
+                                          &grpc_compress_filter,
                                           &grpc_connected_channel_filter};
   size_t nfilters = sizeof(filters) / sizeof(*filters);
   grpc_channel *channel = grpc_channel_create_from_filters(
@@ -84,8 +84,8 @@
 
   cs->f->client = channel;
 
-  return grpc_connected_channel_bind_transport(
-      grpc_channel_get_channel_stack(channel), transport);
+  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
+                                        transport);
 }
 
 static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
@@ -95,8 +95,7 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
 
@@ -106,23 +105,29 @@
 static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *client_args) {
   grpc_endpoint_pair *sfd = f->fixture_data;
+  grpc_transport *transport;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
   sp_client_setup cs;
   cs.client_args = client_args;
   cs.f = f;
-  grpc_create_chttp2_transport(client_setup_transport, &cs, client_args,
-                               sfd->client, NULL, 0, grpc_mdctx_create(), 1);
+  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1);
+  client_setup_transport(&cs, transport, mdctx);
   GPR_ASSERT(f->client);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *server_args) {
   grpc_endpoint_pair *sfd = f->fixture_data;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+  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->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   grpc_server_start(f->server);
-  grpc_create_chttp2_transport(server_setup_transport, f, server_args,
-                               sfd->server, NULL, 0, grpc_mdctx_create(), 0);
+  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
+  server_setup_transport(f, transport, mdctx);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
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 1d2e6f5..2ec2697 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
@@ -39,10 +39,10 @@
 #include "src/core/channel/connected_channel.h"
 #include "src/core/channel/http_client_filter.h"
 #include "src/core/channel/http_server_filter.h"
+#include "src/core/channel/compress_filter.h"
 #include "src/core/iomgr/endpoint_pair.h"
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
@@ -56,14 +56,14 @@
 /* chttp2 transport that is immediately available (used for testing
    connected_channel without a client_channel */
 
-static grpc_transport_setup_result server_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void server_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   grpc_end2end_test_fixture *f = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  return grpc_server_setup_transport(f->server, transport, extra_filters,
-                                     GPR_ARRAY_SIZE(extra_filters), mdctx,
-                                     grpc_server_get_channel_args(f->server));
+  grpc_server_setup_transport(f->server, transport, extra_filters,
+                              GPR_ARRAY_SIZE(extra_filters), mdctx,
+                              grpc_server_get_channel_args(f->server));
 }
 
 typedef struct {
@@ -71,12 +71,12 @@
   grpc_channel_args *client_args;
 } sp_client_setup;
 
-static grpc_transport_setup_result client_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void client_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   sp_client_setup *cs = ts;
 
-  const grpc_channel_filter *filters[] = {&grpc_client_surface_filter,
-                                          &grpc_http_client_filter,
+  const grpc_channel_filter *filters[] = {&grpc_http_client_filter,
+                                          &grpc_compress_filter,
                                           &grpc_connected_channel_filter};
   size_t nfilters = sizeof(filters) / sizeof(*filters);
   grpc_channel *channel = grpc_channel_create_from_filters(
@@ -84,8 +84,8 @@
 
   cs->f->client = channel;
 
-  return grpc_connected_channel_bind_transport(
-      grpc_channel_get_channel_stack(channel), transport);
+  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
+                                        transport);
 }
 
 static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
@@ -95,8 +95,7 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", 1);
 
@@ -106,23 +105,29 @@
 static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *client_args) {
   grpc_endpoint_pair *sfd = f->fixture_data;
+  grpc_transport *transport;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
   sp_client_setup cs;
   cs.client_args = client_args;
   cs.f = f;
-  grpc_create_chttp2_transport(client_setup_transport, &cs, client_args,
-                               sfd->client, NULL, 0, grpc_mdctx_create(), 1);
+  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1);
+  client_setup_transport(&cs, transport, mdctx);
   GPR_ASSERT(f->client);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *server_args) {
   grpc_endpoint_pair *sfd = f->fixture_data;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+  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->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   grpc_server_start(f->server);
-  grpc_create_chttp2_transport(server_setup_transport, f, server_args,
-                               sfd->server, NULL, 0, grpc_mdctx_create(), 0);
+  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
+  server_setup_transport(f, transport, mdctx);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
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 0834987..3aa364c 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
@@ -39,11 +39,11 @@
 #include "src/core/channel/connected_channel.h"
 #include "src/core/channel/http_client_filter.h"
 #include "src/core/channel/http_server_filter.h"
+#include "src/core/channel/compress_filter.h"
 #include "src/core/iomgr/endpoint_pair.h"
 #include "src/core/iomgr/iomgr.h"
 #include "src/core/support/env.h"
 #include "src/core/surface/channel.h"
-#include "src/core/surface/client.h"
 #include "src/core/surface/server.h"
 #include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
@@ -57,14 +57,14 @@
 /* chttp2 transport that is immediately available (used for testing
    connected_channel without a client_channel */
 
-static grpc_transport_setup_result server_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void server_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   grpc_end2end_test_fixture *f = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  return grpc_server_setup_transport(f->server, transport, extra_filters,
-                                     GPR_ARRAY_SIZE(extra_filters), mdctx,
-                                     grpc_server_get_channel_args(f->server));
+  grpc_server_setup_transport(f->server, transport, extra_filters,
+                              GPR_ARRAY_SIZE(extra_filters), mdctx,
+                              grpc_server_get_channel_args(f->server));
 }
 
 typedef struct {
@@ -72,12 +72,12 @@
   grpc_channel_args *client_args;
 } sp_client_setup;
 
-static grpc_transport_setup_result client_setup_transport(
-    void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
+static void client_setup_transport(void *ts, grpc_transport *transport,
+                                   grpc_mdctx *mdctx) {
   sp_client_setup *cs = ts;
 
-  const grpc_channel_filter *filters[] = {&grpc_client_surface_filter,
-                                          &grpc_http_client_filter,
+  const grpc_channel_filter *filters[] = {&grpc_http_client_filter,
+                                          &grpc_compress_filter,
                                           &grpc_connected_channel_filter};
   size_t nfilters = sizeof(filters) / sizeof(*filters);
   grpc_channel *channel = grpc_channel_create_from_filters(
@@ -85,8 +85,8 @@
 
   cs->f->client = channel;
 
-  return grpc_connected_channel_bind_transport(
-      grpc_channel_get_channel_stack(channel), transport);
+  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
+                                        transport);
 }
 
 static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
@@ -96,8 +96,7 @@
   grpc_end2end_test_fixture f;
   memset(&f, 0, sizeof(f));
   f.fixture_data = sfd;
-  f.client_cq = grpc_completion_queue_create();
-  f.server_cq = grpc_completion_queue_create();
+  f.cq = grpc_completion_queue_create();
 
   *sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
 
@@ -107,23 +106,29 @@
 static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *client_args) {
   grpc_endpoint_pair *sfd = f->fixture_data;
+  grpc_transport *transport;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
   sp_client_setup cs;
   cs.client_args = client_args;
   cs.f = f;
-  grpc_create_chttp2_transport(client_setup_transport, &cs, client_args,
-                               sfd->client, NULL, 0, grpc_mdctx_create(), 1);
+  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1);
+  client_setup_transport(&cs, transport, mdctx);
   GPR_ASSERT(f->client);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *server_args) {
   grpc_endpoint_pair *sfd = f->fixture_data;
+  grpc_mdctx *mdctx = grpc_mdctx_create();
+  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->server_cq);
+  grpc_server_register_completion_queue(f->server, f->cq);
   grpc_server_start(f->server);
-  grpc_create_chttp2_transport(server_setup_transport, f, server_args,
-                               sfd->server, NULL, 0, grpc_mdctx_create(), 0);
+  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
+  server_setup_transport(f, transport, mdctx);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0);
 }
 
 static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
diff --git a/test/core/end2end/gen_build_json.py b/test/core/end2end/gen_build_json.py
index 6644752..8b0dd31 100755
--- a/test/core/end2end/gen_build_json.py
+++ b/test/core/end2end/gen_build_json.py
@@ -44,6 +44,7 @@
 END2END_FIXTURES = {
     'chttp2_fake_security': default_secure_fixture_options,
     'chttp2_fullstack': default_unsecure_fixture_options,
+    'chttp2_fullstack_compression': default_unsecure_fixture_options,
     'chttp2_fullstack_with_poll': FixtureOptions(False, ['posix']),
     'chttp2_fullstack_uds_posix': FixtureOptions(False, ['posix']),
     'chttp2_simple_ssl_fullstack': default_secure_fixture_options,
@@ -60,7 +61,7 @@
 # maps test names to options
 END2END_TESTS = {
     'bad_hostname': default_test_options,
-    'cancel_after_accept': TestOptions(flaky=True, secure=False),
+    'cancel_after_accept': default_test_options,
     'cancel_after_accept_and_writes_closed': default_test_options,
     'cancel_after_invoke': default_test_options,
     'cancel_before_invoke': default_test_options,
@@ -71,7 +72,7 @@
     'early_server_shutdown_finishes_tags': default_test_options,
     'empty_batch': default_test_options,
     'graceful_server_shutdown': default_test_options,
-    'invoke_large_request': TestOptions(flaky=True, secure=False),
+    'invoke_large_request': default_test_options,
     'max_concurrent_streams': default_test_options,
     'max_message_length': default_test_options,
     'no_op': default_test_options,
@@ -84,6 +85,7 @@
     'request_response_with_payload_and_call_creds': TestOptions(flaky=False, secure=True),
     'request_with_large_metadata': default_test_options,
     'request_with_payload': default_test_options,
+    'request_with_compressed_payload': default_test_options,
     'request_with_flags': default_test_options,
     'server_finishes_request': default_test_options,
     'simple_delayed_request': default_test_options,
@@ -93,6 +95,19 @@
 
 
 def main():
+  sec_deps = [
+    'end2end_certs',
+    'grpc_test_util',
+    'grpc',
+    'gpr_test_util',
+    'gpr'
+  ]
+  unsec_deps = [
+    'grpc_test_util_unsecure',
+    'grpc_unsecure',
+    'gpr_test_util',
+    'gpr'
+  ]
   json = {
       '#': 'generated with test/end2end/gen_build_json.py',
       'libs': [
@@ -103,6 +118,8 @@
               'secure': 'check' if END2END_FIXTURES[f].secure else 'no',
               'src': ['test/core/end2end/fixtures/%s.c' % f],
               'platforms': [ 'posix' ] if f.endswith('_posix') else END2END_FIXTURES[f].platforms,
+              'deps': sec_deps if END2END_FIXTURES[f].secure else unsec_deps,
+              'headers': ['test/core/end2end/end2end_tests.h'],
           }
           for f in sorted(END2END_FIXTURES.keys())] + [
           {
@@ -111,7 +128,9 @@
               'language': 'c',
               'secure': 'check' if END2END_TESTS[t].secure else 'no',
               'src': ['test/core/end2end/tests/%s.c' % t],
-              'headers': ['test/core/end2end/tests/cancel_test_helpers.h']
+              'headers': ['test/core/end2end/tests/cancel_test_helpers.h',
+                          'test/core/end2end/end2end_tests.h'],
+              'deps': sec_deps if END2END_TESTS[t].secure else unsec_deps
           }
           for t in sorted(END2END_TESTS.keys())] + [
           {
@@ -135,13 +154,7 @@
               'platforms': END2END_FIXTURES[f].platforms,
               'deps': [
                   'end2end_fixture_%s' % f,
-                  'end2end_test_%s' % t,
-                  'end2end_certs',
-                  'grpc_test_util',
-                  'grpc',
-                  'gpr_test_util',
-                  'gpr'
-              ]
+                  'end2end_test_%s' % t] + sec_deps
           }
       for f in sorted(END2END_FIXTURES.keys())
       for t in sorted(END2END_TESTS.keys())] + [
@@ -155,12 +168,7 @@
               'platforms': END2END_FIXTURES[f].platforms,
               'deps': [
                   'end2end_fixture_%s' % f,
-                  'end2end_test_%s' % t,
-                  'grpc_test_util_unsecure',
-                  'grpc_unsecure',
-                  'gpr_test_util',
-                  'gpr'
-              ]
+                  'end2end_test_%s' % t] + unsec_deps
           }
       for f in sorted(END2END_FIXTURES.keys()) if not END2END_FIXTURES[f].secure
       for t in sorted(END2END_TESTS.keys()) if not END2END_TESTS[t].secure]}
diff --git a/test/core/end2end/multiple_server_queues_test.c b/test/core/end2end/multiple_server_queues_test.c
new file mode 100644
index 0000000..208d42e
--- /dev/null
+++ b/test/core/end2end/multiple_server_queues_test.c
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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 <grpc/grpc.h>
+#include "test/core/util/test_config.h"
+
+int main(int argc, char **argv) {
+  grpc_completion_queue *cq1;
+  grpc_completion_queue *cq2;
+  grpc_server *server;
+
+  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);
+  grpc_server_add_http2_port(server, "[::]:0");
+  grpc_server_register_completion_queue(server, cq2);
+  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 */
+  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_server_destroy(server);
+  grpc_completion_queue_destroy(cq1);
+  grpc_completion_queue_destroy(cq2);
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 35b837b..79797f9 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -85,8 +85,8 @@
   GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
 
   grpc_completion_queue_shutdown(cq);
-  while (grpc_completion_queue_next(cq, gpr_inf_future).type !=
-         GRPC_QUEUE_SHUTDOWN)
+  while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME))
+             .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 809c5bb..2509ea0 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,18 +94,15 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -114,8 +113,8 @@
   char *details = NULL;
   size_t details_capacity = 0;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "slartibartfast.local", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "slartibartfast.local",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -144,8 +143,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNAUTHENTICATED);
 
@@ -157,7 +156,7 @@
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_invoke_simple_request(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index cc5586b..1cc6b2d 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -75,8 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -91,12 +93,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Cancel after accept, no payload */
@@ -106,10 +105,10 @@
   grpc_op *op;
   grpc_call *c;
   grpc_call *s;
-  grpc_end2end_test_fixture f = begin_test(config, "cancel_after_accept", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "cancel_after_accept", NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
   grpc_metadata_array request_metadata_recv;
@@ -127,8 +126,8 @@
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -162,12 +161,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(2)));
-  cq_expect_completion(v_server, tag(2), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(2)));
+  cq_expect_completion(cqv, tag(2), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_MESSAGE;
@@ -190,11 +188,9 @@
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
 
-  cq_expect_completion(v_server, tag(3), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(3), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == mode.expect_status);
   GPR_ASSERT(0 == strcmp(details, mode.expect_details));
@@ -214,8 +210,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
   end_test(&f);
   config.tear_down_data(&f);
 }
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 9a2fcf6..015d437 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
@@ -75,8 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -91,12 +93,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Cancel after accept with a writes closed, no payload */
@@ -106,10 +105,10 @@
   grpc_op *op;
   grpc_call *c;
   grpc_call *s;
-  grpc_end2end_test_fixture f = begin_test(config, "test_cancel_after_accept_and_writes_closed", NULL, NULL);
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_cancel_after_accept_and_writes_closed", NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
   grpc_metadata_array request_metadata_recv;
@@ -127,8 +126,8 @@
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -165,12 +164,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(2)));
-  cq_expect_completion(v_server, tag(2), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(2)));
+  cq_expect_completion(cqv, tag(2), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_MESSAGE;
@@ -193,11 +191,9 @@
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
 
-  cq_expect_completion(v_server, tag(3), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(3), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == mode.expect_status);
   GPR_ASSERT(0 == strcmp(details, mode.expect_details));
@@ -217,8 +213,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index 9b3ad28..414ec70 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,12 +94,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Cancel after invoke, no payload */
@@ -109,7 +108,7 @@
   grpc_end2end_test_fixture f =
       begin_test(config, "test_cancel_after_invoke", mode, NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
   grpc_metadata_array request_metadata_recv;
@@ -122,8 +121,8 @@
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -162,8 +161,8 @@
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
 
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == mode.expect_status);
   GPR_ASSERT(0 == strcmp(details, mode.expect_details));
@@ -179,7 +178,7 @@
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(cqv);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index ca19c46..3cfe56e 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Cancel before invoke */
@@ -104,9 +103,10 @@
   grpc_op ops[6];
   grpc_op *op;
   grpc_call *c;
-  grpc_end2end_test_fixture f = begin_test(config, "cancel_before_invoke", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "cancel_before_invoke", NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
   grpc_metadata_array request_metadata_recv;
@@ -119,8 +119,8 @@
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c));
@@ -159,8 +159,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, test_ops, tag(1)));
 
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_CANCELLED);
 
@@ -175,7 +175,7 @@
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(cqv);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index 5d7d762..8bffc3f 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -75,8 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -91,24 +93,22 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Cancel and do nothing */
 static void test_cancel_in_a_vacuum(grpc_end2end_test_config config,
                                     cancellation_mode mode) {
   grpc_call *c;
-  grpc_end2end_test_fixture f = begin_test(config, "test_cancel_in_a_vacuum", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_cancel_in_a_vacuum", NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *v_client = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));
diff --git a/test/core/end2end/tests/census_simple_request.c b/test/core/end2end/tests/census_simple_request.c
index ac2574c..b414755 100644
--- a/test/core/end2end/tests/census_simple_request.c
+++ b/test/core/end2end/tests/census_simple_request.c
@@ -65,8 +65,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -88,20 +90,16 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = n_seconds_time(5);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -113,7 +111,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -143,12 +141,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -167,17 +164,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -188,8 +183,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_invoke_request_with_census(
diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c
index cf9b79f..9acd189 100644
--- a/test/core/end2end/tests/disappearing_server.c
+++ b/test/core/end2end/tests/disappearing_server.c
@@ -76,17 +76,13 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void do_request_and_shutdown_server(grpc_end2end_test_fixture *f,
-                                           cq_verifier *v_client,
-                                           cq_verifier *v_server) {
+                                           cq_verifier *cqv) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -101,7 +97,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f->client, f->client_cq, "/foo",
+  c = grpc_channel_create_call(f->client, f->cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -131,16 +127,16 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f->server, &s, &call_details,
-                                      &request_metadata_recv, f->server_cq,
-                                      f->server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, &s,
+                                                      &call_details,
+                                                      &request_metadata_recv,
+                                                      f->cq, f->cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   /* should be able to shut down the server early
      - and still complete the request */
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
+  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -159,18 +155,16 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_expect_completion(v_server, tag(1000), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_expect_completion(cqv, tag(1000), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -184,23 +178,21 @@
 
 static void disappearing_server_test(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
 
   gpr_log(GPR_INFO, "%s/%s", "disappearing_server_test", config.name);
 
   config.init_client(&f, NULL);
   config.init_server(&f, NULL);
 
-  do_request_and_shutdown_server(&f, v_client, v_server);
+  do_request_and_shutdown_server(&f, cqv);
 
   /* now destroy and recreate the server */
   config.init_server(&f, NULL);
 
-  do_request_and_shutdown_server(&f, v_client, v_server);
+  do_request_and_shutdown_server(&f, cqv);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   end_test(&f);
   config.tear_down_data(&f);
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 5826aba..adc59b4 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
@@ -81,12 +81,9 @@
 static void end_test(grpc_end2end_test_fixture *f) {
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_early_server_shutdown_finishes_inflight_calls(
@@ -94,9 +91,9 @@
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  grpc_end2end_test_fixture f = begin_test(config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -108,8 +105,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -139,12 +136,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -154,18 +150,16 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
   /* shutdown and destroy the server */
-  grpc_server_shutdown_and_notify(f.server, f.server_cq, tag(1000));
+  grpc_server_shutdown_and_notify(f.server, f.cq, tag(1000));
   grpc_server_cancel_all_calls(f.server);
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_expect_completion(v_server, tag(1000), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(1000), 1);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   grpc_server_destroy(f.server);
 
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
-
   GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
@@ -180,8 +174,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   end_test(&f);
   config.tear_down_data(&f);
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 0c2cdb7..fc03cb0 100644
--- a/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
+++ b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
@@ -81,18 +81,16 @@
 static void end_test(grpc_end2end_test_fixture *f) {
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_early_server_shutdown_finishes_tags(
     grpc_end2end_test_config config) {
-  grpc_end2end_test_fixture f = begin_test(config, "test_early_server_shutdown_finishes_tags", NULL, NULL);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_early_server_shutdown_finishes_tags", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_call *s = (void *)1;
   grpc_call_details call_details;
   grpc_metadata_array request_metadata_recv;
@@ -102,21 +100,20 @@
 
   /* upon shutdown, the server should finish all requested calls indicating
      no new call */
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  grpc_server_shutdown_and_notify(f.server, f.server_cq, tag(1000));
-  cq_expect_completion(v_server, tag(101), 0);
-  cq_expect_completion(v_server, tag(1000), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  grpc_server_shutdown_and_notify(f.server, f.cq, tag(1000));
+  cq_expect_completion(cqv, tag(101), 0);
+  cq_expect_completion(cqv, tag(1000), 1);
+  cq_verify(cqv);
   GPR_ASSERT(s == NULL);
 
   grpc_server_destroy(f.server);
 
   end_test(&f);
   config.tear_down_data(&f);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 void grpc_end2end_tests(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index 79d1965..db8458d 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,31 +94,28 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void empty_batch_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op *op = NULL;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, op, 0, tag(1)));
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_invoke_empty_body(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c
index 6a5b4b1..8c1889a 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.c
+++ b/test/core/end2end/tests/graceful_server_shutdown.c
@@ -88,12 +88,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_early_server_shutdown_finishes_inflight_calls(
@@ -101,9 +98,9 @@
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  grpc_end2end_test_fixture f = begin_test(config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -115,8 +112,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -146,16 +143,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   /* shutdown and destroy the server */
-  grpc_server_shutdown_and_notify(f.server, f.server_cq, tag(0xdead));
-  cq_verify_empty(v_server);
+  grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
+  cq_verify_empty(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -174,19 +170,17 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_expect_completion(v_server, tag(0xdead), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(0xdead), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   grpc_call_destroy(s);
 
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
-
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -196,8 +190,7 @@
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   end_test(&f);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index 812bdfa..744a9ad 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -72,8 +72,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -88,22 +90,20 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static gpr_slice large_slice(void) {
   gpr_slice slice = gpr_slice_malloc(1000000);
-  memset(GPR_SLICE_START_PTR(slice), 0xab, GPR_SLICE_LENGTH(slice));
+  memset(GPR_SLICE_START_PTR(slice), 'x', GPR_SLICE_LENGTH(slice));
   return slice;
 }
 
 static void test_invoke_large_request(grpc_end2end_test_config config) {
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_large_request", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_invoke_large_request", NULL, NULL);
 
   gpr_slice request_payload_slice = large_slice();
   gpr_slice response_payload_slice = large_slice();
@@ -114,8 +114,7 @@
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   gpr_timespec deadline = n_seconds_time(30);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -129,8 +128,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -141,71 +140,78 @@
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
   op->data.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &response_payload_recv;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
   op->data.recv_status_on_client.status = &status;
   op->data.recv_status_on_client.status_details = &details;
   op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+  op->flags = 0;
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &request_payload_recv;
+  op->flags = 0;
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = response_payload;
+  op->flags = 0;
   op++;
-  op = ops;
   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -216,8 +222,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(response_payload);
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index f8660bb..1204c07 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,20 +92,16 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -115,7 +113,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -145,12 +143,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -169,17 +166,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -190,8 +185,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_max_concurrent_streams(grpc_end2end_test_config config) {
@@ -204,8 +198,7 @@
   grpc_call *s2;
   int live_call;
   gpr_timespec deadline;
-  cq_verifier *v_client;
-  cq_verifier *v_server;
+  cq_verifier *cqv;
   grpc_event ev;
   grpc_call_details call_details;
   grpc_metadata_array request_metadata_recv;
@@ -222,6 +215,8 @@
   grpc_op ops[6];
   grpc_op *op;
   int was_cancelled;
+  int got_client_start;
+  int got_server_start;
 
   server_arg.key = GRPC_ARG_MAX_CONCURRENT_STREAMS;
   server_arg.type = GRPC_ARG_INTEGER;
@@ -231,8 +226,7 @@
   server_args.args = &server_arg;
 
   f = begin_test(config, "test_max_concurrent_streams", NULL, &server_args);
-  v_client = cq_verifier_create(f.client_cq);
-  v_server = cq_verifier_create(f.server_cq);
+  cqv = cq_verifier_create(f.cq);
 
   grpc_metadata_array_init(&request_metadata_recv);
   grpc_metadata_array_init(&initial_metadata_recv1);
@@ -249,18 +243,17 @@
 
   /* start two requests - ensuring that the second is not accepted until
      the first completes */
-  deadline = n_seconds_time(10);
-  c1 = grpc_channel_create_call(f.client, f.client_cq, "/alpha",
+  deadline = n_seconds_time(1000);
+  c1 = grpc_channel_create_call(f.client, f.cq, "/alpha",
                                 "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c1);
-  c2 = grpc_channel_create_call(f.client, f.client_cq, "/beta",
+  c2 = grpc_channel_create_call(f.client, f.cq, "/beta",
                                 "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c2);
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s1, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s1, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -314,18 +307,28 @@
   GPR_ASSERT(GRPC_CALL_OK ==
              grpc_call_start_batch(c2, ops, op - ops, tag(402)));
 
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
-
-  ev = grpc_completion_queue_next(f.client_cq,
-                                  GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3));
-  GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
-  GPR_ASSERT(ev.success);
-  GPR_ASSERT(ev.tag == tag(301) || ev.tag == tag(401));
-  /* The /alpha or /beta calls started above could be invoked (but NOT both);
-   * check this here */
-  /* We'll get tag 303 or 403, we want 300, 400 */
-  live_call = ((int)(gpr_intptr)ev.tag) - 1;
+  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));
+    GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+    GPR_ASSERT(ev.success);
+    if (ev.tag == tag(101)) {
+      GPR_ASSERT(!got_server_start);
+      got_server_start = 1;
+    } else {
+      GPR_ASSERT(!got_client_start);
+      GPR_ASSERT(ev.tag == tag(301) || ev.tag == tag(401));
+      /* The /alpha or /beta calls started above could be invoked (but NOT
+       * both);
+       * check this here */
+      /* We'll get tag 303 or 403, we want 300, 400 */
+      live_call = ((int)(gpr_intptr)ev.tag) - 1;
+      got_client_start = 1;
+    }
+  }
+  GPR_ASSERT(live_call == 300 || live_call == 400);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -345,21 +348,18 @@
   GPR_ASSERT(GRPC_CALL_OK ==
              grpc_call_start_batch(s1, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(live_call + 2), 1);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(live_call + 2), 1);
   /* first request is finished, we should be able to start the second */
   live_call = (live_call == 300) ? 400 : 300;
-  cq_expect_completion(v_client, tag(live_call + 1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(live_call + 1), 1);
+  cq_verify(cqv);
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s2, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(201)));
-  cq_expect_completion(v_server, tag(201), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s2, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(201)));
+  cq_expect_completion(cqv, tag(201), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -379,14 +379,11 @@
   GPR_ASSERT(GRPC_CALL_OK ==
              grpc_call_start_batch(s2, ops, op - ops, tag(202)));
 
-  cq_expect_completion(v_client, tag(live_call + 2), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(live_call + 2), 1);
+  cq_expect_completion(cqv, tag(202), 1);
+  cq_verify(cqv);
 
-  cq_expect_completion(v_server, tag(202), 1);
-  cq_verify(v_server);
-
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_call_destroy(c1);
   grpc_call_destroy(s1);
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index 8d3d2f1..ea59a93 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_max_message_length(grpc_end2end_test_config config) {
@@ -104,8 +103,7 @@
   grpc_channel_args server_args;
   grpc_call *c;
   grpc_call *s;
-  cq_verifier *v_client;
-  cq_verifier *v_server;
+  cq_verifier *cqv;
   grpc_op ops[6];
   grpc_op *op;
   gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
@@ -128,11 +126,11 @@
   server_args.args = &server_arg;
 
   f = begin_test(config, "test_max_message_length", NULL, &server_args);
-  v_client = cq_verifier_create(f.client_cq);
-  v_server = cq_verifier_create(f.server_cq);
+  cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr:1234", gpr_inf_future);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
+                               "foo.test.google.fr:1234",
+                               gpr_inf_future(GPR_CLOCK_REALTIME));
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -165,12 +163,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -179,11 +176,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status != GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
@@ -200,8 +195,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   end_test(&f);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
index 1f32691..8ead664 100644
--- a/test/core/end2end/tests/no_op.c
+++ b/test/core/end2end/tests/no_op.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_no_op(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index 2b617ce..8a3ec96 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,23 +92,20 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Client pings and server pongs. Repeat messages rounds before finishing. */
 static void test_pingpong_streaming(grpc_end2end_test_config config,
                                     int messages) {
-  grpc_end2end_test_fixture f = begin_test(config, "test_pingpong_streaming", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_pingpong_streaming", NULL, NULL);
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -125,7 +124,7 @@
   gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
   gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -152,12 +151,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(100)));
-  cq_expect_completion(v_server, tag(100), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(100)));
+  cq_expect_completion(cqv, tag(100), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -192,8 +190,8 @@
     op++;
     GPR_ASSERT(GRPC_CALL_OK ==
                grpc_call_start_batch(s, ops, op - ops, tag(102)));
-    cq_expect_completion(v_server, tag(102), 1);
-    cq_verify(v_server);
+    cq_expect_completion(cqv, tag(102), 1);
+    cq_verify(cqv);
 
     op = ops;
     op->op = GRPC_OP_SEND_MESSAGE;
@@ -202,11 +200,9 @@
     op++;
     GPR_ASSERT(GRPC_CALL_OK ==
                grpc_call_start_batch(s, ops, op - ops, tag(103)));
-    cq_expect_completion(v_server, tag(103), 1);
-    cq_verify(v_server);
-
-    cq_expect_completion(v_client, tag(2), 1);
-    cq_verify(v_client);
+    cq_expect_completion(cqv, tag(103), 1);
+    cq_expect_completion(cqv, tag(2), 1);
+    cq_verify(cqv);
 
     grpc_byte_buffer_destroy(request_payload);
     grpc_byte_buffer_destroy(response_payload);
@@ -232,19 +228,16 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(104)));
 
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_expect_completion(v_client, tag(3), 1);
-  cq_verify(v_client);
-
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_expect_completion(v_server, tag(104), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_expect_completion(cqv, tag(3), 1);
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_expect_completion(cqv, tag(104), 1);
+  cq_verify(cqv);
 
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_metadata_array_destroy(&initial_metadata_recv);
   grpc_metadata_array_destroy(&trailing_metadata_recv);
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index 43e34ff..f44fd3a 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,20 +94,16 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f, void *rc) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -117,7 +115,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_registered_call(f.client, f.client_cq, rc, deadline);
+  c = grpc_channel_create_registered_call(f.client, f.cq, rc, deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -146,12 +144,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -170,17 +167,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -191,12 +186,12 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_invoke_simple_request(grpc_end2end_test_config config) {
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
+  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");
 
@@ -207,7 +202,8 @@
 
 static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
   int i;
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
+  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");
 
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 b1c6c98..8b8a11b 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
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Request/response with metadata and payload.*/
@@ -128,9 +127,9 @@
        "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
        16,
        {{NULL, NULL, NULL}}}};
-  grpc_end2end_test_fixture f = begin_test(config, "test_request_response_with_metadata_and_payload", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  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);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -144,8 +143,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -183,12 +182,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -202,8 +200,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -222,11 +220,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -257,8 +253,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(response_payload);
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 d0a7b9a..ef6dfe9 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
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Request/response with metadata and payload.*/
@@ -114,9 +113,9 @@
                              {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
   grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}},
                              {"key4", "val4", 4, {{NULL, NULL, NULL}}}};
-  grpc_end2end_test_fixture f = begin_test(config, "test_request_response_with_metadata_and_payload", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  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);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -130,8 +129,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -169,12 +168,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -188,8 +186,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -208,11 +206,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -235,8 +231,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(response_payload);
diff --git a/test/core/end2end/tests/request_response_with_payload.c b/test/core/end2end/tests/request_response_with_payload.c
index 9bf4816..38d3432 100644
--- a/test/core/end2end/tests/request_response_with_payload.c
+++ b/test/core/end2end/tests/request_response_with_payload.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void request_response_with_payload(grpc_end2end_test_fixture f) {
@@ -108,8 +107,7 @@
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -123,8 +121,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -161,12 +159,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -179,8 +176,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -199,11 +196,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -222,8 +217,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(response_payload);
@@ -235,7 +229,8 @@
    payload and status. */
 static void test_invoke_request_response_with_payload(
     grpc_end2end_test_config config) {
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_request_response_with_payload", NULL, NULL);
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_invoke_request_response_with_payload", NULL, NULL);
   request_response_with_payload(f);
   end_test(&f);
   config.tear_down_data(&f);
@@ -244,7 +239,8 @@
 static void test_invoke_10_request_response_with_payload(
     grpc_end2end_test_config config) {
   int i;
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_10_request_response_with_payload", NULL, NULL);
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_invoke_10_request_response_with_payload", NULL, NULL);
   for (i = 0; i < 10; i++) {
     request_response_with_payload(f);
   }
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 3de1d86..b5c743b 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
@@ -51,11 +51,7 @@
 static const char overridden_iam_token[] = "overridden_token";
 static const char overridden_iam_selector[] = "overridden_selector";
 
-typedef enum {
-  NONE,
-  OVERRIDE,
-  DESTROY
-} override_mode;
+typedef enum { NONE, OVERRIDE, DESTROY } override_mode;
 
 enum { TIMEOUT = 200000 };
 
@@ -88,8 +84,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -104,12 +102,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void print_auth_context(int is_client, const grpc_auth_context *ctx) {
@@ -132,10 +127,11 @@
 static void test_call_creds_failure(grpc_end2end_test_config config) {
   grpc_call *c;
   grpc_credentials *creds = NULL;
-  grpc_end2end_test_fixture f = begin_test(config, "test_call_creds_failure", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_call_creds_failure", NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   /* Try with credentials unfit to be set on a call (channel creds). */
@@ -163,8 +159,7 @@
   gpr_timespec deadline = five_seconds_time();
 
   grpc_end2end_test_fixture f = begin_test(config, test_name, NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -178,10 +173,10 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
   grpc_credentials *creds = NULL;
-  const grpc_auth_context *s_auth_context = NULL;
+  grpc_auth_context *s_auth_context = NULL;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
   creds = grpc_iam_credentials_create(iam_token, iam_selector);
   GPR_ASSERT(creds != NULL);
@@ -236,16 +231,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
-                                                      &call_details,
-                                                      &request_metadata_recv,
-                                                      f.server_cq, f.server_cq,
-                                                      tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
   s_auth_context = grpc_call_auth_context(s);
   GPR_ASSERT(s_auth_context != NULL);
   print_auth_context(0, s_auth_context);
+  grpc_auth_context_release(s_auth_context);
 
   /* Cannot set creds on the server call object. */
   GPR_ASSERT(grpc_call_set_credentials(s, NULL) != GRPC_CALL_OK);
@@ -261,8 +255,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -281,11 +275,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -337,8 +329,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(response_payload);
@@ -351,17 +342,22 @@
 
 void test_request_response_with_payload_and_call_creds(
     grpc_end2end_test_config config) {
-  request_response_with_payload_and_call_creds("test_request_response_with_payload_and_call_creds", config, NONE);
+  request_response_with_payload_and_call_creds(
+      "test_request_response_with_payload_and_call_creds", config, NONE);
 }
 
 void test_request_response_with_payload_and_overridden_call_creds(
     grpc_end2end_test_config config) {
-  request_response_with_payload_and_call_creds("test_request_response_with_payload_and_overridden_call_creds", config, OVERRIDE);
+  request_response_with_payload_and_call_creds(
+      "test_request_response_with_payload_and_overridden_call_creds", config,
+      OVERRIDE);
 }
 
 void test_request_response_with_payload_and_deleted_call_creds(
     grpc_end2end_test_config config) {
-  request_response_with_payload_and_call_creds("test_request_response_with_payload_and_deleted_call_creds", config, DESTROY);
+  request_response_with_payload_and_call_creds(
+      "test_request_response_with_payload_and_deleted_call_creds", config,
+      DESTROY);
 }
 
 void grpc_end2end_tests(grpc_end2end_test_config config) {
@@ -372,4 +368,3 @@
     test_request_response_with_payload_and_deleted_call_creds(config);
   }
 }
-
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 e91ebf4..a5c0851 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
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Request/response with metadata and payload.*/
@@ -110,12 +109,15 @@
   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_end2end_test_fixture f = begin_test(config, "test_request_response_with_metadata_and_payload", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  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_end2end_test_fixture f = begin_test(
+      config, "test_request_response_with_metadata_and_payload", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -129,8 +131,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -168,13 +170,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
-                                                      &call_details,
-                                                      &request_metadata_recv,
-                                                      f.server_cq, f.server_cq,
-                                                      tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -188,8 +188,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -209,11 +209,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -237,8 +235,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(response_payload);
diff --git a/test/core/end2end/tests/request_with_compressed_payload.c b/test/core/end2end/tests/request_with_compressed_payload.c
new file mode 100644
index 0000000..2599f79
--- /dev/null
+++ b/test/core/end2end/tests/request_with_compressed_payload.c
@@ -0,0 +1,315 @@
+/*
+ *
+ * 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/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+
+#include "test/core/end2end/cq_verifier.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/compress_filter.h"
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(gpr_intptr t) { return (void *)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char *test_name,
+                                            grpc_channel_args *client_args,
+                                            grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_client(&f, client_args);
+  config.init_server(&f, server_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time());
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  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))
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+}
+
+static void request_with_payload_template(
+    grpc_end2end_test_config config, const char *test_name,
+    gpr_uint32 send_flags_bitmask,
+    grpc_compression_algorithm requested_compression_algorithm,
+    grpc_compression_algorithm expected_compression_algorithm,
+    grpc_metadata *client_metadata) {
+  grpc_call *c;
+  grpc_call *s;
+  gpr_slice request_payload_slice;
+  grpc_byte_buffer *request_payload;
+  gpr_timespec deadline = five_seconds_time();
+  grpc_channel_args *client_args;
+  grpc_channel_args *server_args;
+  grpc_end2end_test_fixture f;
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  char *details = NULL;
+  size_t details_capacity = 0;
+  int was_cancelled = 2;
+  cq_verifier *cqv;
+  char str[1024];
+
+  memset(str, 'x', 1023); str[1023] = '\0';
+  request_payload_slice = gpr_slice_from_copied_string(str);
+  request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+
+  client_args = grpc_channel_args_set_compression_algorithm(
+      NULL, requested_compression_algorithm);
+  server_args = grpc_channel_args_set_compression_algorithm(
+      NULL, requested_compression_algorithm);
+
+  f = begin_test(config, test_name, client_args, server_args);
+  cqv = cq_verifier_create(f.cq);
+
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
+                               "foo.test.google.fr", deadline);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  if (client_metadata != NULL) {
+    op->data.send_initial_metadata.count = 1;
+    op->data.send_initial_metadata.metadata = client_metadata;
+  } else {
+    op->data.send_initial_metadata.count = 0;
+  }
+  op->flags = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = request_payload;
+  op->flags = send_flags_bitmask;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+  op->flags = 0;
+  op++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_server_request_call(f.server, &s, &call_details,
+                                      &request_metadata_recv, f.cq,
+                                      f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &request_payload_recv;
+  op->flags = 0;
+  op++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
+
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
+
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  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++;
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
+
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(0 == strcmp(details, "xyz"));
+  GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
+  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  GPR_ASSERT(was_cancelled == 0);
+
+  GPR_ASSERT(request_payload_recv->type == GRPC_BB_RAW);
+  GPR_ASSERT(request_payload_recv->data.raw.compression ==
+             expected_compression_algorithm);
+
+  GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, str));
+
+  gpr_free(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(cqv);
+
+  gpr_slice_unref(request_payload_slice);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+
+  grpc_channel_args_destroy(client_args);
+  grpc_channel_args_destroy(server_args);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_invoke_request_with_exceptionally_uncompressed_payload(
+    grpc_end2end_test_config config) {
+  request_with_payload_template(
+      config, "test_invoke_request_with_exceptionally_uncompressed_payload",
+      GRPC_WRITE_NO_COMPRESS, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_NONE,
+      NULL);
+}
+
+static void test_invoke_request_with_uncompressed_payload(
+    grpc_end2end_test_config config) {
+  request_with_payload_template(
+      config, "test_invoke_request_with_uncompressed_payload", 0,
+      GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE, NULL);
+}
+
+static void test_invoke_request_with_compressed_payload(
+    grpc_end2end_test_config config) {
+  request_with_payload_template(
+      config, "test_invoke_request_with_compressed_payload", 0,
+      GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP, NULL);
+}
+
+static void test_invoke_request_with_compressed_payload_md_override(
+    grpc_end2end_test_config config) {
+  grpc_metadata gzip_compression_override;
+  grpc_metadata none_compression_override;
+
+  gzip_compression_override.key = GRPC_COMPRESS_REQUEST_ALGORITHM_KEY;
+  gzip_compression_override.value = "gzip";
+  gzip_compression_override.value_length = 4;
+  memset(&gzip_compression_override.internal_data, 0,
+         sizeof(gzip_compression_override.internal_data));
+
+  none_compression_override.key = GRPC_COMPRESS_REQUEST_ALGORITHM_KEY;
+  none_compression_override.value = "none";
+  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 */
+  request_with_payload_template(
+      config, "test_invoke_request_with_compressed_payload_md_override_1", 0,
+      GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP, &gzip_compression_override);
+
+  /* Channel default DEFLATE, call override to GZIP */
+  request_with_payload_template(
+      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 */
+  request_with_payload_template(
+      config, "test_invoke_request_with_compressed_payload_md_override_3", 0,
+      GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_NONE, &none_compression_override);
+}
+
+void grpc_end2end_tests(grpc_end2end_test_config config) {
+  test_invoke_request_with_exceptionally_uncompressed_payload(config);
+  test_invoke_request_with_uncompressed_payload(config);
+  test_invoke_request_with_compressed_payload(config);
+  test_invoke_request_with_compressed_payload_md_override(config);
+}
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index 5ad4755..0bfedca 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -75,8 +75,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -91,12 +93,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void test_invoke_request_with_flags(
@@ -106,11 +105,10 @@
   gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
+  gpr_timespec deadline = GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10);
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_request_with_flags", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -123,8 +121,8 @@
   size_t details_capacity = 0;
   grpc_call_error expectation;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -158,6 +156,11 @@
   expectation = call_start_batch_expected_result;
   GPR_ASSERT(expectation == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
+  if (expectation == GRPC_CALL_OK) {
+    cq_expect_completion(cqv, tag(1), 1);
+    cq_verify(cqv);
+  }
+
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
   grpc_metadata_array_destroy(&trailing_metadata_recv);
@@ -166,8 +169,7 @@
 
   grpc_call_destroy(c);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(request_payload_recv);
@@ -178,7 +180,7 @@
 
 void grpc_end2end_tests(grpc_end2end_test_config config) {
   size_t i;
-  gpr_uint32 flags_for_op[GRPC_OP_RECV_CLOSE_ON_SERVER+1];
+  gpr_uint32 flags_for_op[GRPC_OP_RECV_CLOSE_ON_SERVER + 1];
 
   {
     /* check that all grpc_op_types fail when their flag value is set to an
diff --git a/test/core/end2end/tests/request_with_large_metadata.c b/test/core/end2end/tests/request_with_large_metadata.c
index cf6f4b2..ad34c69 100644
--- a/test/core/end2end/tests/request_with_large_metadata.c
+++ b/test/core/end2end/tests/request_with_large_metadata.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Request with a large amount of metadata.*/
@@ -107,9 +106,9 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta;
-  grpc_end2end_test_fixture f = begin_test(config, "test_request_with_large_metadata", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_request_with_large_metadata", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -123,8 +122,8 @@
   int was_cancelled = 2;
   const int large_size = 64 * 1024;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   meta.key = "key";
@@ -164,12 +163,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -182,8 +180,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -198,11 +196,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -221,8 +217,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(request_payload_recv);
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index 935aa58..8db6457 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -74,8 +74,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -90,12 +92,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 /* Client sends a request with payload, server reads then returns status. */
@@ -106,9 +105,9 @@
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   gpr_timespec deadline = five_seconds_time();
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_request_with_payload", NULL, NULL);
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_invoke_request_with_payload", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -121,8 +120,8 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -155,12 +154,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -173,8 +171,8 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -189,11 +187,9 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(103)));
 
-  cq_expect_completion(v_server, tag(103), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
@@ -211,8 +207,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(request_payload_recv);
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index 973f024..062a59a 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,20 +94,16 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -117,7 +115,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -144,12 +142,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -168,17 +165,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -189,8 +184,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_invoke_simple_request(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index 36558ec..a2665d7 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -62,8 +62,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -78,12 +80,9 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_delayed_request_body(grpc_end2end_test_config config,
@@ -94,8 +93,7 @@
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f->client_cq);
-  cq_verifier *v_server = cq_verifier_create(f->server_cq);
+  cq_verifier *cqv = cq_verifier_create(f->cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -109,8 +107,8 @@
 
   config.init_client(f, client_args);
 
-  c = grpc_channel_create_call(f->client, f->client_cq, "/foo",
-                               "foo.test.google.fr", deadline);
+  c = grpc_channel_create_call(f->client, f->cq, "/foo", "foo.test.google.fr",
+                               deadline);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -141,12 +139,12 @@
 
   config.init_server(f, server_args);
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f->server, &s, &call_details,
-                                      &request_metadata_recv, f->server_cq,
-                                      f->server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, &s,
+                                                      &call_details,
+                                                      &request_metadata_recv,
+                                                      f->cq, f->cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -165,17 +163,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -186,8 +182,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_simple_delayed_request_short(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index 06f9223..6194b84 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,20 +94,16 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -117,7 +115,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -147,12 +145,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -171,17 +168,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -192,8 +187,7 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
 static void test_invoke_simple_request(grpc_end2end_test_config config) {
@@ -207,7 +201,8 @@
 
 static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
   int i;
-  grpc_end2end_test_fixture f = begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
   for (i = 0; i < 10; i++) {
     simple_request_body(f);
     gpr_log(GPR_INFO, "Passed simple request %d", i);
@@ -217,6 +212,9 @@
 }
 
 void grpc_end2end_tests(grpc_end2end_test_config config) {
-  test_invoke_simple_request(config);
+  int i;
+  for (i = 0; i < 10; i++) {
+    test_invoke_simple_request(config);
+  }
   test_invoke_10_simple_requests(config);
 }
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 1d7a150..2cd638c 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
@@ -76,8 +76,10 @@
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
-  grpc_server_shutdown_and_notify(f->server, f->server_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->server_cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)).type == GRPC_OP_COMPLETE);
+  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))
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -92,20 +94,16 @@
   shutdown_server(f);
   shutdown_client(f);
 
-  grpc_completion_queue_shutdown(f->server_cq);
-  drain_cq(f->server_cq);
-  grpc_completion_queue_destroy(f->server_cq);
-  grpc_completion_queue_shutdown(f->client_cq);
-  drain_cq(f->client_cq);
-  grpc_completion_queue_destroy(f->client_cq);
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
-  cq_verifier *v_client = cq_verifier_create(f.client_cq);
-  cq_verifier *v_server = cq_verifier_create(f.server_cq);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -117,7 +115,7 @@
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
+  c = grpc_channel_create_call(f.client, f.cq, "/foo",
                                "foo.test.google.fr:1234", deadline);
   GPR_ASSERT(c);
 
@@ -147,12 +145,11 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, ops, op - ops, tag(1)));
 
-  GPR_ASSERT(GRPC_CALL_OK ==
-             grpc_server_request_call(f.server, &s, &call_details,
-                                      &request_metadata_recv, f.server_cq,
-                                      f.server_cq, tag(101)));
-  cq_expect_completion(v_server, tag(101), 1);
-  cq_verify(v_server);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
 
   op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -171,17 +168,15 @@
   op++;
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(s, ops, op - ops, tag(102)));
 
-  cq_expect_completion(v_server, tag(102), 1);
-  cq_verify(v_server);
-
-  cq_expect_completion(v_client, tag(1), 1);
-  cq_verify(v_client);
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
   GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
-  GPR_ASSERT(was_cancelled == 0);
+  GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -192,11 +187,11 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  cq_verifier_destroy(v_client);
-  cq_verifier_destroy(v_server);
+  cq_verifier_destroy(cqv);
 }
 
-static void test_invoke_10_simple_requests(grpc_end2end_test_config config, int initial_sequence_number) {
+static void test_invoke_10_simple_requests(grpc_end2end_test_config config,
+                                           int initial_sequence_number) {
   int i;
   grpc_end2end_test_fixture f;
   grpc_arg client_arg;
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index ee5e390..2b19654 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -89,24 +89,26 @@
 }
 
 static void step_ping_pong_request(void) {
-  call = grpc_channel_create_call(channel, cq, "/Reflector/reflectUnary",
-                                  "localhost", gpr_inf_future);
+  call =
+      grpc_channel_create_call(channel, cq, "/Reflector/reflectUnary",
+                               "localhost", gpr_inf_future(GPR_CLOCK_REALTIME));
   GPR_ASSERT(GRPC_CALL_OK ==
              grpc_call_start_batch(call, ops, op - ops, (void *)1));
-  grpc_completion_queue_next(cq, gpr_inf_future);
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
   grpc_call_destroy(call);
   grpc_byte_buffer_destroy(response_payload_recv);
   call = NULL;
 }
 
 static void init_ping_pong_stream(void) {
-  call = grpc_channel_create_call(channel, cq, "/Reflector/reflectStream",
-                                  "localhost", gpr_inf_future);
+  call =
+      grpc_channel_create_call(channel, cq, "/Reflector/reflectStream",
+                               "localhost", gpr_inf_future(GPR_CLOCK_REALTIME));
   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);
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
 
   grpc_metadata_array_init(&initial_metadata_recv);
 
@@ -119,12 +121,12 @@
 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);
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME));
   grpc_byte_buffer_destroy(response_payload_recv);
 }
 
 static double now(void) {
-  gpr_timespec tv = gpr_now();
+  gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME);
   return 1e9 * tv.tv_sec + tv.tv_nsec;
 }
 
@@ -208,8 +210,8 @@
 
   grpc_channel_destroy(channel);
   grpc_completion_queue_shutdown(cq);
-  while (grpc_completion_queue_next(cq, gpr_inf_future).type !=
-         GRPC_QUEUE_SHUTDOWN)
+  while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME))
+             .type != GRPC_QUEUE_SHUTDOWN)
     ;
   grpc_completion_queue_destroy(cq);
   grpc_byte_buffer_destroy(the_buffer);
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index e58d721..082bbd3 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -234,12 +234,15 @@
     if (got_sigint && !shutdown_started) {
       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)).type == GRPC_OP_COMPLETE);
+      GPR_ASSERT(grpc_completion_queue_pluck(
+                     cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))
+                     .type == GRPC_OP_COMPLETE);
       grpc_completion_queue_shutdown(cq);
       shutdown_started = 1;
     }
     ev = grpc_completion_queue_next(
-        cq, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)));
+        cq, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                         gpr_time_from_micros(1000000, GPR_TIMESPAN)));
     s = ev.tag;
     switch (ev.type) {
       case GRPC_OP_COMPLETE:
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
index 7682091..4801eb3 100644
--- a/test/core/httpcli/httpcli_test.c
+++ b/test/core/httpcli/httpcli_test.c
@@ -35,6 +35,7 @@
 
 #include <string.h>
 
+#include <grpc/grpc.h>
 #include "src/core/iomgr/iomgr.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -44,14 +45,16 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
-static gpr_event g_done;
+static int g_done = 0;
+static grpc_httpcli_context g_context;
+static grpc_pollset g_pollset;
 
 static gpr_timespec n_seconds_time(int seconds) {
   return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
 }
 
 static void on_finish(void *arg, const grpc_httpcli_response *response) {
-  const char *expect = 
+  const char *expect =
       "<html><head><title>Hello world!</title></head>"
       "<body><p>This is a test</p></body></html>";
   GPR_ASSERT(arg == (void *)42);
@@ -59,54 +62,69 @@
   GPR_ASSERT(response->status == 200);
   GPR_ASSERT(response->body_length == strlen(expect));
   GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
-  gpr_event_set(&g_done, (void *)1);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  g_done = 1;
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 static void test_get(int use_ssl, int port) {
   grpc_httpcli_request req;
-  char* host;
+  char *host;
 
+  g_done = 0;
   gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_get", use_ssl);
 
   gpr_asprintf(&host, "localhost:%d", port);
   gpr_log(GPR_INFO, "requesting from %s", host);
 
-  gpr_event_init(&g_done);
   memset(&req, 0, sizeof(req));
   req.host = host;
   req.path = "/get";
   req.use_ssl = use_ssl;
 
-  grpc_httpcli_get(&req, n_seconds_time(15), on_finish, (void *)42);
+  grpc_httpcli_get(&g_context, &g_pollset, &req, n_seconds_time(15), on_finish,
+                   (void *)42);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (!g_done) {
+    grpc_pollset_work(&g_pollset, n_seconds_time(20));
+  }
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   gpr_free(host);
-  GPR_ASSERT(gpr_event_wait(&g_done, n_seconds_time(20)));
 }
 
 static void test_post(int use_ssl, int port) {
   grpc_httpcli_request req;
-  char* host;
+  char *host;
 
+  g_done = 0;
   gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_post", (int)use_ssl);
 
   gpr_asprintf(&host, "localhost:%d", port);
   gpr_log(GPR_INFO, "posting to %s", host);
 
-  gpr_event_init(&g_done);
   memset(&req, 0, sizeof(req));
   req.host = host;
   req.path = "/post";
   req.use_ssl = use_ssl;
 
-  grpc_httpcli_post(&req, "hello", 5, n_seconds_time(15), on_finish,
-                    (void *)42);
-  GPR_ASSERT(gpr_event_wait(&g_done, n_seconds_time(20)));
+  grpc_httpcli_post(&g_context, &g_pollset, &req, "hello", 5,
+                    n_seconds_time(15), on_finish, (void *)42);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (!g_done) {
+    grpc_pollset_work(&g_pollset, n_seconds_time(20));
+  }
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+  gpr_free(host);
 }
 
+static void destroy_pollset(void *ignored) { grpc_pollset_destroy(&g_pollset); }
+
 int main(int argc, char **argv) {
-  gpr_subprocess* server;
+  gpr_subprocess *server;
   char *me = argv[0];
   char *lslash = strrchr(me, '/');
-  char* args[4];
+  char *args[4];
   char root[1024];
   int port = grpc_pick_unused_port_or_die();
 
@@ -122,20 +140,25 @@
   gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
   args[1] = "--port";
   gpr_asprintf(&args[2], "%d", port);
-  server = gpr_subprocess_create(3, (const char**)args);
+  server = gpr_subprocess_create(3, (const char **)args);
   GPR_ASSERT(server);
   gpr_free(args[0]);
   gpr_free(args[2]);
 
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
 
   grpc_test_init(argc, argv);
-  grpc_iomgr_init();
+  grpc_init();
+  grpc_httpcli_context_init(&g_context);
+  grpc_pollset_init(&g_pollset);
 
   test_get(0, port);
   test_post(0, port);
 
-  grpc_iomgr_shutdown();
+  grpc_httpcli_context_destroy(&g_context);
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, NULL);
+  grpc_shutdown();
 
   gpr_subprocess_destroy(server);
 
diff --git a/test/core/iomgr/alarm_heap_test.c b/test/core/iomgr/alarm_heap_test.c
index b3e1e64..66b6e4c 100644
--- a/test/core/iomgr/alarm_heap_test.c
+++ b/test/core/iomgr/alarm_heap_test.c
@@ -44,6 +44,7 @@
   gpr_timespec ts;
   ts.tv_sec = rand();
   ts.tv_nsec = rand();
+  ts.clock_type = GPR_CLOCK_REALTIME;
   return ts;
 }
 
@@ -101,7 +102,7 @@
 
 static void check_pq_top(grpc_alarm *elements, grpc_alarm_heap *pq,
                          gpr_uint8 *inpq, int num_elements) {
-  gpr_timespec max_deadline = gpr_inf_past;
+  gpr_timespec max_deadline = gpr_inf_past(GPR_CLOCK_REALTIME);
   int *max_deadline_indices = gpr_malloc(num_elements * sizeof(int));
   int *top_elements;
   int num_max_deadline_indices = 0;
diff --git a/test/core/iomgr/alarm_list_test.c b/test/core/iomgr/alarm_list_test.c
index 684e3f5..56d662e 100644
--- a/test/core/iomgr/alarm_list_test.c
+++ b/test/core/iomgr/alarm_list_test.c
@@ -51,7 +51,7 @@
 }
 
 static void add_test(void) {
-  gpr_timespec start = gpr_now();
+  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   int i;
   grpc_alarm alarms[20];
 
@@ -60,45 +60,51 @@
 
   /* 10 ms alarms.  will expire in the current epoch */
   for (i = 0; i < 10; i++) {
-    grpc_alarm_init(&alarms[i], gpr_time_add(start, gpr_time_from_millis(10)),
-                    cb, (void *)(gpr_intptr) i, start);
+    grpc_alarm_init(&alarms[i],
+                    gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
+                    cb, (void *)(gpr_intptr)i, start);
   }
 
   /* 1010 ms alarms.  will expire in the next epoch */
   for (i = 10; i < 20; i++) {
-    grpc_alarm_init(&alarms[i], gpr_time_add(start, gpr_time_from_millis(1010)),
-                    cb, (void *)(gpr_intptr) i, start);
+    grpc_alarm_init(&alarms[i], gpr_time_add(start, gpr_time_from_millis(
+                                                        1010, GPR_TIMESPAN)),
+                    cb, (void *)(gpr_intptr)i, start);
   }
 
   /* collect alarms.  Only the first batch should be ready. */
-  GPR_ASSERT(10 ==
-             grpc_alarm_check(
-                 NULL, gpr_time_add(start, gpr_time_from_millis(500)), NULL));
+  GPR_ASSERT(10 == grpc_alarm_check(NULL,
+                                    gpr_time_add(start, gpr_time_from_millis(
+                                                            500, GPR_TIMESPAN)),
+                                    NULL));
   for (i = 0; i < 20; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  GPR_ASSERT(0 ==
-             grpc_alarm_check(
-                 NULL, gpr_time_add(start, gpr_time_from_millis(600)), NULL));
+  GPR_ASSERT(0 == grpc_alarm_check(
+                      NULL, gpr_time_add(
+                                start, gpr_time_from_millis(600, GPR_TIMESPAN)),
+                      NULL));
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
   /* collect the rest of the alarms */
-  GPR_ASSERT(10 ==
-             grpc_alarm_check(
-                 NULL, gpr_time_add(start, gpr_time_from_millis(1500)), NULL));
+  GPR_ASSERT(
+      10 == grpc_alarm_check(NULL, gpr_time_add(start, gpr_time_from_millis(
+                                                           1500, GPR_TIMESPAN)),
+                             NULL));
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 20));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  GPR_ASSERT(0 ==
-             grpc_alarm_check(
-                 NULL, gpr_time_add(start, gpr_time_from_millis(1600)), NULL));
+  GPR_ASSERT(0 == grpc_alarm_check(NULL,
+                                   gpr_time_add(start, gpr_time_from_millis(
+                                                           1600, GPR_TIMESPAN)),
+                                   NULL));
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 20));
     GPR_ASSERT(cb_called[i][0] == 0);
@@ -107,24 +113,30 @@
   grpc_alarm_list_shutdown();
 }
 
+static gpr_timespec tfm(int m) {
+  gpr_timespec t = gpr_time_from_millis(m, GPR_TIMESPAN);
+  t.clock_type = GPR_CLOCK_REALTIME;
+  return t;
+}
+
 /* Cleaning up a list with pending alarms. */
 void destruction_test(void) {
   grpc_alarm alarms[5];
 
-  grpc_alarm_list_init(gpr_time_0);
+  grpc_alarm_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
   memset(cb_called, 0, sizeof(cb_called));
 
-  grpc_alarm_init(&alarms[0], gpr_time_from_millis(100), cb,
-                  (void *)(gpr_intptr) 0, gpr_time_0);
-  grpc_alarm_init(&alarms[1], gpr_time_from_millis(3), cb,
-                  (void *)(gpr_intptr) 1, gpr_time_0);
-  grpc_alarm_init(&alarms[2], gpr_time_from_millis(100), cb,
-                  (void *)(gpr_intptr) 2, gpr_time_0);
-  grpc_alarm_init(&alarms[3], gpr_time_from_millis(3), cb,
-                  (void *)(gpr_intptr) 3, gpr_time_0);
-  grpc_alarm_init(&alarms[4], gpr_time_from_millis(1), cb,
-                  (void *)(gpr_intptr) 4, gpr_time_0);
-  GPR_ASSERT(1 == grpc_alarm_check(NULL, gpr_time_from_millis(2), NULL));
+  grpc_alarm_init(&alarms[0], tfm(100), cb, (void *)(gpr_intptr)0,
+                  gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_alarm_init(&alarms[1], tfm(3), cb, (void *)(gpr_intptr)1,
+                  gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_alarm_init(&alarms[2], tfm(100), cb, (void *)(gpr_intptr)2,
+                  gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_alarm_init(&alarms[3], tfm(3), cb, (void *)(gpr_intptr)3,
+                  gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_alarm_init(&alarms[4], tfm(1), cb, (void *)(gpr_intptr)4,
+                  gpr_time_0(GPR_CLOCK_REALTIME));
+  GPR_ASSERT(1 == grpc_alarm_check(NULL, tfm(2), NULL));
   GPR_ASSERT(1 == cb_called[4][1]);
   grpc_alarm_cancel(&alarms[0]);
   grpc_alarm_cancel(&alarms[3]);
diff --git a/test/core/iomgr/alarm_test.c b/test/core/iomgr/alarm_test.c
index 0ccec43..362eb5f 100644
--- a/test/core/iomgr/alarm_test.c
+++ b/test/core/iomgr/alarm_test.c
@@ -113,7 +113,7 @@
   gpr_event_init(&arg.fcb_arg);
 
   grpc_alarm_init(&alarm, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100), alarm_cb, &arg,
-                  gpr_now());
+                  gpr_now(GPR_CLOCK_REALTIME));
 
   alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
   gpr_mu_lock(&arg.mu);
@@ -165,7 +165,7 @@
   gpr_event_init(&arg2.fcb_arg);
 
   grpc_alarm_init(&alarm_to_cancel, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100),
-                  alarm_cb, &arg2, gpr_now());
+                  alarm_cb, &arg2, gpr_now(GPR_CLOCK_REALTIME));
   grpc_alarm_cancel(&alarm_to_cancel);
 
   alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index f9c5282..0cfba5f 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -57,6 +57,8 @@
 
 */
 
+static grpc_pollset *g_pollset;
+
 size_t count_and_unref_slices(gpr_slice *slices, size_t nslices,
                               int *current_data) {
   size_t num_bytes = 0;
@@ -111,8 +113,6 @@
 struct read_and_write_test_state {
   grpc_endpoint *read_ep;
   grpc_endpoint *write_ep;
-  gpr_mu mu;
-  gpr_cv cv;
   size_t target_bytes;
   size_t bytes_read;
   size_t current_write_size;
@@ -130,10 +130,10 @@
   GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR);
   if (error == GRPC_ENDPOINT_CB_SHUTDOWN) {
     gpr_log(GPR_INFO, "Read handler shutdown");
-    gpr_mu_lock(&state->mu);
+    gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
     state->read_done = 1;
-    gpr_cv_signal(&state->cv);
-    gpr_mu_unlock(&state->mu);
+    grpc_pollset_kick(g_pollset);
+    gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
     return;
   }
 
@@ -141,10 +141,10 @@
       count_and_unref_slices(slices, nslices, &state->current_read_data);
   if (state->bytes_read == state->target_bytes) {
     gpr_log(GPR_INFO, "Read handler done");
-    gpr_mu_lock(&state->mu);
+    gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
     state->read_done = 1;
-    gpr_cv_signal(&state->cv);
-    gpr_mu_unlock(&state->mu);
+    grpc_pollset_kick(g_pollset);
+    gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
   } else {
     grpc_endpoint_notify_on_read(state->read_ep,
                                  read_and_write_test_read_handler, data);
@@ -160,14 +160,15 @@
 
   GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR);
 
-  gpr_log(GPR_DEBUG, "%s: error=%d", "read_and_write_test_write_handler", error);
+  gpr_log(GPR_DEBUG, "%s: error=%d", "read_and_write_test_write_handler",
+          error);
 
   if (error == GRPC_ENDPOINT_CB_SHUTDOWN) {
     gpr_log(GPR_INFO, "Write handler shutdown");
-    gpr_mu_lock(&state->mu);
+    gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
     state->write_done = 1;
-    gpr_cv_signal(&state->cv);
-    gpr_mu_unlock(&state->mu);
+    grpc_pollset_kick(g_pollset);
+    gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
     return;
   }
 
@@ -198,10 +199,10 @@
   GPR_ASSERT(state->bytes_written == state->target_bytes);
 
   gpr_log(GPR_INFO, "Write handler done");
-  gpr_mu_lock(&state->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
   state->write_done = 1;
-  gpr_cv_signal(&state->cv);
-  gpr_mu_unlock(&state->mu);
+  grpc_pollset_kick(g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
 }
 
 /* Do both reading and writing using the grpc_endpoint API.
@@ -213,7 +214,8 @@
                                 size_t slice_size, int shutdown) {
   struct read_and_write_test_state state;
   gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20);
-  grpc_endpoint_test_fixture f = begin_test(config, "read_and_write_test", slice_size);
+  grpc_endpoint_test_fixture f =
+      begin_test(config, "read_and_write_test", slice_size);
 
   if (shutdown) {
     gpr_log(GPR_INFO, "Start read and write shutdown test");
@@ -222,9 +224,6 @@
             num_bytes, slice_size);
   }
 
-  gpr_mu_init(&state.mu);
-  gpr_cv_init(&state.cv);
-
   state.read_ep = f.client_ep;
   state.write_ep = f.server_ep;
   state.target_bytes = num_bytes;
@@ -253,29 +252,24 @@
     grpc_endpoint_shutdown(state.write_ep);
   }
 
-  gpr_mu_lock(&state.mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
   while (!state.read_done || !state.write_done) {
-    if (gpr_cv_wait(&state.cv, &state.mu, deadline)) {
-      gpr_log(GPR_ERROR, "timeout: read_done=%d, write_done=%d",
-              state.read_done, state.write_done);
-      abort();
-    }
+    GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
+    grpc_pollset_work(g_pollset, deadline);
   }
-  gpr_mu_unlock(&state.mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
 
   grpc_endpoint_destroy(state.read_ep);
   grpc_endpoint_destroy(state.write_ep);
-  gpr_mu_destroy(&state.mu);
-  gpr_cv_destroy(&state.cv);
   end_test(config);
 }
 
 struct timeout_test_state {
-  gpr_event io_done;
+  int io_done;
 };
 
 typedef struct {
-  gpr_event ev;
+  int done;
   grpc_endpoint *ep;
 } shutdown_during_write_test_state;
 
@@ -291,7 +285,10 @@
 
   if (error != GRPC_ENDPOINT_CB_OK) {
     grpc_endpoint_destroy(st->ep);
-    gpr_event_set(&st->ev, (void *)(gpr_intptr) error);
+    gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
+    st->done = error;
+    grpc_pollset_kick(g_pollset);
+    gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
   } else {
     grpc_endpoint_notify_on_read(
         st->ep, shutdown_during_write_test_read_handler, user_data);
@@ -310,7 +307,10 @@
     gpr_log(GPR_ERROR,
             "shutdown_during_write_test_write_handler completed unexpectedly");
   }
-  gpr_event_set(&st->ev, (void *)(gpr_intptr) 1);
+  gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
+  st->done = 1;
+  grpc_pollset_kick(g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
 }
 
 static void shutdown_during_write_test(grpc_endpoint_test_config config,
@@ -323,14 +323,15 @@
   shutdown_during_write_test_state read_st;
   shutdown_during_write_test_state write_st;
   gpr_slice *slices;
-  grpc_endpoint_test_fixture f = begin_test(config, "shutdown_during_write_test", slice_size);
+  grpc_endpoint_test_fixture f =
+      begin_test(config, "shutdown_during_write_test", slice_size);
 
   gpr_log(GPR_INFO, "testing shutdown during a write");
 
   read_st.ep = f.client_ep;
   write_st.ep = f.server_ep;
-  gpr_event_init(&read_st.ev);
-  gpr_event_init(&write_st.ev);
+  read_st.done = 0;
+  write_st.done = 0;
 
   grpc_endpoint_notify_on_read(
       read_st.ep, shutdown_during_write_test_read_handler, &read_st);
@@ -347,9 +348,19 @@
       case GRPC_ENDPOINT_WRITE_PENDING:
         grpc_endpoint_shutdown(write_st.ep);
         deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
-        GPR_ASSERT(gpr_event_wait(&write_st.ev, deadline));
+        gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
+        while (!write_st.done) {
+          GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
+          grpc_pollset_work(g_pollset, deadline);
+        }
+        gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
         grpc_endpoint_destroy(write_st.ep);
-        GPR_ASSERT(gpr_event_wait(&read_st.ev, deadline));
+        gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
+        while (!read_st.done) {
+          GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
+          grpc_pollset_work(g_pollset, deadline);
+        }
+        gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
         gpr_free(slices);
         end_test(config);
         return;
@@ -361,9 +372,12 @@
   abort();
 }
 
-void grpc_endpoint_tests(grpc_endpoint_test_config config) {
+void grpc_endpoint_tests(grpc_endpoint_test_config config,
+                         grpc_pollset *pollset) {
+  g_pollset = pollset;
   read_and_write_test(config, 10000000, 100000, 8192, 0);
   read_and_write_test(config, 1000000, 100000, 1, 0);
   read_and_write_test(config, 100000000, 100000, 1, 1);
   shutdown_during_write_test(config, 1000);
+  g_pollset = NULL;
 }
diff --git a/test/core/iomgr/endpoint_tests.h b/test/core/iomgr/endpoint_tests.h
index 1679d7b..700f854 100644
--- a/test/core/iomgr/endpoint_tests.h
+++ b/test/core/iomgr/endpoint_tests.h
@@ -52,6 +52,7 @@
   void (*clean_up)();
 };
 
-void grpc_endpoint_tests(grpc_endpoint_test_config config);
+void grpc_endpoint_tests(grpc_endpoint_test_config config,
+                         grpc_pollset *pollset);
 
-#endif  /* GRPC_TEST_CORE_IOMGR_ENDPOINT_TESTS_H */
+#endif /* GRPC_TEST_CORE_IOMGR_ENDPOINT_TESTS_H */
diff --git a/src/core/surface/client.h b/test/core/iomgr/fd_conservation_posix_test.c
similarity index 67%
copy from src/core/surface/client.h
copy to test/core/iomgr/fd_conservation_posix_test.c
index 9db2ccf..8327c68 100644
--- a/src/core/surface/client.h
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -31,11 +31,33 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#include <sys/resource.h>
 
-#include "src/core/channel/channel_stack.h"
+#include <grpc/support/log.h>
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+#include "test/core/util/test_config.h"
+#include "src/core/iomgr/endpoint_pair.h"
+#include "src/core/iomgr/iomgr.h"
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+int main(int argc, char **argv) {
+  int i;
+  struct rlimit rlim;
+  grpc_endpoint_pair p;
+  grpc_test_init(argc, argv);
+  grpc_iomgr_init();
+
+  /* set max # of file descriptors to a low value, and
+     verify we can create and destroy many more than this number
+     of descriptors */
+  rlim.rlim_cur = rlim.rlim_max = 10;
+  GPR_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim));
+
+  for (i = 0; i < 100; i++) {
+    p = grpc_iomgr_create_endpoint_pair("test", 1);
+    grpc_endpoint_destroy(p.client);
+    grpc_endpoint_destroy(p.server);
+  }
+
+  grpc_iomgr_shutdown();
+  return 0;
+}
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index 2c8a89e..cd26866 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -51,6 +51,8 @@
 #include <grpc/support/time.h>
 #include "test/core/util/test_config.h"
 
+static grpc_pollset g_pollset;
+
 /* buffer size used to send and receive data.
    1024 is the minimal value to set TCP send and receive buffer. */
 #define BUF_SIZE 1024
@@ -94,16 +96,12 @@
 typedef struct {
   grpc_fd *em_fd;           /* listening fd */
   ssize_t read_bytes_total; /* total number of received bytes */
-  gpr_mu mu;                /* protect done and done_cv */
-  gpr_cv done_cv;           /* signaled when a server finishes serving */
   int done;                 /* set to 1 when a server finishes serving */
   grpc_iomgr_closure listen_closure;
 } server;
 
 static void server_init(server *sv) {
   sv->read_bytes_total = 0;
-  gpr_mu_init(&sv->mu);
-  gpr_cv_init(&sv->done_cv);
   sv->done = 0;
 }
 
@@ -122,7 +120,7 @@
                                 int success) {
   session *se = arg;
   server *sv = se->sv;
-  grpc_fd_orphan(se->em_fd, NULL, NULL);
+  grpc_fd_orphan(se->em_fd, NULL, "a");
   gpr_free(se);
   /* Start to shutdown listen fd. */
   grpc_fd_shutdown(sv->em_fd);
@@ -177,12 +175,12 @@
 static void listen_shutdown_cb(void *arg /*server*/, int success) {
   server *sv = arg;
 
-  grpc_fd_orphan(sv->em_fd, NULL, NULL);
+  grpc_fd_orphan(sv->em_fd, NULL, "b");
 
-  gpr_mu_lock(&sv->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   sv->done = 1;
-  gpr_cv_signal(&sv->done_cv);
-  gpr_mu_unlock(&sv->mu);
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 /* Called when a new TCP connection request arrives in the listening port. */
@@ -209,6 +207,7 @@
   se = gpr_malloc(sizeof(*se));
   se->sv = sv;
   se->em_fd = grpc_fd_create(fd, "listener");
+  grpc_pollset_add_fd(&g_pollset, se->em_fd);
   se->session_read_closure.cb = session_read_cb;
   se->session_read_closure.cb_arg = se;
   grpc_fd_notify_on_read(se->em_fd, &se->session_read_closure);
@@ -237,6 +236,7 @@
   GPR_ASSERT(listen(fd, MAX_NUM_FD) == 0);
 
   sv->em_fd = grpc_fd_create(fd, "server");
+  grpc_pollset_add_fd(&g_pollset, sv->em_fd);
   /* Register to be interested in reading from listen_fd. */
   sv->listen_closure.cb = listen_cb;
   sv->listen_closure.cb_arg = sv;
@@ -247,12 +247,11 @@
 
 /* Wait and shutdown a sever. */
 static void server_wait_and_shutdown(server *sv) {
-  gpr_mu_lock(&sv->mu);
-  while (!sv->done) gpr_cv_wait(&sv->done_cv, &sv->mu, gpr_inf_future);
-  gpr_mu_unlock(&sv->mu);
-
-  gpr_mu_destroy(&sv->mu);
-  gpr_cv_destroy(&sv->done_cv);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (!sv->done) {
+    grpc_pollset_work(&g_pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 /* ===An upload client to test notify_on_write=== */
@@ -271,9 +270,7 @@
      notify_on_write to schedule another write. */
   int client_write_cnt;
 
-  gpr_mu mu;      /* protect done and done_cv */
-  gpr_cv done_cv; /* signaled when a client finishes sending */
-  int done;       /* set to 1 when a client finishes sending */
+  int done; /* set to 1 when a client finishes sending */
   grpc_iomgr_closure write_closure;
 } client;
 
@@ -281,17 +278,15 @@
   memset(cl->write_buf, 0, sizeof(cl->write_buf));
   cl->write_bytes_total = 0;
   cl->client_write_cnt = 0;
-  gpr_mu_init(&cl->mu);
-  gpr_cv_init(&cl->done_cv);
   cl->done = 0;
 }
 
 /* Called when a client upload session is ready to shutdown. */
 static void client_session_shutdown_cb(void *arg /*client*/, int success) {
   client *cl = arg;
-  grpc_fd_orphan(cl->em_fd, NULL, NULL);
+  grpc_fd_orphan(cl->em_fd, NULL, "c");
   cl->done = 1;
-  gpr_cv_signal(&cl->done_cv);
+  grpc_pollset_kick(&g_pollset);
 }
 
 /* Write as much as possible, then register notify_on_write. */
@@ -302,9 +297,9 @@
   ssize_t write_once = 0;
 
   if (!success) {
-    gpr_mu_lock(&cl->mu);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
     client_session_shutdown_cb(arg, 1);
-    gpr_mu_unlock(&cl->mu);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
     return;
   }
 
@@ -314,7 +309,7 @@
   } while (write_once > 0);
 
   if (errno == EAGAIN) {
-    gpr_mu_lock(&cl->mu);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
     if (cl->client_write_cnt < CLIENT_TOTAL_WRITE_CNT) {
       cl->write_closure.cb = client_session_write;
       cl->write_closure.cb_arg = cl;
@@ -323,7 +318,7 @@
     } else {
       client_session_shutdown_cb(arg, 1);
     }
-    gpr_mu_unlock(&cl->mu);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   } else {
     gpr_log(GPR_ERROR, "unknown errno %s", strerror(errno));
     abort();
@@ -352,18 +347,18 @@
   }
 
   cl->em_fd = grpc_fd_create(fd, "client");
+  grpc_pollset_add_fd(&g_pollset, cl->em_fd);
 
   client_session_write(cl, 1);
 }
 
 /* Wait for the signal to shutdown a client. */
 static void client_wait_and_shutdown(client *cl) {
-  gpr_mu_lock(&cl->mu);
-  while (!cl->done) gpr_cv_wait(&cl->done_cv, &cl->mu, gpr_inf_future);
-  gpr_mu_unlock(&cl->mu);
-
-  gpr_mu_destroy(&cl->mu);
-  gpr_cv_destroy(&cl->done_cv);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (!cl->done) {
+    grpc_pollset_work(&g_pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 /* Test grpc_fd. Start an upload server and client, upload a stream of
@@ -385,38 +380,29 @@
 }
 
 typedef struct fd_change_data {
-  gpr_mu mu;
-  gpr_cv cv;
   void (*cb_that_ran)(void *, int success);
 } fd_change_data;
 
-void init_change_data(fd_change_data *fdc) {
-  gpr_mu_init(&fdc->mu);
-  gpr_cv_init(&fdc->cv);
-  fdc->cb_that_ran = NULL;
-}
+void init_change_data(fd_change_data *fdc) { fdc->cb_that_ran = NULL; }
 
-void destroy_change_data(fd_change_data *fdc) {
-  gpr_mu_destroy(&fdc->mu);
-  gpr_cv_destroy(&fdc->cv);
-}
+void destroy_change_data(fd_change_data *fdc) {}
 
 static void first_read_callback(void *arg /* fd_change_data */, int success) {
   fd_change_data *fdc = arg;
 
-  gpr_mu_lock(&fdc->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   fdc->cb_that_ran = first_read_callback;
-  gpr_cv_signal(&fdc->cv);
-  gpr_mu_unlock(&fdc->mu);
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 static void second_read_callback(void *arg /* fd_change_data */, int success) {
   fd_change_data *fdc = arg;
 
-  gpr_mu_lock(&fdc->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   fdc->cb_that_ran = second_read_callback;
-  gpr_cv_signal(&fdc->cv);
-  gpr_mu_unlock(&fdc->mu);
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 /* Test that changing the callback we use for notify_on_read actually works.
@@ -448,6 +434,7 @@
   GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
 
   em_fd = grpc_fd_create(sv[0], "test_grpc_fd_change");
+  grpc_pollset_add_fd(&g_pollset, em_fd);
 
   /* Register the first callback, then make its FD readable */
   grpc_fd_notify_on_read(em_fd, &first_closure);
@@ -456,12 +443,12 @@
   GPR_ASSERT(result == 1);
 
   /* And now wait for it to run. */
-  gpr_mu_lock(&a.mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (a.cb_that_ran == NULL) {
-    gpr_cv_wait(&a.cv, &a.mu, gpr_inf_future);
+    grpc_pollset_work(&g_pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   GPR_ASSERT(a.cb_that_ran == first_read_callback);
-  gpr_mu_unlock(&a.mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
   /* And drain the socket so we can generate a new read edge */
   result = read(sv[0], &data, 1);
@@ -474,25 +461,29 @@
   result = write(sv[1], &data, 1);
   GPR_ASSERT(result == 1);
 
-  gpr_mu_lock(&b.mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (b.cb_that_ran == NULL) {
-    gpr_cv_wait(&b.cv, &b.mu, gpr_inf_future);
+    grpc_pollset_work(&g_pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   /* Except now we verify that second_read_callback ran instead */
   GPR_ASSERT(b.cb_that_ran == second_read_callback);
-  gpr_mu_unlock(&b.mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
-  grpc_fd_orphan(em_fd, NULL, NULL);
+  grpc_fd_orphan(em_fd, NULL, "d");
   destroy_change_data(&a);
   destroy_change_data(&b);
   close(sv[1]);
 }
 
+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_grpc_fd();
   test_grpc_fd_change();
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
   grpc_iomgr_shutdown();
   return 0;
 }
diff --git a/test/core/iomgr/poll_kick_posix_test.c b/test/core/iomgr/poll_kick_posix_test.c
index 2c5b444..3aa6807 100644
--- a/test/core/iomgr/poll_kick_posix_test.c
+++ b/test/core/iomgr/poll_kick_posix_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/pollset_kick.h"
+#include "src/core/iomgr/pollset_kick_posix.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -45,31 +45,31 @@
 
 static void test_non_kick(void) {
   grpc_pollset_kick_state state;
-  int fd;
+  grpc_kick_fd_info *kfd;
 
   grpc_pollset_kick_init(&state);
-  fd = grpc_pollset_kick_pre_poll(&state);
-  GPR_ASSERT(fd >= 0);
+  kfd = grpc_pollset_kick_pre_poll(&state);
+  GPR_ASSERT(kfd != NULL);
 
-  grpc_pollset_kick_post_poll(&state);
+  grpc_pollset_kick_post_poll(&state, kfd);
   grpc_pollset_kick_destroy(&state);
 }
 
 static void test_basic_kick(void) {
   /* Kicked during poll */
   grpc_pollset_kick_state state;
-  int fd;
+  grpc_kick_fd_info *kfd;
   grpc_pollset_kick_init(&state);
 
-  fd = grpc_pollset_kick_pre_poll(&state);
-  GPR_ASSERT(fd >= 0);
+  kfd = grpc_pollset_kick_pre_poll(&state);
+  GPR_ASSERT(kfd != NULL);
 
   grpc_pollset_kick_kick(&state);
 
   /* Now hypothetically we polled and found that we were kicked */
-  grpc_pollset_kick_consume(&state);
+  grpc_pollset_kick_consume(&state, kfd);
 
-  grpc_pollset_kick_post_poll(&state);
+  grpc_pollset_kick_post_poll(&state, kfd);
 
   grpc_pollset_kick_destroy(&state);
 }
@@ -77,13 +77,13 @@
 static void test_non_poll_kick(void) {
   /* Kick before entering poll */
   grpc_pollset_kick_state state;
-  int fd;
+  grpc_kick_fd_info *kfd;
 
   grpc_pollset_kick_init(&state);
 
   grpc_pollset_kick_kick(&state);
-  fd = grpc_pollset_kick_pre_poll(&state);
-  GPR_ASSERT(fd < 0);
+  kfd = grpc_pollset_kick_pre_poll(&state);
+  GPR_ASSERT(kfd == NULL);
   grpc_pollset_kick_destroy(&state);
 }
 
@@ -92,20 +92,20 @@
 static void test_over_free(void) {
   /* Check high watermark pipe free logic */
   int i;
-  struct grpc_pollset_kick_state *kick_state =
-      gpr_malloc(sizeof(grpc_pollset_kick_state) * GRPC_MAX_CACHED_PIPES);
+  grpc_kick_fd_info **kfds =
+      gpr_malloc(sizeof(grpc_kick_fd_info *) * GRPC_MAX_CACHED_PIPES);
+  grpc_pollset_kick_state state;
+  grpc_pollset_kick_init(&state);
   for (i = 0; i < GRPC_MAX_CACHED_PIPES; ++i) {
-    int fd;
-    grpc_pollset_kick_init(&kick_state[i]);
-    fd = grpc_pollset_kick_pre_poll(&kick_state[i]);
-    GPR_ASSERT(fd >= 0);
+    kfds[i] = grpc_pollset_kick_pre_poll(&state);
+    GPR_ASSERT(kfds[i] != NULL);
   }
 
   for (i = 0; i < GRPC_MAX_CACHED_PIPES; ++i) {
-    grpc_pollset_kick_post_poll(&kick_state[i]);
-    grpc_pollset_kick_destroy(&kick_state[i]);
+    grpc_pollset_kick_post_poll(&state, kfds[i]);
   }
-  gpr_free(kick_state);
+  grpc_pollset_kick_destroy(&state);
+  gpr_free(kfds);
 }
 
 static void run_tests(void) {
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 3c4d8fe..637886a 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -45,20 +45,31 @@
 #include <grpc/support/time.h>
 #include "test/core/util/test_config.h"
 
+static grpc_pollset_set g_pollset_set;
+static grpc_pollset g_pollset;
+static int g_connections_complete = 0;
+
 static gpr_timespec test_deadline(void) {
   return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
 }
 
+static void finish_connection() {
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  g_connections_complete++;
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+}
+
 static void must_succeed(void *arg, grpc_endpoint *tcp) {
   GPR_ASSERT(tcp);
   grpc_endpoint_shutdown(tcp);
   grpc_endpoint_destroy(tcp);
-  gpr_event_set(arg, (void *)1);
+  finish_connection();
 }
 
 static void must_fail(void *arg, grpc_endpoint *tcp) {
   GPR_ASSERT(!tcp);
-  gpr_event_set(arg, (void *)1);
+  finish_connection();
 }
 
 void test_succeeds(void) {
@@ -66,9 +77,9 @@
   socklen_t addr_len = sizeof(addr);
   int svr_fd;
   int r;
-  gpr_event ev;
+  int connections_complete_before;
 
-  gpr_event_init(&ev);
+  gpr_log(GPR_DEBUG, "test_succeeds");
 
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
@@ -79,10 +90,15 @@
   GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len));
   GPR_ASSERT(0 == listen(svr_fd, 1));
 
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  connections_complete_before = g_connections_complete;
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+
   /* connect to it */
   GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0);
-  grpc_tcp_client_connect(must_succeed, &ev, (struct sockaddr *)&addr, addr_len,
-                          gpr_inf_future);
+  grpc_tcp_client_connect(must_succeed, NULL, &g_pollset_set,
+                          (struct sockaddr *)&addr, addr_len,
+                          gpr_inf_future(GPR_CLOCK_REALTIME));
 
   /* await the connection */
   do {
@@ -92,40 +108,56 @@
   GPR_ASSERT(r >= 0);
   close(r);
 
-  /* wait for the connection callback to finish */
-  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+
+  while (g_connections_complete == connections_complete_before) {
+    grpc_pollset_work(&g_pollset, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5));
+  }
+
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 void test_fails(void) {
   struct sockaddr_in addr;
   socklen_t addr_len = sizeof(addr);
-  gpr_event ev;
+  int connections_complete_before;
 
-  gpr_event_init(&ev);
+  gpr_log(GPR_DEBUG, "test_fails");
 
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
 
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  connections_complete_before = g_connections_complete;
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+
   /* connect to a broken address */
-  grpc_tcp_client_connect(must_fail, &ev, (struct sockaddr *)&addr, addr_len,
-                          gpr_inf_future);
+  grpc_tcp_client_connect(must_fail, NULL, &g_pollset_set,
+                          (struct sockaddr *)&addr, addr_len,
+                          gpr_inf_future(GPR_CLOCK_REALTIME));
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
 
   /* wait for the connection callback to finish */
-  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  while (g_connections_complete == connections_complete_before) {
+    grpc_pollset_work(&g_pollset, test_deadline());
+  }
+
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 void test_times_out(void) {
   struct sockaddr_in addr;
   socklen_t addr_len = sizeof(addr);
   int svr_fd;
-#define NUM_CLIENT_CONNECTS 10
+#define NUM_CLIENT_CONNECTS 100
   int client_fd[NUM_CLIENT_CONNECTS];
   int i;
   int r;
-  gpr_event ev;
+  int connections_complete_before;
   gpr_timespec connect_deadline;
 
-  gpr_event_init(&ev);
+  gpr_log(GPR_DEBUG, "test_times_out");
 
   memset(&addr, 0, sizeof(addr));
   addr.sin_family = AF_INET;
@@ -153,28 +185,53 @@
 
   connect_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
 
-  grpc_tcp_client_connect(must_fail, &ev, (struct sockaddr *)&addr, addr_len,
-                          connect_deadline);
-  /* Make sure the event doesn't trigger early */
-  GPR_ASSERT(!gpr_event_wait(&ev, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(500)));
-  /* Now wait until it should have triggered */
-  sleep(1);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  connections_complete_before = g_connections_complete;
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
-  /* wait for the connection callback to finish */
-  GPR_ASSERT(gpr_event_wait(&ev, test_deadline()));
+  grpc_tcp_client_connect(must_fail, NULL, &g_pollset_set,
+                          (struct sockaddr *)&addr, addr_len, connect_deadline);
+
+  /* Make sure the event doesn't trigger early */
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (gpr_time_cmp(gpr_time_add(connect_deadline,
+                                   gpr_time_from_seconds(2, GPR_TIMESPAN)),
+                      gpr_now(GPR_CLOCK_REALTIME)) > 0) {
+    int is_after_deadline =
+        gpr_time_cmp(connect_deadline, gpr_now(GPR_CLOCK_REALTIME)) <= 0;
+    if (is_after_deadline &&
+        gpr_time_cmp(gpr_time_add(connect_deadline,
+                                  gpr_time_from_seconds(1, GPR_TIMESPAN)),
+                     gpr_now(GPR_CLOCK_REALTIME)) > 0) {
+      /* allow some slack before insisting that things be done */
+    } else {
+      GPR_ASSERT(g_connections_complete ==
+                 connections_complete_before + is_after_deadline);
+    }
+    grpc_pollset_work(&g_pollset, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10));
+  }
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+
   close(svr_fd);
   for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) {
     close(client_fd[i]);
   }
 }
 
+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_set_init(&g_pollset_set);
+  grpc_pollset_init(&g_pollset);
+  grpc_pollset_set_add_pollset(&g_pollset_set, &g_pollset);
   test_succeeds();
   gpr_log(GPR_ERROR, "End of first test");
   test_fails();
   test_times_out();
+  grpc_pollset_set_destroy(&g_pollset_set);
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
   grpc_iomgr_shutdown();
   return 0;
 }
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index 2cfcc83..a23c649 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -48,6 +48,8 @@
 #include "test/core/util/test_config.h"
 #include "test/core/iomgr/endpoint_tests.h"
 
+static grpc_pollset g_pollset;
+
 /*
    General test notes:
 
@@ -114,8 +116,6 @@
 
 struct read_socket_state {
   grpc_endpoint *ep;
-  gpr_mu mu;
-  gpr_cv cv;
   ssize_t read_bytes;
   ssize_t target_read_bytes;
 };
@@ -145,18 +145,18 @@
 
   GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK);
 
-  gpr_mu_lock(&state->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   current_data = state->read_bytes % 256;
   read_bytes = count_and_unref_slices(slices, nslices, &current_data);
   state->read_bytes += read_bytes;
   gpr_log(GPR_INFO, "Read %d bytes of %d", read_bytes,
           state->target_read_bytes);
   if (state->read_bytes >= state->target_read_bytes) {
-    gpr_cv_signal(&state->cv);
+    /* empty */
   } else {
     grpc_endpoint_notify_on_read(state->ep, read_cb, state);
   }
-  gpr_mu_unlock(&state->mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 /* Write to a socket, then read from it using the grpc_tcp API. */
@@ -173,31 +173,25 @@
   create_sockets(sv);
 
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), slice_size);
+  grpc_endpoint_add_to_pollset(ep, &g_pollset);
+
   written_bytes = fill_socket_partial(sv[0], num_bytes);
   gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes);
 
-  gpr_mu_init(&state.mu);
-  gpr_cv_init(&state.cv);
   state.ep = ep;
   state.read_bytes = 0;
   state.target_read_bytes = written_bytes;
 
   grpc_endpoint_notify_on_read(ep, read_cb, &state);
 
-  gpr_mu_lock(&state.mu);
-  for (;;) {
-    GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
-    if (state.read_bytes >= state.target_read_bytes) {
-      break;
-    }
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (state.read_bytes < state.target_read_bytes) {
+    grpc_pollset_work(&g_pollset, deadline);
   }
   GPR_ASSERT(state.read_bytes == state.target_read_bytes);
-  gpr_mu_unlock(&state.mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
   grpc_endpoint_destroy(ep);
-
-  gpr_mu_destroy(&state.mu);
-  gpr_cv_destroy(&state.cv);
 }
 
 /* Write to a socket until it fills up, then read from it using the grpc_tcp
@@ -214,37 +208,29 @@
   create_sockets(sv);
 
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), slice_size);
+  grpc_endpoint_add_to_pollset(ep, &g_pollset);
+
   written_bytes = fill_socket(sv[0]);
   gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes);
 
-  gpr_mu_init(&state.mu);
-  gpr_cv_init(&state.cv);
   state.ep = ep;
   state.read_bytes = 0;
   state.target_read_bytes = written_bytes;
 
   grpc_endpoint_notify_on_read(ep, read_cb, &state);
 
-  gpr_mu_lock(&state.mu);
-  for (;;) {
-    GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
-    if (state.read_bytes >= state.target_read_bytes) {
-      break;
-    }
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (state.read_bytes < state.target_read_bytes) {
+    grpc_pollset_work(&g_pollset, deadline);
   }
   GPR_ASSERT(state.read_bytes == state.target_read_bytes);
-  gpr_mu_unlock(&state.mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
   grpc_endpoint_destroy(ep);
-
-  gpr_mu_destroy(&state.mu);
-  gpr_cv_destroy(&state.cv);
 }
 
 struct write_socket_state {
   grpc_endpoint *ep;
-  gpr_mu mu;
-  gpr_cv cv;
   int write_done;
 };
 
@@ -275,11 +261,11 @@
                        grpc_endpoint_cb_status error) {
   struct write_socket_state *state = (struct write_socket_state *)user_data;
   gpr_log(GPR_INFO, "Write done callback called");
-  gpr_mu_lock(&state->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   gpr_log(GPR_INFO, "Signalling write done");
   state->write_done = 1;
-  gpr_cv_signal(&state->cv);
-  gpr_mu_unlock(&state->mu);
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 void drain_socket_blocking(int fd, size_t num_bytes, size_t read_size) {
@@ -294,6 +280,9 @@
   GPR_ASSERT(fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == 0);
 
   for (;;) {
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_pollset_work(&g_pollset, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10));
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
     do {
       bytes_read =
           read(fd, buf, bytes_left > read_size ? read_size : bytes_left);
@@ -352,9 +341,8 @@
 
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"),
                        GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
+  grpc_endpoint_add_to_pollset(ep, &g_pollset);
 
-  gpr_mu_init(&state.mu);
-  gpr_cv_init(&state.cv);
   state.ep = ep;
   state.write_done = 0;
 
@@ -367,19 +355,17 @@
     GPR_ASSERT(read_bytes == num_bytes);
   } else {
     drain_socket_blocking(sv[0], num_bytes, num_bytes);
-    gpr_mu_lock(&state.mu);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
     for (;;) {
       if (state.write_done) {
         break;
       }
-      GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+      grpc_pollset_work(&g_pollset, deadline);
     }
-    gpr_mu_unlock(&state.mu);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   }
 
   grpc_endpoint_destroy(ep);
-  gpr_mu_destroy(&state.mu);
-  gpr_cv_destroy(&state.cv);
   gpr_free(slices);
 }
 
@@ -409,10 +395,10 @@
 
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_error_test"),
                        GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
+  grpc_endpoint_add_to_pollset(ep, &g_pollset);
+
   close(sv[0]);
 
-  gpr_mu_init(&state.mu);
-  gpr_cv_init(&state.cv);
   state.ep = ep;
   state.write_done = 0;
 
@@ -425,20 +411,18 @@
       break;
     case GRPC_ENDPOINT_WRITE_PENDING:
       grpc_endpoint_notify_on_read(ep, read_done_for_write_error, NULL);
-      gpr_mu_lock(&state.mu);
+      gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
       for (;;) {
         if (state.write_done) {
           break;
         }
-        GPR_ASSERT(gpr_cv_wait(&state.cv, &state.mu, deadline) == 0);
+        grpc_pollset_work(&g_pollset, deadline);
       }
-      gpr_mu_unlock(&state.mu);
+      gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
       break;
   }
 
   grpc_endpoint_destroy(ep);
-  gpr_mu_destroy(&state.mu);
-  gpr_cv_destroy(&state.cv);
   free(slices);
 }
 
@@ -479,6 +463,8 @@
       grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"), slice_size);
   f.server_ep =
       grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"), slice_size);
+  grpc_endpoint_add_to_pollset(f.client_ep, &g_pollset);
+  grpc_endpoint_add_to_pollset(f.server_ep, &g_pollset);
 
   return f;
 }
@@ -487,11 +473,15 @@
     {"tcp/tcp_socketpair", create_fixture_tcp_socketpair, clean_up},
 };
 
+static void destroy_pollset(void *p) { grpc_pollset_destroy(p); }
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   grpc_init();
+  grpc_pollset_init(&g_pollset);
   run_tests();
-  grpc_endpoint_tests(configs[0]);
+  grpc_endpoint_tests(configs[0], &g_pollset);
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
   grpc_shutdown();
 
   return 0;
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 328b19f..83252a8 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -45,18 +45,17 @@
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", #x)
 
-static gpr_mu mu;
-static gpr_cv cv;
-static int nconnects = 0;
+static grpc_pollset g_pollset;
+static int g_nconnects = 0;
 
 static void on_connect(void *arg, grpc_endpoint *tcp) {
   grpc_endpoint_shutdown(tcp);
   grpc_endpoint_destroy(tcp);
 
-  gpr_mu_lock(&mu);
-  nconnects++;
-  gpr_cv_broadcast(&cv);
-  gpr_mu_unlock(&mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  g_nconnects++;
+  grpc_pollset_kick(&g_pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
 static void test_no_op(void) {
@@ -106,12 +105,11 @@
   grpc_tcp_server *s = grpc_tcp_server_create();
   int nconnects_before;
   gpr_timespec deadline;
+  grpc_pollset *pollsets[1];
   int i;
   LOG_TEST("test_connect");
   gpr_log(GPR_INFO, "clients=%d", n);
 
-  gpr_mu_lock(&mu);
-
   memset(&addr, 0, sizeof(addr));
   addr.ss_family = AF_INET;
   GPR_ASSERT(grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, addr_len));
@@ -121,38 +119,42 @@
   GPR_ASSERT(getsockname(svrfd, (struct sockaddr *)&addr, &addr_len) == 0);
   GPR_ASSERT(addr_len <= sizeof(addr));
 
-  grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
+  pollsets[0] = &g_pollset;
+  grpc_tcp_server_start(s, pollsets, 1, on_connect, NULL);
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
 
   for (i = 0; i < n; i++) {
-    deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
+    deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
 
-    nconnects_before = nconnects;
+    nconnects_before = g_nconnects;
     clifd = socket(addr.ss_family, SOCK_STREAM, 0);
     GPR_ASSERT(clifd >= 0);
+    gpr_log(GPR_DEBUG, "start connect");
     GPR_ASSERT(connect(clifd, (struct sockaddr *)&addr, addr_len) == 0);
 
-    while (nconnects == nconnects_before) {
-      GPR_ASSERT(gpr_cv_wait(&cv, &mu, deadline) == 0);
+    gpr_log(GPR_DEBUG, "wait");
+    while (g_nconnects == nconnects_before &&
+           gpr_time_cmp(deadline, gpr_now(GPR_CLOCK_REALTIME)) > 0) {
+      grpc_pollset_work(&g_pollset, deadline);
     }
+    gpr_log(GPR_DEBUG, "wait done");
 
-    GPR_ASSERT(nconnects == nconnects_before + 1);
+    GPR_ASSERT(g_nconnects == nconnects_before + 1);
     close(clifd);
-
-    if (i != n - 1) {
-      sleep(1);
-    }
   }
 
-  gpr_mu_unlock(&mu);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
   grpc_tcp_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();
-  gpr_mu_init(&mu);
-  gpr_cv_init(&cv);
+  grpc_pollset_init(&g_pollset);
 
   test_no_op();
   test_no_op_with_start();
@@ -161,8 +163,7 @@
   test_connect(1);
   test_connect(10);
 
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
   grpc_iomgr_shutdown();
-  gpr_mu_destroy(&mu);
-  gpr_cv_destroy(&cv);
   return 0;
 }
diff --git a/test/core/json/json_rewrite_test.c b/test/core/json/json_rewrite_test.c
index ec6deeb..f585932 100644
--- a/test/core/json/json_rewrite_test.c
+++ b/test/core/json/json_rewrite_test.c
@@ -64,6 +64,11 @@
 static void json_writer_output_char(void* userdata, char c) {
   json_writer_userdata* state = userdata;
   int cmp = fgetc(state->cmp);
+
+  /* treat CRLF as LF */
+  if (cmp == '\r' && c == '\n') {
+    cmp = fgetc(state->cmp);
+  }
   GPR_ASSERT(cmp == c);
 }
 
diff --git a/test/core/network_benchmarks/low_level_ping_pong.c b/test/core/network_benchmarks/low_level_ping_pong.c
index 78a0eef..0ce4bd4 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.c
+++ b/test/core/network_benchmarks/low_level_ping_pong.c
@@ -296,7 +296,7 @@
 }
 
 static double now(void) {
-  gpr_timespec tv = gpr_now();
+  gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME);
   return 1e9 * tv.tv_sec + tv.tv_nsec;
 }
 
diff --git a/test/core/security/auth_context_test.c b/test/core/security/auth_context_test.c
index 2fb0c01..a30505a 100644
--- a/test/core/security/auth_context_test.c
+++ b/test/core/security/auth_context_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include<string.h>
+#include <string.h>
 
 #include "src/core/security/security_context.h"
 #include "src/core/support/string.h"
@@ -52,7 +52,7 @@
   GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL);
   it = grpc_auth_context_find_properties_by_name(ctx, "foo");
   GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL);
-  grpc_auth_context_unref(ctx);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
 }
 
 static void test_simple_context(void) {
@@ -86,7 +86,7 @@
   GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &ctx->properties[1]);
   GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL);
 
-  grpc_auth_context_unref(ctx);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
 }
 
 static void test_chained_context(void) {
@@ -96,7 +96,7 @@
   size_t i;
 
   gpr_log(GPR_INFO, "test_chained_context");
-  grpc_auth_context_unref(chained);
+  GRPC_AUTH_CONTEXT_UNREF(chained, "chained");
   chained->properties[0] =
       grpc_auth_property_init_from_cstring("name", "padapo");
   chained->properties[1] = grpc_auth_property_init_from_cstring("foo", "baz");
@@ -129,7 +129,7 @@
   GPR_ASSERT(grpc_auth_property_iterator_next(&it) == &chained->properties[0]);
   GPR_ASSERT(grpc_auth_property_iterator_next(&it) == NULL);
 
-  grpc_auth_context_unref(ctx);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
 }
 
 
diff --git a/test/core/security/base64_test.c b/test/core/security/base64_test.c
index a922896..f8b7ebf 100644
--- a/test/core/security/base64_test.c
+++ b/test/core/security/base64_test.c
@@ -169,6 +169,43 @@
   gpr_free(b64);
 }
 
+static void test_unpadded_decode(void) {
+  gpr_slice decoded;
+
+  decoded = grpc_base64_decode("Zm9vYmFy", 0);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(decoded));
+  GPR_ASSERT(gpr_slice_str_cmp(decoded, "foobar") == 0);
+  gpr_slice_unref(decoded);
+
+  decoded = grpc_base64_decode("Zm9vYmE", 0);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(decoded));
+  GPR_ASSERT(gpr_slice_str_cmp(decoded, "fooba") == 0);
+  gpr_slice_unref(decoded);
+
+  decoded = grpc_base64_decode("Zm9vYg", 0);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(decoded));
+  GPR_ASSERT(gpr_slice_str_cmp(decoded, "foob") == 0);
+  gpr_slice_unref(decoded);
+
+  decoded = grpc_base64_decode("Zm9v", 0);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(decoded));
+  GPR_ASSERT(gpr_slice_str_cmp(decoded, "foo") == 0);
+  gpr_slice_unref(decoded);
+
+  decoded = grpc_base64_decode("Zm8", 0);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(decoded));
+  GPR_ASSERT(gpr_slice_str_cmp(decoded, "fo") == 0);
+  gpr_slice_unref(decoded);
+
+  decoded = grpc_base64_decode("Zg", 0);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(decoded));
+  GPR_ASSERT(gpr_slice_str_cmp(decoded, "f") == 0);
+  gpr_slice_unref(decoded);
+
+  decoded = grpc_base64_decode("", 0);
+  GPR_ASSERT(GPR_SLICE_IS_EMPTY(decoded));
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_simple_encode_decode_b64_no_multiline();
@@ -181,5 +218,6 @@
   test_full_range_encode_decode_b64_urlsafe_multiline();
   test_url_safe_unsafe_mismtach_failure();
   test_rfc4648_test_vectors();
+  test_unpadded_decode();
   return 0;
 }
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 69ec680..d3fea96 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -37,12 +37,17 @@
 
 #include "src/core/httpcli/httpcli.h"
 #include "src/core/security/json_token.h"
+#include "src/core/support/env.h"
+#include "src/core/support/file.h"
 #include "src/core/support/string.h"
+
+#include "test/core/util/test_config.h"
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include "test/core/util/test_config.h"
+
 #include <openssl/rsa.h>
 
 static const char test_iam_authorization_token[] = "blahblahblhahb";
@@ -210,8 +215,7 @@
   grpc_httpcli_response response =
       http_response(200, valid_oauth2_json_response);
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
-             GRPC_CREDENTIALS_OK);
+                 &response, &token_md, &token_lifetime) == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(token_lifetime.tv_sec == 3599);
   GPR_ASSERT(token_lifetime.tv_nsec == 0);
   GPR_ASSERT(token_md->num_entries == 1);
@@ -328,10 +332,31 @@
       test_iam_authorization_token, test_iam_authority_selector);
   GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
-  grpc_credentials_get_request_metadata(creds, test_service_url,
+  grpc_credentials_get_request_metadata(creds, NULL, test_service_url,
                                         check_iam_metadata, creds);
 }
 
+static void check_access_token_metadata(void *user_data,
+                                        grpc_credentials_md *md_elems,
+                                        size_t num_md,
+                                        grpc_credentials_status status) {
+  grpc_credentials *c = (grpc_credentials *)user_data;
+  expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}};
+  GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
+  GPR_ASSERT(num_md == 1);
+  check_metadata(emd, md_elems, num_md);
+  grpc_credentials_unref(c);
+}
+
+static void test_access_token_creds(void) {
+  grpc_credentials *creds = grpc_access_token_credentials_create("blah");
+  GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
+  GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
+  GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
+  grpc_credentials_get_request_metadata(creds, NULL, test_service_url,
+                                        check_access_token_metadata, creds);
+}
+
 static void check_ssl_oauth2_composite_metadata(
     void *user_data, grpc_credentials_md *md_elems, size_t num_md,
     grpc_credentials_status status) {
@@ -354,8 +379,8 @@
       grpc_composite_credentials_create(ssl_creds, oauth2_creds);
   grpc_credentials_unref(ssl_creds);
   grpc_credentials_unref(oauth2_creds);
-  GPR_ASSERT(strcmp(composite_creds->type,
-                    GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
+  GPR_ASSERT(strcmp(composite_creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) ==
+             0);
   GPR_ASSERT(grpc_credentials_has_request_metadata(composite_creds));
   GPR_ASSERT(!grpc_credentials_has_request_metadata_only(composite_creds));
   creds_array = grpc_composite_credentials_get_credentials(composite_creds);
@@ -364,14 +389,13 @@
                     GRPC_CREDENTIALS_TYPE_SSL) == 0);
   GPR_ASSERT(strcmp(creds_array->creds_array[1]->type,
                     GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
-  grpc_credentials_get_request_metadata(composite_creds, test_service_url,
+  grpc_credentials_get_request_metadata(composite_creds, NULL, test_service_url,
                                         check_ssl_oauth2_composite_metadata,
                                         composite_creds);
 }
 
 void test_ssl_fake_transport_security_composite_creds_failure(void) {
-  grpc_credentials *ssl_creds =
-      grpc_ssl_credentials_create(NULL, NULL);
+  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
   grpc_credentials *fake_transport_security_creds =
       grpc_fake_transport_security_credentials_create();
 
@@ -412,8 +436,8 @@
   grpc_credentials_unref(oauth2_creds);
   grpc_credentials_unref(aux_creds);
   grpc_credentials_unref(iam_creds);
-  GPR_ASSERT(strcmp(composite_creds->type,
-                    GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
+  GPR_ASSERT(strcmp(composite_creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) ==
+             0);
   GPR_ASSERT(grpc_credentials_has_request_metadata(composite_creds));
   GPR_ASSERT(!grpc_credentials_has_request_metadata_only(composite_creds));
   creds_array = grpc_composite_credentials_get_credentials(composite_creds);
@@ -424,7 +448,7 @@
                     GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
   GPR_ASSERT(strcmp(creds_array->creds_array[2]->type,
                     GRPC_CREDENTIALS_TYPE_IAM) == 0);
-  grpc_credentials_get_request_metadata(composite_creds, test_service_url,
+  grpc_credentials_get_request_metadata(composite_creds, NULL, test_service_url,
                                         check_ssl_oauth2_iam_composite_metadata,
                                         composite_creds);
 }
@@ -455,9 +479,10 @@
     const grpc_httpcli_request *request) {
   GPR_ASSERT(!request->use_ssl);
   GPR_ASSERT(strcmp(request->host, "metadata") == 0);
-  GPR_ASSERT(strcmp(request->path,
-             "/computeMetadata/v1/instance/service-accounts/default/token")
-             == 0);
+  GPR_ASSERT(
+      strcmp(request->path,
+             "/computeMetadata/v1/instance/service-accounts/default/token") ==
+      0);
   GPR_ASSERT(request->hdr_count == 1);
   GPR_ASSERT(strcmp(request->hdrs[0].key, "Metadata-Flavor") == 0);
   GPR_ASSERT(strcmp(request->hdrs[0].value, "Google") == 0);
@@ -506,16 +531,16 @@
   /* First request: http get should be called. */
   grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_success,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      compute_engine_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
 
   /* Second request: the cached token should be served directly. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_success,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      compute_engine_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
 
   grpc_credentials_unref(compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
@@ -528,9 +553,9 @@
                             httpcli_post_should_not_be_called);
   GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
-  grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_failure,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      compute_engine_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
   grpc_credentials_unref(compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
 }
@@ -553,8 +578,8 @@
   GPR_ASSERT(strcmp(request->path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0);
   GPR_ASSERT(request->hdr_count == 1);
   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
-  GPR_ASSERT(strcmp(request->hdrs[0].value,
-                    "application/x-www-form-urlencoded") == 0);
+  GPR_ASSERT(
+      strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
 }
 
 static int refresh_token_httpcli_post_success(
@@ -587,16 +612,16 @@
   /* First request: http get should be called. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             refresh_token_httpcli_post_success);
-  grpc_credentials_get_request_metadata(refresh_token_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_success,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      refresh_token_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
 
   /* Second request: the cached token should be served directly. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(refresh_token_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_success,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      refresh_token_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
 
   grpc_credentials_unref(refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
@@ -609,9 +634,9 @@
                             refresh_token_httpcli_post_failure);
   GPR_ASSERT(grpc_credentials_has_request_metadata(refresh_token_creds));
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(refresh_token_creds));
-  grpc_credentials_get_request_metadata(refresh_token_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_failure,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      refresh_token_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
   grpc_credentials_unref(refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
 }
@@ -667,8 +692,8 @@
   char *expected_body = NULL;
   GPR_ASSERT(body != NULL);
   GPR_ASSERT(body_size != 0);
-  gpr_asprintf(&expected_body, "%s%s",
-               GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, test_signed_jwt);
+  gpr_asprintf(&expected_body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX,
+               test_signed_jwt);
   GPR_ASSERT(strlen(expected_body) == body_size);
   GPR_ASSERT(memcmp(expected_body, body, body_size) == 0);
   gpr_free(expected_body);
@@ -677,8 +702,8 @@
   GPR_ASSERT(strcmp(request->path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0);
   GPR_ASSERT(request->hdr_count == 1);
   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
-  GPR_ASSERT(strcmp(request->hdrs[0].value,
-                    "application/x-www-form-urlencoded") == 0);
+  GPR_ASSERT(
+      strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
 }
 
 static int service_account_httpcli_post_success(
@@ -714,18 +739,18 @@
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             service_account_httpcli_post_success);
-  grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_success,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      service_account_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
 
   /* Second request: the cached token should be served directly. */
   grpc_jwt_encode_and_sign_set_override(
       encode_and_sign_jwt_should_not_be_called);
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_success,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      service_account_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
 
   gpr_free(json_key_string);
   grpc_credentials_unref(service_account_creds);
@@ -744,9 +769,9 @@
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             service_account_httpcli_post_failure);
-  grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_failure,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      service_account_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
 
   gpr_free(json_key_string);
   grpc_credentials_unref(service_account_creds);
@@ -764,9 +789,9 @@
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
-                                        on_oauth2_creds_get_metadata_failure,
-                                        (void *)test_user_data);
+  grpc_credentials_get_request_metadata(
+      service_account_creds, NULL, test_service_url,
+      on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
 
   gpr_free(json_key_string);
   grpc_credentials_unref(service_account_creds);
@@ -808,21 +833,21 @@
 
   /* First request: jwt_encode_and_sign should be called. */
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
-  grpc_credentials_get_request_metadata(jwt_creds, test_service_url,
+  grpc_credentials_get_request_metadata(jwt_creds, NULL, test_service_url,
                                         on_jwt_creds_get_metadata_success,
                                         (void *)test_user_data);
 
   /* Second request: the cached token should be served directly. */
   grpc_jwt_encode_and_sign_set_override(
       encode_and_sign_jwt_should_not_be_called);
-  grpc_credentials_get_request_metadata(jwt_creds, test_service_url,
+  grpc_credentials_get_request_metadata(jwt_creds, NULL, test_service_url,
                                         on_jwt_creds_get_metadata_success,
                                         (void *)test_user_data);
 
   /* Third request: Different service url so jwt_encode_and_sign should be
      called again (no caching). */
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
-  grpc_credentials_get_request_metadata(jwt_creds, other_test_service_url,
+  grpc_credentials_get_request_metadata(jwt_creds, NULL, other_test_service_url,
                                         on_jwt_creds_get_metadata_success,
                                         (void *)test_user_data);
 
@@ -839,7 +864,7 @@
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds));
 
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
-  grpc_credentials_get_request_metadata(jwt_creds, test_service_url,
+  grpc_credentials_get_request_metadata(jwt_creds, NULL, test_service_url,
                                         on_jwt_creds_get_metadata_failure,
                                         (void *)test_user_data);
 
@@ -848,6 +873,68 @@
   grpc_jwt_encode_and_sign_set_override(NULL);
 }
 
+static void set_google_default_creds_env_var_with_file_contents(
+    const char *file_prefix, const char *contents) {
+  size_t contents_len = strlen(contents);
+  char *creds_file_name;
+  FILE *creds_file = gpr_tmpfile(file_prefix, &creds_file_name);
+  GPR_ASSERT(creds_file_name != NULL);
+  GPR_ASSERT(creds_file != NULL);
+  GPR_ASSERT(fwrite(contents, 1, contents_len, creds_file) == contents_len);
+  fclose(creds_file);
+  gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
+  gpr_free(creds_file_name);
+}
+
+static grpc_credentials *composite_inner_creds(grpc_credentials *creds,
+                                               const char *inner_creds_type) {
+  size_t i;
+  grpc_composite_credentials *composite;
+  GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
+  composite = (grpc_composite_credentials *)creds;
+  for (i = 0; i < composite->inner.num_creds; i++) {
+    grpc_credentials *c = composite->inner.creds_array[i];
+    if (strcmp(c->type, inner_creds_type) == 0) return c;
+  }
+  GPR_ASSERT(0); /* Not found. */
+}
+
+static void test_google_default_creds_auth_key(void) {
+  grpc_jwt_credentials *jwt;
+  grpc_credentials *creds;
+  char *json_key = test_json_key_str();
+  grpc_flush_cached_google_default_credentials();
+  set_google_default_creds_env_var_with_file_contents(
+      "json_key_google_default_creds", json_key);
+  gpr_free(json_key);
+  creds = grpc_google_default_credentials_create();
+  GPR_ASSERT(creds != NULL);
+  jwt = (grpc_jwt_credentials *)composite_inner_creds(
+      creds, GRPC_CREDENTIALS_TYPE_JWT);
+  GPR_ASSERT(
+      strcmp(jwt->key.client_id,
+             "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
+      0);
+  grpc_credentials_unref(creds);
+  gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+}
+
+static void test_google_default_creds_access_token(void) {
+  grpc_refresh_token_credentials *refresh;
+  grpc_credentials *creds;
+  grpc_flush_cached_google_default_credentials();
+  set_google_default_creds_env_var_with_file_contents(
+      "refresh_token_google_default_creds", test_refresh_token_str);
+  creds = grpc_google_default_credentials_create();
+  GPR_ASSERT(creds != NULL);
+  refresh = (grpc_refresh_token_credentials *)composite_inner_creds(
+      creds, GRPC_CREDENTIALS_TYPE_OAUTH2);
+  GPR_ASSERT(strcmp(refresh->refresh_token.client_id,
+                    "32555999999.apps.googleusercontent.com") == 0);
+  grpc_credentials_unref(creds);
+  gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_empty_md_store();
@@ -864,6 +951,7 @@
   test_oauth2_token_fetcher_creds_parsing_missing_token_type();
   test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime();
   test_iam_creds();
+  test_access_token_creds();
   test_ssl_oauth2_composite_creds();
   test_ssl_oauth2_iam_composite_creds();
   test_compute_engine_creds_success();
@@ -875,5 +963,7 @@
   test_service_account_creds_signing_failure();
   test_jwt_creds_success();
   test_jwt_creds_signing_failure();
+  test_google_default_creds_auth_key();
+  test_google_default_creds_access_token();
   return 0;
 }
diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c
index 3202df3..64c4dde 100644
--- a/test/core/security/fetch_oauth2.c
+++ b/test/core/security/fetch_oauth2.c
@@ -44,36 +44,7 @@
 
 #include "src/core/security/credentials.h"
 #include "src/core/support/file.h"
-
-typedef struct {
-  gpr_cv cv;
-  gpr_mu mu;
-  int is_done;
-} synchronizer;
-
-static void on_oauth2_response(void *user_data,
-                               grpc_credentials_md *md_elems,
-                               size_t num_md, grpc_credentials_status status) {
-  synchronizer *sync = user_data;
-  char *token;
-  gpr_slice token_slice;
-  if (status == GRPC_CREDENTIALS_ERROR) {
-    gpr_log(GPR_ERROR, "Fetching token failed.");
-  } else {
-    GPR_ASSERT(num_md == 1);
-    token_slice = md_elems[0].value;
-    token = gpr_malloc(GPR_SLICE_LENGTH(token_slice) + 1);
-    memcpy(token, GPR_SLICE_START_PTR(token_slice),
-           GPR_SLICE_LENGTH(token_slice));
-    token[GPR_SLICE_LENGTH(token_slice)] = '\0';
-    printf("Got token: %s.\n", token);
-    gpr_free(token);
-  }
-  gpr_mu_lock(&sync->mu);
-  sync->is_done = 1;
-  gpr_mu_unlock(&sync->mu);
-  gpr_cv_signal(&sync->cv);
-}
+#include "test/core/security/oauth2_utils.h"
 
 static grpc_credentials *create_service_account_creds(
     const char *json_key_file_path, const char *scope) {
@@ -102,10 +73,10 @@
 }
 
 int main(int argc, char **argv) {
-  synchronizer sync;
   grpc_credentials *creds = NULL;
   char *json_key_file_path = NULL;
   char *json_refresh_token_file_path = NULL;
+  char *token = NULL;
   int use_gce = 0;
   char *scope = NULL;
   gpr_cmdline *cl = gpr_cmdline_create("fetch_oauth2");
@@ -176,18 +147,11 @@
   }
   GPR_ASSERT(creds != NULL);
 
-  gpr_mu_init(&sync.mu);
-  gpr_cv_init(&sync.cv);
-  sync.is_done = 0;
-
-  grpc_credentials_get_request_metadata(creds, "", on_oauth2_response, &sync);
-
-  gpr_mu_lock(&sync.mu);
-  while (!sync.is_done) gpr_cv_wait(&sync.cv, &sync.mu, gpr_inf_future);
-  gpr_mu_unlock(&sync.mu);
-
-  gpr_mu_destroy(&sync.mu);
-  gpr_cv_destroy(&sync.cv);
+  token = grpc_test_fetch_oauth2_token_with_credentials(creds);
+  if (token != NULL) {
+    printf("Got token: %s.\n", token);
+    gpr_free(token);
+  }
   grpc_credentials_release(creds);
   gpr_cmdline_destroy(cl);
   grpc_shutdown();
diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c
index b43e042..da57cef 100644
--- a/test/core/security/json_token_test.c
+++ b/test/core/security/json_token_test.c
@@ -269,8 +269,8 @@
 
 static void check_jwt_claim(grpc_json *claim, const char *expected_audience,
                             const char *expected_scope) {
-  gpr_timespec expiration = {0, 0};
-  gpr_timespec issue_time = {0, 0};
+  gpr_timespec expiration = gpr_time_0(GPR_CLOCK_REALTIME);
+  gpr_timespec issue_time = gpr_time_0(GPR_CLOCK_REALTIME);
   gpr_timespec parsed_lifetime;
   grpc_json *iss = NULL;
   grpc_json *scope = NULL;
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
new file mode 100644
index 0000000..98db56c
--- /dev/null
+++ b/test/core/security/jwt_verifier_test.c
@@ -0,0 +1,565 @@
+/*
+*
+*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/security/jwt_verifier.h"
+
+#include <string.h>
+
+#include "src/core/httpcli/httpcli.h"
+#include "src/core/security/base64.h"
+#include "src/core/security/json_token.h"
+#include "test/core/util/test_config.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/string_util.h>
+
+/* This JSON key was generated with the GCE console and revoked immediately.
+   The identifiers have been changed as well.
+   Maximum size for a string literal is 509 chars in C89, yay!  */
+static const char json_key_str_part1[] =
+    "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
+    "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE"
+    "qg"
+    "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
+    "rWBQvS4hle4LfijkP3J5BG+"
+    "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
+    "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
+    "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
+    "8HpCqFYM9V8f34SBWfD4fRFT+n/"
+    "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
+static const char json_key_str_part2[] =
+    "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
+    "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
+    "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA"
+    "G"
+    "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
+    "A"
+    "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
+    "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
+    "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
+    "Y"
+    "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
+static const char json_key_str_part3_for_google_email_issuer[] =
+    "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
+    "\"client_email\": "
+    "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
+    "com\", \"client_id\": "
+    "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
+    "com\", \"type\": \"service_account\" }";
+/* Trick our JWT library into issuing a JWT with iss=accounts.google.com. */
+static const char json_key_str_part3_for_url_issuer[] =
+    "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
+    "\"client_email\": \"accounts.google.com\", "
+    "\"client_id\": "
+    "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
+    "com\", \"type\": \"service_account\" }";
+static const char json_key_str_part3_for_custom_email_issuer[] =
+    "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
+    "\"client_email\": "
+    "\"foo@bar.com\", \"client_id\": "
+    "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
+    "com\", \"type\": \"service_account\" }";
+
+static grpc_jwt_verifier_email_domain_key_url_mapping custom_mapping = {
+  "bar.com", "keys.bar.com/jwk"
+};
+
+static const char expected_user_data[] = "user data";
+
+static const char good_jwk_set[] =
+    "{"
+    " \"keys\": ["
+    "  {"
+    "   \"kty\": \"RSA\","
+    "   \"alg\": \"RS256\","
+    "   \"use\": \"sig\","
+    "   \"kid\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\","
+    "   \"n\": "
+    "\"4S8myegefIeRdynuYkSqBYaOLDvU19cHKC56RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ6mxP"
+    "QutZC1nKNJ6D-tYFC9LiGV7gt-KOQ_cnkEb4hcMw_xF_OI1FCx6cBcM0-"
+    "RjiQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFU=\","
+    "   \"e\": \"AQAB\""
+    "  }"
+    " ]"
+    "}";
+
+static gpr_timespec expected_lifetime = {3600, 0, GPR_TIMESPAN};
+
+static const char good_google_email_keys_part1[] =
+    "{\"e6b5137873db8d2ef81e06a47289e6434ec8a165\": \"-----BEGIN "
+    "CERTIFICATE-----"
+    "\\nMIICATCCAWoCCQDEywLhxvHjnDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB\\nVTET"
+    "MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\\ncyBQdHkgTHR"
+    "kMB4XDTE1MDYyOTA4Mzk1MFoXDTI1MDYyNjA4Mzk1MFowRTELMAkG\\nA1UEBhMCQVUxEzARBg"
+    "NVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\\nIFdpZGdpdHMgUHR5IEx0ZDCBn"
+    "zANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4S8m\\nyegefIeRdynuYkSqBYaOLDvU19cHKC56"
+    "RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ\\n6mxPQutZC1nKNJ6D+tYFC9LiGV7gt+KOQ/";
+
+static const char good_google_email_keys_part2[] =
+    "cnkEb4hcMw/xF/OI1FCx6cBcM0+"
+    "Rji\\nQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFUCAwEAATANBgkqhkiG9w0BAQsF\\nA"
+    "AOBgQBfu69FkPmBknbKNFgurPz78kbs3VNN+k/"
+    "PUgO5DHKskJmgK2TbtvX2VMpx\\nkftmHGzgzMzUlOtigCaGMgHWjfqjpP9uuDbahXrZBJzB8c"
+    "Oq7MrQF8r17qVvo3Ue\\nPjTKQMAsU8uxTEMmeuz9L6yExs0rfd6bPOrQkAoVfFfiYB3/"
+    "pA==\\n-----END CERTIFICATE-----\\n\"}";
+
+static const char expected_audience[] = "https://foo.com";
+
+static const char good_openid_config[] =
+    "{"
+    " \"issuer\": \"https://accounts.google.com\","
+    " \"authorization_endpoint\": "
+    "\"https://accounts.google.com/o/oauth2/v2/auth\","
+    " \"token_endpoint\": \"https://www.googleapis.com/oauth2/v4/token\","
+    " \"userinfo_endpoint\": \"https://www.googleapis.com/oauth2/v3/userinfo\","
+    " \"revocation_endpoint\": \"https://accounts.google.com/o/oauth2/revoke\","
+    " \"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\""
+    "}";
+
+static const char expired_claims[] =
+    "{ \"aud\": \"https://foo.com\","
+    "  \"iss\": \"blah.foo.com\","
+    "  \"sub\": \"juju@blah.foo.com\","
+    "  \"jti\": \"jwtuniqueid\","
+    "  \"iat\": 100,"  /* Way back in the past... */
+    "  \"exp\": 120,"
+    "  \"nbf\": 60,"
+    "  \"foo\": \"bar\"}";
+
+static const char claims_without_time_constraint[] =
+    "{ \"aud\": \"https://foo.com\","
+    "  \"iss\": \"blah.foo.com\","
+    "  \"sub\": \"juju@blah.foo.com\","
+    "  \"jti\": \"jwtuniqueid\","
+    "  \"foo\": \"bar\"}";
+
+static const char invalid_claims[] =
+    "{ \"aud\": \"https://foo.com\","
+    "  \"iss\": 46," /* Issuer cannot be a number. */
+    "  \"sub\": \"juju@blah.foo.com\","
+    "  \"jti\": \"jwtuniqueid\","
+    "  \"foo\": \"bar\"}";
+
+typedef struct {
+  grpc_jwt_verifier_status expected_status;
+  const char *expected_issuer;
+  const char *expected_subject;
+} verifier_test_config;
+
+static void test_claims_success(void) {
+  grpc_jwt_claims *claims;
+  gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint);
+  grpc_json *json = grpc_json_parse_string_with_len(
+      (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
+  GPR_ASSERT(json != NULL);
+  claims = grpc_jwt_claims_from_json(json, s);
+  GPR_ASSERT(claims != NULL);
+  GPR_ASSERT(grpc_jwt_claims_json(claims) == json);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "juju@blah.foo.com") == 0);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0);
+  GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
+             GRPC_JWT_VERIFIER_OK);
+  grpc_jwt_claims_destroy(claims);
+}
+
+static void test_expired_claims_failure(void) {
+  grpc_jwt_claims *claims;
+  gpr_slice s = gpr_slice_from_copied_string(expired_claims);
+  grpc_json *json = grpc_json_parse_string_with_len(
+      (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
+  gpr_timespec exp_iat = {100, 0, GPR_CLOCK_REALTIME};
+  gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME};
+  gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME};
+  GPR_ASSERT(json != NULL);
+  claims = grpc_jwt_claims_from_json(json, s);
+  GPR_ASSERT(claims != NULL);
+  GPR_ASSERT(grpc_jwt_claims_json(claims) == json);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "juju@blah.foo.com") == 0);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0);
+  GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_issued_at(claims), exp_iat) == 0);
+  GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_expires_at(claims), exp_exp) == 0);
+  GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_not_before(claims), exp_nbf) == 0);
+
+  GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
+             GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE);
+  grpc_jwt_claims_destroy(claims);
+}
+
+static void test_invalid_claims_failure(void) {
+  gpr_slice s = gpr_slice_from_copied_string(invalid_claims);
+  grpc_json *json = grpc_json_parse_string_with_len(
+      (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
+  GPR_ASSERT(grpc_jwt_claims_from_json(json, s) == NULL);
+}
+
+static void test_bad_audience_claims_failure(void) {
+  grpc_jwt_claims *claims;
+  gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint);
+  grpc_json *json = grpc_json_parse_string_with_len(
+      (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
+  GPR_ASSERT(json != NULL);
+  claims = grpc_jwt_claims_from_json(json, s);
+  GPR_ASSERT(claims != NULL);
+  GPR_ASSERT(grpc_jwt_claims_check(claims, "https://bar.com") ==
+             GRPC_JWT_VERIFIER_BAD_AUDIENCE);
+  grpc_jwt_claims_destroy(claims);
+}
+
+static char *json_key_str(const char *last_part) {
+  size_t result_len = strlen(json_key_str_part1) + strlen(json_key_str_part2) +
+                      strlen(last_part);
+  char *result = gpr_malloc(result_len + 1);
+  char *current = result;
+  strcpy(result, json_key_str_part1);
+  current += strlen(json_key_str_part1);
+  strcpy(current, json_key_str_part2);
+  current += strlen(json_key_str_part2);
+  strcpy(current, last_part);
+  return result;
+}
+
+static char *good_google_email_keys(void) {
+  size_t result_len = strlen(good_google_email_keys_part1) +
+                      strlen(good_google_email_keys_part2);
+  char *result = gpr_malloc(result_len + 1);
+  char *current = result;
+  strcpy(result, good_google_email_keys_part1);
+  current += strlen(good_google_email_keys_part1);
+  strcpy(current, good_google_email_keys_part2);
+  return result;
+}
+
+static grpc_httpcli_response http_response(int status, char *body) {
+  grpc_httpcli_response response;
+  memset(&response, 0, sizeof(grpc_httpcli_response));
+  response.status = status;
+  response.body = body;
+  response.body_length = strlen(body);
+  return response;
+}
+
+static int httpcli_post_should_not_be_called(
+    const grpc_httpcli_request *request, const char *body_bytes,
+    size_t body_size, gpr_timespec deadline,
+    grpc_httpcli_response_cb on_response, void *user_data) {
+  GPR_ASSERT("HTTP POST should not be called" == NULL);
+  return 1;
+}
+
+static int httpcli_get_google_keys_for_email(
+    const grpc_httpcli_request *request, gpr_timespec deadline,
+    grpc_httpcli_response_cb on_response, void *user_data) {
+  grpc_httpcli_response response = http_response(200, good_google_email_keys());
+  GPR_ASSERT(request->use_ssl);
+  GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
+  GPR_ASSERT(strcmp(request->path,
+                    "/robot/v1/metadata/x509/"
+                    "777-abaslkan11hlb6nmim3bpspl31ud@developer."
+                    "gserviceaccount.com") == 0);
+  on_response(user_data, &response);
+  gpr_free(response.body);
+  return 1;
+}
+
+static void on_verification_success(void *user_data,
+                                    grpc_jwt_verifier_status status,
+                                    grpc_jwt_claims *claims) {
+  GPR_ASSERT(status == GRPC_JWT_VERIFIER_OK);
+  GPR_ASSERT(claims != NULL);
+  GPR_ASSERT(user_data == (void *)expected_user_data);
+  GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), expected_audience) == 0);
+  grpc_jwt_claims_destroy(claims);
+}
+
+static void test_jwt_verifier_google_email_issuer_success(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
+  char *jwt = NULL;
+  char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
+  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
+  gpr_free(key_str);
+  GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
+  grpc_httpcli_set_override(httpcli_get_google_keys_for_email,
+                            httpcli_post_should_not_be_called);
+  jwt =
+      grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL);
+  grpc_auth_json_key_destruct(&key);
+  GPR_ASSERT(jwt != NULL);
+  grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
+                           on_verification_success, (void *)expected_user_data);
+  gpr_free(jwt);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+static int httpcli_get_custom_keys_for_email(
+    const grpc_httpcli_request *request, gpr_timespec deadline,
+    grpc_httpcli_response_cb on_response, void *user_data) {
+  grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
+  GPR_ASSERT(request->use_ssl);
+  GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0);
+  GPR_ASSERT(strcmp(request->path, "/jwk/foo@bar.com") == 0);
+  on_response(user_data, &response);
+  gpr_free(response.body);
+  return 1;
+}
+
+static void test_jwt_verifier_custom_email_issuer_success(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(&custom_mapping, 1);
+  char *jwt = NULL;
+  char *key_str = json_key_str(json_key_str_part3_for_custom_email_issuer);
+  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
+  gpr_free(key_str);
+  GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
+  grpc_httpcli_set_override(httpcli_get_custom_keys_for_email,
+                            httpcli_post_should_not_be_called);
+  jwt =
+      grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL);
+  grpc_auth_json_key_destruct(&key);
+  GPR_ASSERT(jwt != NULL);
+  grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
+                           on_verification_success, (void *)expected_user_data);
+  gpr_free(jwt);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+static int httpcli_get_jwk_set(
+    const grpc_httpcli_request *request, gpr_timespec deadline,
+    grpc_httpcli_response_cb on_response, void *user_data) {
+  grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
+  GPR_ASSERT(request->use_ssl);
+  GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
+  GPR_ASSERT(strcmp(request->path, "/oauth2/v3/certs") == 0);
+  on_response(user_data, &response);
+  gpr_free(response.body);
+  return 1;
+}
+
+static int httpcli_get_openid_config(const grpc_httpcli_request *request,
+                                     gpr_timespec deadline,
+                                     grpc_httpcli_response_cb on_response,
+                                     void *user_data) {
+  grpc_httpcli_response response =
+      http_response(200, gpr_strdup(good_openid_config));
+  GPR_ASSERT(request->use_ssl);
+  GPR_ASSERT(strcmp(request->host, "accounts.google.com") == 0);
+  GPR_ASSERT(strcmp(request->path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0);
+  grpc_httpcli_set_override(httpcli_get_jwk_set,
+                            httpcli_post_should_not_be_called);
+  on_response(user_data, &response);
+  gpr_free(response.body);
+  return 1;
+}
+
+static void test_jwt_verifier_url_issuer_success(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
+  char *jwt = NULL;
+  char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
+  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
+  gpr_free(key_str);
+  GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
+  grpc_httpcli_set_override(httpcli_get_openid_config,
+                            httpcli_post_should_not_be_called);
+  jwt =
+      grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL);
+  grpc_auth_json_key_destruct(&key);
+  GPR_ASSERT(jwt != NULL);
+  grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
+                           on_verification_success, (void *)expected_user_data);
+  gpr_free(jwt);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void on_verification_key_retrieval_error(void *user_data,
+                                                grpc_jwt_verifier_status status,
+                                                grpc_jwt_claims *claims) {
+  GPR_ASSERT(status == GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR);
+  GPR_ASSERT(claims == NULL);
+  GPR_ASSERT(user_data == (void *)expected_user_data);
+}
+
+static int httpcli_get_bad_json(const grpc_httpcli_request *request,
+                                gpr_timespec deadline,
+                                grpc_httpcli_response_cb on_response,
+                                void *user_data) {
+  grpc_httpcli_response response =
+      http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
+  GPR_ASSERT(request->use_ssl);
+  on_response(user_data, &response);
+  gpr_free(response.body);
+  return 1;
+}
+
+static void test_jwt_verifier_url_issuer_bad_config(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
+  char *jwt = NULL;
+  char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
+  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
+  gpr_free(key_str);
+  GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
+  grpc_httpcli_set_override(httpcli_get_bad_json,
+                            httpcli_post_should_not_be_called);
+  jwt =
+      grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL);
+  grpc_auth_json_key_destruct(&key);
+  GPR_ASSERT(jwt != NULL);
+  grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
+                           on_verification_key_retrieval_error,
+                           (void *)expected_user_data);
+  gpr_free(jwt);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void test_jwt_verifier_bad_json_key(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
+  char *jwt = NULL;
+  char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
+  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
+  gpr_free(key_str);
+  GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
+  grpc_httpcli_set_override(httpcli_get_bad_json,
+                            httpcli_post_should_not_be_called);
+  jwt =
+      grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL);
+  grpc_auth_json_key_destruct(&key);
+  GPR_ASSERT(jwt != NULL);
+  grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
+                           on_verification_key_retrieval_error,
+                           (void *)expected_user_data);
+  gpr_free(jwt);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void corrupt_jwt_sig(char *jwt) {
+  gpr_slice sig;
+  char *bad_b64_sig;
+  gpr_uint8 *sig_bytes;
+  char *last_dot = strrchr(jwt, '.');
+  GPR_ASSERT(last_dot != NULL);
+  sig = grpc_base64_decode(last_dot + 1, 1);
+  GPR_ASSERT(!GPR_SLICE_IS_EMPTY(sig));
+  sig_bytes = GPR_SLICE_START_PTR(sig);
+  (*sig_bytes)++; /* Corrupt first byte. */
+  bad_b64_sig =
+      grpc_base64_encode(GPR_SLICE_START_PTR(sig), GPR_SLICE_LENGTH(sig), 1, 0);
+  memcpy(last_dot + 1, bad_b64_sig, strlen(bad_b64_sig));
+  gpr_free(bad_b64_sig);
+  gpr_slice_unref(sig);
+}
+
+static void on_verification_bad_signature(void *user_data,
+                                          grpc_jwt_verifier_status status,
+                                          grpc_jwt_claims *claims) {
+  GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_SIGNATURE);
+  GPR_ASSERT(claims == NULL);
+  GPR_ASSERT(user_data == (void *)expected_user_data);
+}
+
+static void test_jwt_verifier_bad_signature(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
+  char *jwt = NULL;
+  char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
+  grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
+  gpr_free(key_str);
+  GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
+  grpc_httpcli_set_override(httpcli_get_openid_config,
+                            httpcli_post_should_not_be_called);
+  jwt =
+      grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, NULL);
+  grpc_auth_json_key_destruct(&key);
+  corrupt_jwt_sig(jwt);
+  GPR_ASSERT(jwt != NULL);
+  grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
+                           on_verification_bad_signature,
+                           (void *)expected_user_data);
+  gpr_free(jwt);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+static int httpcli_get_should_not_be_called(
+    const grpc_httpcli_request *request, gpr_timespec deadline,
+    grpc_httpcli_response_cb on_response, void *user_data) {
+  GPR_ASSERT(0);
+  return 1;
+}
+
+static void on_verification_bad_format(void *user_data,
+                                       grpc_jwt_verifier_status status,
+                                       grpc_jwt_claims *claims) {
+  GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_FORMAT);
+  GPR_ASSERT(claims == NULL);
+  GPR_ASSERT(user_data == (void *)expected_user_data);
+}
+
+static void test_jwt_verifier_bad_format(void) {
+  grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
+  grpc_httpcli_set_override(httpcli_get_should_not_be_called,
+                            httpcli_post_should_not_be_called);
+  grpc_jwt_verifier_verify(verifier, NULL, "bad jwt", expected_audience,
+                           on_verification_bad_format,
+                           (void *)expected_user_data);
+  grpc_jwt_verifier_destroy(verifier);
+  grpc_httpcli_set_override(NULL, NULL);
+}
+
+/* find verification key: bad jks, cannot find key in jks */
+/* bad signature custom provided email*/
+/* bad key */
+
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_claims_success();
+  test_expired_claims_failure();
+  test_invalid_claims_failure();
+  test_bad_audience_claims_failure();
+  test_jwt_verifier_google_email_issuer_success();
+  test_jwt_verifier_custom_email_issuer_success();
+  test_jwt_verifier_url_issuer_success();
+  test_jwt_verifier_url_issuer_bad_config();
+  test_jwt_verifier_bad_json_key();
+  test_jwt_verifier_bad_signature();
+  test_jwt_verifier_bad_format();
+  return 0;
+}
+
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
new file mode 100644
index 0000000..ecd04fd
--- /dev/null
+++ b/test/core/security/oauth2_utils.c
@@ -0,0 +1,93 @@
+/*
+ *
+ * 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/security/oauth2_utils.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/security/credentials.h"
+
+typedef struct {
+  grpc_pollset pollset;
+  int is_done;
+  char *token;
+} oauth2_request;
+
+static void on_oauth2_response(void *user_data, grpc_credentials_md *md_elems,
+                               size_t num_md, grpc_credentials_status status) {
+  oauth2_request *request = user_data;
+  char *token = NULL;
+  gpr_slice token_slice;
+  if (status == GRPC_CREDENTIALS_ERROR) {
+    gpr_log(GPR_ERROR, "Fetching token failed.");
+  } else {
+    GPR_ASSERT(num_md == 1);
+    token_slice = md_elems[0].value;
+    token = gpr_malloc(GPR_SLICE_LENGTH(token_slice) + 1);
+    memcpy(token, GPR_SLICE_START_PTR(token_slice),
+           GPR_SLICE_LENGTH(token_slice));
+    token[GPR_SLICE_LENGTH(token_slice)] = '\0';
+  }
+  gpr_mu_lock(GRPC_POLLSET_MU(&request->pollset));
+  request->is_done = 1;
+  request->token = token;
+  grpc_pollset_kick(&request->pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&request->pollset));
+}
+
+static void do_nothing(void *unused) {}
+
+char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds) {
+  oauth2_request request;
+  grpc_pollset_init(&request.pollset);
+  request.is_done = 0;
+
+  grpc_credentials_get_request_metadata(creds, &request.pollset, "",
+                                        on_oauth2_response, &request);
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&request.pollset));
+  while (!request.is_done)
+    grpc_pollset_work(&request.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
+  gpr_mu_unlock(GRPC_POLLSET_MU(&request.pollset));
+
+  grpc_pollset_shutdown(&request.pollset, do_nothing, NULL);
+  grpc_pollset_destroy(&request.pollset);
+  return request.token;
+}
diff --git a/src/core/surface/client.h b/test/core/security/oauth2_utils.h
similarity index 75%
copy from src/core/surface/client.h
copy to test/core/security/oauth2_utils.h
index 9db2ccf..8082351 100644
--- a/src/core/surface/client.h
+++ b/test/core/security/oauth2_utils.h
@@ -31,11 +31,21 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
-#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
+#ifndef GRPC_TEST_CORE_SECURITY_OAUTH2_UTILS_H
+#define GRPC_TEST_CORE_SECURITY_OAUTH2_UTILS_H
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/security/credentials.h"
 
-extern const grpc_channel_filter grpc_client_surface_filter;
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
+/* Fetch oauth2 access token with a credentials object. Does not take ownership.
+   Returns NULL on a failure. The caller should call gpr_free on the token. */
+char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_TEST_CORE_SECURITY_OAUTH2_UTILS_H */
diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c
index 051e860..0875cfb 100644
--- a/test/core/security/print_google_default_creds_token.c
+++ b/test/core/security/print_google_default_creds_token.c
@@ -35,6 +35,7 @@
 #include <string.h>
 
 #include "src/core/security/credentials.h"
+#include "src/core/support/string.h"
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
@@ -44,8 +45,7 @@
 #include <grpc/support/sync.h>
 
 typedef struct {
-  gpr_cv cv;
-  gpr_mu mu;
+  grpc_pollset pollset;
   int is_done;
 } synchronizer;
 
@@ -57,14 +57,16 @@
   if (status == GRPC_CREDENTIALS_ERROR) {
     fprintf(stderr, "Fetching token failed.\n");
   } else {
+    char *token;
     GPR_ASSERT(num_md == 1);
-    printf("\nGot token: %s\n\n",
-           (const char *)GPR_SLICE_START_PTR(md_elems[0].value));
+    token = gpr_dump_slice(md_elems[0].value, GPR_DUMP_ASCII);
+    printf("\nGot token: %s\n\n", token);
+    gpr_free(token);
   }
-  gpr_mu_lock(&sync->mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&sync->pollset));
   sync->is_done = 1;
-  gpr_mu_unlock(&sync->mu);
-  gpr_cv_signal(&sync->cv);
+  grpc_pollset_kick(&sync->pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&sync->pollset));
 }
 
 int main(int argc, char **argv) {
@@ -86,18 +88,17 @@
     goto end;
   }
 
-  gpr_mu_init(&sync.mu);
-  gpr_cv_init(&sync.cv);
+  grpc_pollset_init(&sync.pollset);
   sync.is_done = 0;
 
-  grpc_credentials_get_request_metadata(creds, "", on_metadata_response, &sync);
+  grpc_credentials_get_request_metadata(creds, &sync.pollset, service_url,
+                                        on_metadata_response, &sync);
 
-  gpr_mu_lock(&sync.mu);
-  while (!sync.is_done) gpr_cv_wait(&sync.cv, &sync.mu, gpr_inf_future);
-  gpr_mu_unlock(&sync.mu);
+  gpr_mu_lock(GRPC_POLLSET_MU(&sync.pollset));
+  while (!sync.is_done)
+    grpc_pollset_work(&sync.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
+  gpr_mu_unlock(GRPC_POLLSET_MU(&sync.pollset));
 
-  gpr_mu_destroy(&sync.mu);
-  gpr_cv_destroy(&sync.cv);
   grpc_credentials_release(creds);
 
 end:
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 30b2362..a8368fc 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -44,6 +44,8 @@
 #include "test/core/util/test_config.h"
 #include "src/core/tsi/fake_transport_security.h"
 
+static grpc_pollset g_pollset;
+
 static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair(
     size_t slice_size, gpr_slice *leftover_slices, size_t leftover_nslices) {
   tsi_frame_protector *fake_read_protector = tsi_create_fake_protector(NULL);
@@ -52,6 +54,8 @@
   grpc_endpoint_pair tcp;
 
   tcp = grpc_iomgr_create_endpoint_pair("fixture", slice_size);
+  grpc_endpoint_add_to_pollset(tcp.client, &g_pollset);
+  grpc_endpoint_add_to_pollset(tcp.server, &g_pollset);
 
   if (leftover_nslices == 0) {
     f.client_ep =
@@ -190,13 +194,17 @@
   clean_up();
 }
 
+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_endpoint_tests(configs[0]);
+  grpc_pollset_init(&g_pollset);
+  grpc_endpoint_tests(configs[0], &g_pollset);
   test_leftover(configs[1], 1);
   test_destroy_ep_early(configs[1], 1);
+  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
   grpc_iomgr_shutdown();
 
   return 0;
diff --git a/test/core/security/security_connector_test.c b/test/core/security/security_connector_test.c
new file mode 100644
index 0000000..b37fd72
--- /dev/null
+++ b/test/core/security/security_connector_test.c
@@ -0,0 +1,256 @@
+/*
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "src/core/security/security_connector.h"
+#include "src/core/security/security_context.h"
+#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/tsi/transport_security.h"
+#include "test/core/util/test_config.h"
+
+#include <grpc/grpc_security.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+static int check_transport_security_type(const grpc_auth_context *ctx) {
+  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
+      ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
+  const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
+  if (prop == NULL) return 0;
+  if (strncmp(prop->value, GRPC_SSL_TRANSPORT_SECURITY_TYPE,
+              prop->value_length) != 0) {
+    return 0;
+  }
+  /* Check that we have only one property with this name. */
+  if (grpc_auth_property_iterator_next(&it) != NULL) return 0;
+  return 1;
+}
+
+static void test_unauthenticated_ssl_peer(void) {
+  tsi_peer peer;
+  grpc_auth_context *ctx;
+  GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  ctx = tsi_ssl_peer_to_auth_context(&peer);
+  GPR_ASSERT(ctx != NULL);
+  GPR_ASSERT(!grpc_auth_context_peer_is_authenticated(ctx));
+  GPR_ASSERT(check_transport_security_type(ctx));
+
+  tsi_peer_destruct(&peer);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
+}
+
+static int check_identity(const grpc_auth_context *ctx,
+                         const char *expected_property_name,
+                         const char **expected_identities,
+                         size_t num_identities) {
+  grpc_auth_property_iterator it;
+  const grpc_auth_property *prop;
+  size_t i;
+  GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
+  it = grpc_auth_context_peer_identity(ctx);
+  for (i = 0; i < num_identities; i++) {
+    prop = grpc_auth_property_iterator_next(&it);
+    if (prop == NULL) {
+      gpr_log(GPR_ERROR, "Expected identity value %s not found.",
+              expected_identities[i]);
+      return 0;
+    }
+    if (strcmp(prop->name, expected_property_name) != 0) {
+      gpr_log(GPR_ERROR, "Expected peer identity property name %s and got %s.",
+              expected_property_name, prop->name);
+      return 0;
+    }
+    if (strncmp(prop->value, expected_identities[i], prop->value_length) != 0) {
+      gpr_log(GPR_ERROR, "Expected peer identity %s and got %s.",
+              expected_identities[i], prop->value);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static int check_x509_cn(const grpc_auth_context *ctx,
+                         const char *expected_cn) {
+  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
+      ctx, GRPC_X509_CN_PROPERTY_NAME);
+  const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
+  if (prop == NULL) {
+    gpr_log(GPR_ERROR, "CN property not found.");
+    return 0;
+  }
+  if (strncmp(prop->value, expected_cn, prop->value_length) != 0) {
+    gpr_log(GPR_ERROR, "Expected CN %s and got %s", expected_cn, prop->value);
+    return 0;
+  }
+  if (grpc_auth_property_iterator_next(&it) != NULL) {
+    gpr_log(GPR_ERROR, "Expected only one property for CN.");
+    return 0;
+  }
+  return 1;
+}
+
+static void test_cn_only_ssl_peer_to_auth_context(void) {
+  tsi_peer peer;
+  grpc_auth_context *ctx;
+  const char *expected_cn = "cn1";
+  GPR_ASSERT(tsi_construct_peer(2, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
+                 &peer.properties[1]) == TSI_OK);
+  ctx = tsi_ssl_peer_to_auth_context(&peer);
+  GPR_ASSERT(ctx != NULL);
+  GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
+  GPR_ASSERT(check_identity(ctx, GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1));
+  GPR_ASSERT(check_transport_security_type(ctx));
+  GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+
+  tsi_peer_destruct(&peer);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
+}
+
+static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
+  tsi_peer peer;
+  grpc_auth_context *ctx;
+  const char *expected_cn = "cn1";
+  const char *expected_san = "san1";
+  GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
+                 &peer.properties[1]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_san,
+                 &peer.properties[2]) == TSI_OK);
+  ctx = tsi_ssl_peer_to_auth_context(&peer);
+  GPR_ASSERT(ctx != NULL);
+  GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
+  GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1));
+  GPR_ASSERT(check_transport_security_type(ctx));
+  GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+
+  tsi_peer_destruct(&peer);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
+}
+
+static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
+  tsi_peer peer;
+  grpc_auth_context *ctx;
+  const char *expected_cn = "cn1";
+  const char *expected_sans[] = {"san1", "san2", "san3"};
+  size_t i;
+  GPR_ASSERT(tsi_construct_peer(2 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
+             TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
+                 &peer.properties[1]) == TSI_OK);
+  for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
+                   expected_sans[i], &peer.properties[2 + i]) == TSI_OK);
+  }
+  ctx = tsi_ssl_peer_to_auth_context(&peer);
+  GPR_ASSERT(ctx != NULL);
+  GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
+  GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, expected_sans,
+                            GPR_ARRAY_SIZE(expected_sans)));
+  GPR_ASSERT(check_transport_security_type(ctx));
+  GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+
+  tsi_peer_destruct(&peer);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
+}
+
+static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
+    void) {
+  tsi_peer peer;
+  grpc_auth_context *ctx;
+  const char *expected_cn = "cn1";
+  const char *expected_sans[] = {"san1", "san2", "san3"};
+  size_t i;
+  GPR_ASSERT(tsi_construct_peer(4 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
+             TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 "foo", "bar", &peer.properties[1]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
+                 &peer.properties[2]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 "chapi", "chapo", &peer.properties[3]) == TSI_OK);
+  for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
+                   expected_sans[i], &peer.properties[4 + i]) == TSI_OK);
+  }
+  ctx = tsi_ssl_peer_to_auth_context(&peer);
+  GPR_ASSERT(ctx != NULL);
+  GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
+  GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, expected_sans,
+                            GPR_ARRAY_SIZE(expected_sans)));
+  GPR_ASSERT(check_transport_security_type(ctx));
+  GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+
+  tsi_peer_destruct(&peer);
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  test_unauthenticated_ssl_peer();
+  test_cn_only_ssl_peer_to_auth_context();
+  test_cn_and_one_san_ssl_peer_to_auth_context();
+  test_cn_and_multiple_sans_ssl_peer_to_auth_context();
+  test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
+
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c
new file mode 100644
index 0000000..cb073f1
--- /dev/null
+++ b/test/core/security/verify_jwt.c
@@ -0,0 +1,120 @@
+/*
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "src/core/security/jwt_verifier.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/cmdline.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/sync.h>
+
+typedef struct {
+  grpc_pollset pollset;
+  int is_done;
+  int success;
+} synchronizer;
+
+static void print_usage_and_exit(gpr_cmdline *cl, const char *argv0) {
+  char *usage = gpr_cmdline_usage_string(cl, argv0);
+  fprintf(stderr, "%s", usage);
+  gpr_free(usage);
+  gpr_cmdline_destroy(cl);
+  exit(1);
+}
+
+static void on_jwt_verification_done(void *user_data,
+                                     grpc_jwt_verifier_status status,
+                                     grpc_jwt_claims *claims) {
+  synchronizer *sync = user_data;
+
+  sync->success = (status == GRPC_JWT_VERIFIER_OK);
+  if (sync->success) {
+    char *claims_str;
+    GPR_ASSERT(claims != NULL);
+    claims_str =
+        grpc_json_dump_to_string((grpc_json *)grpc_jwt_claims_json(claims), 2);
+    printf("Claims: \n\n%s\n", claims_str);
+    gpr_free(claims_str);
+    grpc_jwt_claims_destroy(claims);
+  } else {
+    GPR_ASSERT(claims == NULL);
+    fprintf(stderr, "Verification failed with error %s\n",
+            grpc_jwt_verifier_status_to_string(status));
+  }
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&sync->pollset));
+  sync->is_done = 1;
+  grpc_pollset_kick(&sync->pollset);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&sync->pollset));
+}
+
+int main(int argc, char **argv) {
+  synchronizer sync;
+  grpc_jwt_verifier *verifier;
+  gpr_cmdline *cl;
+  char *jwt = NULL;
+  char *aud = NULL;
+
+  cl = gpr_cmdline_create("JWT verifier tool");
+  gpr_cmdline_add_string(cl, "jwt", "JSON web token to verify", &jwt);
+  gpr_cmdline_add_string(cl, "aud", "Audience for the JWT", &aud);
+  gpr_cmdline_parse(cl, argc, argv);
+  if (jwt == NULL || aud == NULL) {
+    print_usage_and_exit(cl, argv[0]);
+  }
+
+  verifier = grpc_jwt_verifier_create(NULL, 0);
+
+  grpc_init();
+
+  grpc_pollset_init(&sync.pollset);
+  sync.is_done = 0;
+
+  grpc_jwt_verifier_verify(verifier, &sync.pollset, jwt, aud,
+                           on_jwt_verification_done, &sync);
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&sync.pollset));
+  while (!sync.is_done)
+    grpc_pollset_work(&sync.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
+  gpr_mu_unlock(GRPC_POLLSET_MU(&sync.pollset));
+
+  grpc_jwt_verifier_destroy(verifier);
+  gpr_cmdline_destroy(cl);
+  return !sync.success;
+}
+
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index 241ec1c..3292f8a 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -237,7 +237,8 @@
   gpr_timespec interval;
   int counter = 0;
   printf("   Reader starting\n");
-  interval = gpr_time_from_micros(args->read_iteration_interval_in_msec * 1000);
+  interval = gpr_time_from_micros(args->read_iteration_interval_in_msec * 1000,
+                                  GPR_TIMESPAN);
   gpr_mu_lock(args->mu);
   while (!args->stop_flag && records_read < args->total_records) {
     gpr_cv_wait(&args->stop, args->mu, interval);
@@ -310,7 +311,7 @@
   /* Wait for writers to finish. */
   gpr_mu_lock(&writers_mu);
   while (writers_count != 0) {
-    gpr_cv_wait(&writers_done, &writers_mu, gpr_inf_future);
+    gpr_cv_wait(&writers_done, &writers_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&writers_mu);
   gpr_mu_destroy(&writers_mu);
@@ -323,7 +324,7 @@
   }
   /* wait for reader to finish */
   while (reader.running) {
-    gpr_cv_wait(&reader_done, &reader_mu, gpr_inf_future);
+    gpr_cv_wait(&reader_done, &reader_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   if (circular_log) {
     /* Assert that there were no out-of-space errors. */
@@ -568,7 +569,7 @@
     double write_time_micro = 0.0;
     int nrecords = 0;
     setup_test(0);
-    start_time = gpr_now();
+    start_time = gpr_now(GPR_CLOCK_REALTIME);
     while (1) {
       void* record = census_log_start_write(write_size);
       if (record == NULL) {
@@ -577,7 +578,7 @@
       census_log_end_write(record, write_size);
       nrecords++;
     }
-    write_time = gpr_time_sub(gpr_now(), start_time);
+    write_time = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start_time);
     write_time_micro = write_time.tv_sec * 1000000 + write_time.tv_nsec / 1000;
     census_log_shutdown();
     printf(
diff --git a/test/core/statistics/multiple_writers_circular_buffer_test.c b/test/core/statistics/multiple_writers_circular_buffer_test.c
index a645e15..56ada89 100644
--- a/test/core/statistics/multiple_writers_circular_buffer_test.c
+++ b/test/core/statistics/multiple_writers_circular_buffer_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_multiple_writers_circular_log();
   return 0;
 }
diff --git a/test/core/statistics/multiple_writers_test.c b/test/core/statistics/multiple_writers_test.c
index 84aef15..e524927 100644
--- a/test/core/statistics/multiple_writers_test.c
+++ b/test/core/statistics/multiple_writers_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_multiple_writers();
   return 0;
 }
diff --git a/test/core/statistics/performance_test.c b/test/core/statistics/performance_test.c
index 3c1e282..3f0e080 100644
--- a/test/core/statistics/performance_test.c
+++ b/test/core/statistics/performance_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_performance();
   return 0;
 }
diff --git a/test/core/statistics/quick_test.c b/test/core/statistics/quick_test.c
index 0e43231..c72ae77 100644
--- a/test/core/statistics/quick_test.c
+++ b/test/core/statistics/quick_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_invalid_record_size();
   test_end_write_with_different_size();
   test_read_pending_record();
diff --git a/test/core/statistics/small_log_test.c b/test/core/statistics/small_log_test.c
index c151b77..b26b95f 100644
--- a/test/core/statistics/small_log_test.c
+++ b/test/core/statistics/small_log_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_small_log();
   return 0;
 }
diff --git a/test/core/statistics/trace_test.c b/test/core/statistics/trace_test.c
index b13fd03..187884d 100644
--- a/test/core/statistics/trace_test.c
+++ b/test/core/statistics/trace_test.c
@@ -136,7 +136,7 @@
   gpr_mu_lock(&arg.mu);
   while (arg.num_done < NUM_THREADS) {
     gpr_log(GPR_INFO, "num done %d", arg.num_done);
-    gpr_cv_wait(&arg.done, &arg.mu, gpr_inf_future);
+    gpr_cv_wait(&arg.done, &arg.mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&arg.mu);
   census_tracing_shutdown();
diff --git a/test/core/statistics/window_stats_test.c b/test/core/statistics/window_stats_test.c
index d893f7f..9e637cc 100644
--- a/test/core/statistics/window_stats_test.c
+++ b/test/core/statistics/window_stats_test.c
@@ -83,7 +83,7 @@
   result.statistic = &sum;
   census_window_stats_get_sums(stats, zero, &result);
   GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
-  census_window_stats_get_sums(stats, gpr_now(), &result);
+  census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), &result);
   GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
   census_window_stats_destroy(stats);
 }
@@ -268,7 +268,7 @@
   struct census_window_stats* stats =
       census_window_stats_create(1, &kMinInterval, 7, &kMyStatInfo);
   GPR_ASSERT(stats != NULL);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   for (i = 0; i < 100000; i++) {
     increment.tv_nsec = rand() % 100000000; /* up to 1/10th second */
     when = gpr_time_add(when, increment);
@@ -290,9 +290,9 @@
   int i;
   const int count = 100000;
   gpr_timespec increment = {0, 0};
-  struct census_window_stats* stats =
-      census_window_stats_create(1, &gpr_inf_future, 10, &kMyStatInfo);
-  srand(gpr_now().tv_nsec);
+  struct census_window_stats* stats = census_window_stats_create(
+      1, &gpr_inf_future(GPR_CLOCK_REALTIME), 10, &kMyStatInfo);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   for (i = 0; i < count; i++) {
     increment.tv_sec = rand() % 21600; /* 6 hours */
     when = gpr_time_add(when, increment);
diff --git a/test/core/support/cancellable_test.c b/test/core/support/cancellable_test.c
index b2db1af..9b321d3 100644
--- a/test/core/support/cancellable_test.c
+++ b/test/core/support/cancellable_test.c
@@ -55,7 +55,8 @@
 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, &t->cancel)) {
+  while (!gpr_cv_cancellable_wait(
+      &t->cv, &t->mu, gpr_inf_future(GPR_CLOCK_REALTIME), &t->cancel)) {
   }
   t->n--;
   if (t->n == 0) {
@@ -81,24 +82,30 @@
   GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
 
   /* Test timeout on event wait for uncancelled gpr_cancellable */
-  interval = gpr_now();
+  interval = gpr_now(GPR_CLOCK_REALTIME);
   gpr_event_cancellable_wait(
-      &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
-  interval = gpr_time_sub(gpr_now(), interval);
-  GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
+      &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();
+  interval = gpr_now(GPR_CLOCK_REALTIME);
   while (!gpr_cv_cancellable_wait(
-             &t.cv, &t.mu,
-             gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
-             &t.cancel)) {
+      &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(), interval);
-  GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
+  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
@@ -113,7 +120,8 @@
   /* 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_time_from_micros(1000000)));
+              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);
 
@@ -124,27 +132,31 @@
   GPR_ASSERT(gpr_cancellable_is_cancelled(&t.cancel));
 
   /* Wait for threads to finish. */
-  gpr_event_wait(&t.done, gpr_inf_future);
+  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();
+  interval = gpr_now(GPR_CLOCK_REALTIME);
   while (!gpr_cv_cancellable_wait(
-             &t.cv, &t.mu,
-             gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
-             &t.cancel)) {
+      &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(), interval);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
+  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();
+  interval = gpr_now(GPR_CLOCK_REALTIME);
   gpr_event_cancellable_wait(
-      &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
-  interval = gpr_time_sub(gpr_now(), interval);
-  GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
+      &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);
diff --git a/test/core/support/slice_test.c b/test/core/support/slice_test.c
index 63dedea..3ca8742 100644
--- a/test/core/support/slice_test.c
+++ b/test/core/support/slice_test.c
@@ -35,6 +35,7 @@
 
 #include <string.h>
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/support/stack_lockfree_test.c b/test/core/support/stack_lockfree_test.c
new file mode 100644
index 0000000..02ec315
--- /dev/null
+++ b/test/core/support/stack_lockfree_test.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * 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/support/stack_lockfree.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include "test/core/util/test_config.h"
+
+/* max stack size supported */
+#define MAX_STACK_SIZE 65534
+
+#define MAX_THREADS 32
+
+static void test_serial_sized(int size) {
+  gpr_stack_lockfree *stack = gpr_stack_lockfree_create(size);
+  int i;
+
+  /* First try popping empty */
+  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
+
+  /* Now add one item and check it */
+  gpr_stack_lockfree_push(stack, 3);
+  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == 3);
+  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
+
+  /* Now add repeatedly more items and check them */
+  for (i = 1; i < size; i *= 2) {
+    int j;
+    for (j = 0; j <= i; j++) {
+      GPR_ASSERT(gpr_stack_lockfree_push(stack, j) == (j == 0));
+    }
+    for (j = 0; j <= i; j++) {
+      GPR_ASSERT(gpr_stack_lockfree_pop(stack) == i - j);
+    }
+    GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
+  }
+
+  gpr_stack_lockfree_destroy(stack);
+}
+
+static void test_serial() {
+  int i;
+  for (i = 128; i < MAX_STACK_SIZE; i *= 2) {
+    test_serial_sized(i);
+  }
+  test_serial_sized(MAX_STACK_SIZE);
+}
+
+struct test_arg {
+  gpr_stack_lockfree *stack;
+  int stack_size;
+  int nthreads;
+  int rank;
+  int sum;
+};
+
+static void test_mt_body(void *v) {
+  struct test_arg *arg = (struct test_arg *)v;
+  int lo, hi;
+  int i;
+  int res;
+  lo = arg->rank * arg->stack_size / arg->nthreads;
+  hi = (arg->rank + 1) * arg->stack_size / arg->nthreads;
+  for (i = lo; i < hi; i++) {
+    gpr_stack_lockfree_push(arg->stack, i);
+    if ((res = gpr_stack_lockfree_pop(arg->stack)) != -1) {
+      arg->sum += res;
+    }
+  }
+  while ((res = gpr_stack_lockfree_pop(arg->stack)) != -1) {
+    arg->sum += res;
+  }
+}
+
+static void test_mt_sized(int size, int nth) {
+  gpr_stack_lockfree *stack;
+  struct test_arg args[MAX_THREADS];
+  gpr_thd_id thds[MAX_THREADS];
+  int sum;
+  int i;
+  gpr_thd_options options = gpr_thd_options_default();
+
+  stack = gpr_stack_lockfree_create(size);
+  for (i = 0; i < nth; i++) {
+    args[i].stack = stack;
+    args[i].stack_size = size;
+    args[i].nthreads = nth;
+    args[i].rank = i;
+    args[i].sum = 0;
+  }
+  gpr_thd_options_set_joinable(&options);
+  for (i = 0; i < nth; i++) {
+    GPR_ASSERT(gpr_thd_new(&thds[i], test_mt_body, &args[i], &options));
+  }
+  sum = 0;
+  for (i = 0; i < nth; i++) {
+    gpr_thd_join(thds[i]);
+    sum = sum + args[i].sum;
+  }
+  GPR_ASSERT((unsigned)sum == ((unsigned)size * (size - 1)) / 2);
+  gpr_stack_lockfree_destroy(stack);
+}
+
+static void test_mt() {
+  int size, nth;
+  for (nth = 1; nth < MAX_THREADS; nth++) {
+    for (size = 128; size < MAX_STACK_SIZE; size *= 2) {
+      test_mt_sized(size, nth);
+    }
+    test_mt_sized(MAX_STACK_SIZE, nth);
+  }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_serial();
+  test_mt();
+  return 0;
+}
diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c
index b59082e..9023d07 100644
--- a/test/core/support/string_test.c
+++ b/test/core/support/string_test.c
@@ -58,21 +58,49 @@
   GPR_ASSERT(NULL == gpr_strdup(NULL));
 }
 
-static void expect_hexdump(const char *buf, size_t len, gpr_uint32 flags,
-                           const char *result) {
-  char *got = gpr_hexdump(buf, len, flags);
+static void expect_dump(const char *buf, size_t len, gpr_uint32 flags,
+                        const char *result) {
+  char *got = gpr_dump(buf, len, flags);
   GPR_ASSERT(0 == strcmp(got, result));
   gpr_free(got);
 }
 
-static void test_hexdump(void) {
-  LOG_TEST_NAME("test_hexdump");
-  expect_hexdump("\x01", 1, 0, "01");
-  expect_hexdump("\x01", 1, GPR_HEXDUMP_PLAINTEXT, "01 '.'");
-  expect_hexdump("\x01\x02", 2, 0, "01 02");
-  expect_hexdump("\x01\x23\x45\x67\x89\xab\xcd\xef", 8, 0,
+static void test_dump(void) {
+  LOG_TEST_NAME("test_dump");
+  expect_dump("\x01", 1, GPR_DUMP_HEX, "01");
+  expect_dump("\x01", 1, GPR_DUMP_HEX | GPR_DUMP_ASCII, "01 '.'");
+  expect_dump("\x01\x02", 2, GPR_DUMP_HEX, "01 02");
+  expect_dump("\x01\x23\x45\x67\x89\xab\xcd\xef", 8, GPR_DUMP_HEX,
                  "01 23 45 67 89 ab cd ef");
-  expect_hexdump("ab", 2, GPR_HEXDUMP_PLAINTEXT, "61 62 'ab'");
+  expect_dump("ab", 2, GPR_DUMP_HEX | GPR_DUMP_ASCII, "61 62 'ab'");
+}
+
+static void expect_slice_dump(gpr_slice slice, gpr_uint32 flags,
+                              const char *result) {
+  char *got = gpr_dump_slice(slice, flags);
+  GPR_ASSERT(0 == strcmp(got, result));
+  gpr_free(got);
+  gpr_slice_unref(slice);
+}
+
+static void test_dump_slice(void) {
+  static const char *text = "HELLO WORLD!";
+  static const char *long_text =
+      "It was a bright cold day in April, and the clocks were striking "
+      "thirteen. Winston Smith, his chin nuzzled into his breast in an effort "
+      "to escape the vile wind, slipped quickly through the glass doors of "
+      "Victory Mansions, though not quickly enough to prevent a swirl of "
+      "gritty dust from entering along with him.";
+
+  LOG_TEST_NAME("test_dump_slice");
+
+  expect_slice_dump(gpr_slice_from_copied_string(text), GPR_DUMP_ASCII, text);
+  expect_slice_dump(gpr_slice_from_copied_string(long_text), GPR_DUMP_ASCII,
+                    long_text);
+  expect_slice_dump(gpr_slice_from_copied_buffer("\x01", 1), GPR_DUMP_HEX,
+                    "01");
+  expect_slice_dump(gpr_slice_from_copied_buffer("\x01", 1),
+                    GPR_DUMP_HEX | GPR_DUMP_ASCII, "01 '.'");
 }
 
 static void test_pu32_fail(const char *s) {
@@ -145,11 +173,128 @@
   }
 }
 
+static void test_strjoin(void) {
+  const char *parts[4] = {"one", "two", "three", "four"};
+  size_t joined_len;
+  char *joined;
+
+  LOG_TEST_NAME("test_strjoin");
+
+  joined = gpr_strjoin(parts, 4, &joined_len);
+  GPR_ASSERT(0 == strcmp("onetwothreefour", joined));
+  gpr_free(joined);
+
+  joined = gpr_strjoin(parts, 0, &joined_len);
+  GPR_ASSERT(0 == strcmp("", joined));
+  gpr_free(joined);
+
+  joined = gpr_strjoin(parts, 1, &joined_len);
+  GPR_ASSERT(0 == strcmp("one", joined));
+  gpr_free(joined);
+}
+
+static void test_strjoin_sep(void) {
+  const char *parts[4] = {"one", "two", "three", "four"};
+  size_t joined_len;
+  char *joined;
+
+  LOG_TEST_NAME("test_strjoin_sep");
+
+  joined = gpr_strjoin_sep(parts, 4, ", ", &joined_len);
+  GPR_ASSERT(0 == strcmp("one, two, three, four", joined));
+  gpr_free(joined);
+
+  /* empty separator */
+  joined = gpr_strjoin_sep(parts, 4, "", &joined_len);
+  GPR_ASSERT(0 == strcmp("onetwothreefour", joined));
+  gpr_free(joined);
+
+  /* degenerated case specifying zero input parts */
+  joined = gpr_strjoin_sep(parts, 0, ", ", &joined_len);
+  GPR_ASSERT(0 == strcmp("", joined));
+  gpr_free(joined);
+
+  /* single part should have no separator */
+  joined = gpr_strjoin_sep(parts, 1, ", ", &joined_len);
+  GPR_ASSERT(0 == strcmp("one", joined));
+  gpr_free(joined);
+}
+
+static void test_strsplit(void) {
+  gpr_slice_buffer* parts;
+  gpr_slice str;
+
+  LOG_TEST_NAME("test_strsplit");
+
+  parts = gpr_malloc(sizeof(gpr_slice_buffer));
+  gpr_slice_buffer_init(parts);
+
+  str = gpr_slice_from_copied_string("one, two, three, four");
+  gpr_slice_split(str, ", ", parts);
+  GPR_ASSERT(4 == parts->count);
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one"));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "two"));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[2], "three"));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[3], "four"));
+  gpr_slice_buffer_reset_and_unref(parts);
+  gpr_slice_unref(str);
+
+  /* separator not present in string */
+  str = gpr_slice_from_copied_string("one two three four");
+  gpr_slice_split(str, ", ", parts);
+  GPR_ASSERT(1 == parts->count);
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "one two three four"));
+  gpr_slice_buffer_reset_and_unref(parts);
+  gpr_slice_unref(str);
+
+  /* separator at the end */
+  str = gpr_slice_from_copied_string("foo,");
+  gpr_slice_split(str, ",", parts);
+  GPR_ASSERT(2 == parts->count);
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], "foo"));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], ""));
+  gpr_slice_buffer_reset_and_unref(parts);
+  gpr_slice_unref(str);
+
+  /* separator at the beginning */
+  str = gpr_slice_from_copied_string(",foo");
+  gpr_slice_split(str, ",", parts);
+  GPR_ASSERT(2 == parts->count);
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], ""));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], "foo"));
+  gpr_slice_buffer_reset_and_unref(parts);
+  gpr_slice_unref(str);
+
+  /* standalone separator */
+  str = gpr_slice_from_copied_string(",");
+  gpr_slice_split(str, ",", parts);
+  GPR_ASSERT(2 == parts->count);
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], ""));
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[1], ""));
+  gpr_slice_buffer_reset_and_unref(parts);
+  gpr_slice_unref(str);
+
+  /* empty input */
+  str = gpr_slice_from_copied_string("");
+  gpr_slice_split(str, ", ", parts);
+  GPR_ASSERT(1 == parts->count);
+  GPR_ASSERT(0 == gpr_slice_str_cmp(parts->slices[0], ""));
+  gpr_slice_buffer_reset_and_unref(parts);
+  gpr_slice_unref(str);
+
+  gpr_slice_buffer_destroy(parts);
+  gpr_free(parts);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_strdup();
-  test_hexdump();
+  test_dump();
+  test_dump_slice();
   test_parse_uint32();
   test_asprintf();
+  test_strjoin();
+  test_strjoin_sep();
+  test_strsplit();
   return 0;
 }
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 44bc6ba..f729eb0 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -81,13 +81,14 @@
 void queue_append(queue *q, int x) {
   gpr_mu_lock(&q->mu);
   /* To wait for a predicate without a deadline, loop on the negation of the
-     predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
+     predicate, and use gpr_cv_wait(..., gpr_inf_future(GPR_CLOCK_REALTIME))
+     inside the loop
      to release the lock, wait, and reacquire on each iteration.  Code that
      makes the condition true should use gpr_cv_broadcast() on the
      corresponding condition variable.  The predicate must be on state
      protected by the lock.  */
   while (q->length == N) {
-    gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
+    gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
     /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
@@ -209,7 +210,7 @@
 static void test_wait(struct test *m) {
   gpr_mu_lock(&m->mu);
   while (m->done != 0) {
-    gpr_cv_wait(&m->done_cv, &m->mu, gpr_inf_future);
+    gpr_cv_wait(&m->done_cv, &m->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&m->mu);
 }
@@ -242,12 +243,12 @@
                  void (*extra)(void *m), int timeout_s) {
   gpr_int64 iterations = 1024;
   struct test *m;
-  gpr_timespec start = gpr_now();
+  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec time_taken;
-  gpr_timespec deadline =
-      gpr_time_add(start, gpr_time_from_micros(timeout_s * 1000000));
+  gpr_timespec deadline = gpr_time_add(
+      start, gpr_time_from_micros(timeout_s * 1000000, GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
-  while (gpr_time_cmp(gpr_now(), deadline) < 0) {
+  while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
     fprintf(stderr, " %ld", (long)iterations);
     m = test_new(10, iterations);
@@ -265,7 +266,7 @@
     }
     test_destroy(m);
   }
-  time_taken = gpr_time_sub(gpr_now(), start);
+  time_taken = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start);
   fprintf(stderr, " done %ld.%09d s\n", (long)time_taken.tv_sec,
           (int)time_taken.tv_nsec);
 }
@@ -306,7 +307,7 @@
   for (i = 0; i != m->iterations; i++) {
     gpr_mu_lock(&m->mu);
     while ((m->counter % m->threads) != id) {
-      gpr_cv_wait(&m->cv, &m->mu, gpr_inf_future);
+      gpr_cv_wait(&m->cv, &m->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
     }
     m->counter++;
     gpr_cv_broadcast(&m->cv);
@@ -323,7 +324,8 @@
   for (i = 0; i != m->iterations; i++) {
     gpr_timespec deadline;
     gpr_mu_lock(&m->mu);
-    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+    deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                            gpr_time_from_micros(1000, GPR_TIMESPAN));
     while (!gpr_cv_wait(&m->cv, &m->mu, deadline)) {
     }
     m->counter++;
@@ -339,7 +341,8 @@
   gpr_int64 i;
   for (i = 0; i != m->iterations; i++) {
     gpr_timespec deadline;
-    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+    deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                            gpr_time_from_micros(1000, GPR_TIMESPAN));
     GPR_ASSERT(gpr_event_wait(&m->event, deadline) == NULL);
     gpr_mu_lock(&m->mu);
     m->counter++;
@@ -377,14 +380,15 @@
   gpr_int64 i;
   int value;
   for (i = 0; i != n; i++) {
-    queue_remove(&m->q, &value, gpr_inf_future);
+    queue_remove(&m->q, &value, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_lock(&m->mu);
   m->counter = n;
   gpr_mu_unlock(&m->mu);
   GPR_ASSERT(
       !queue_remove(&m->q, &value,
-                    gpr_time_add(gpr_now(), gpr_time_from_micros(1000000))));
+                    gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                 gpr_time_from_micros(1000000, GPR_TIMESPAN))));
   mark_thread_done(m);
 }
 
@@ -424,7 +428,8 @@
   struct test *m = v;
   gpr_int64 n = m->iterations * m->threads;
   gpr_int64 i;
-  GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future) == (void *)1);
+  GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future(GPR_CLOCK_REALTIME)) ==
+             (void *)1);
   GPR_ASSERT(gpr_event_get(&m->event) == (void *)1);
   for (i = 1; i != n; i++) {
     GPR_ASSERT(!gpr_unref(&m->refcount));
diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c
index bb3d54a..7232cd9 100644
--- a/test/core/support/thd_test.c
+++ b/test/core/support/thd_test.c
@@ -79,7 +79,7 @@
   }
   gpr_mu_lock(&t.mu);
   while (!t.is_done) {
-    gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future);
+    gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&t.mu);
   GPR_ASSERT(t.n == 0);
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
index c1dce77..594863c 100644
--- a/test/core/support/time_test.c
+++ b/test/core/support/time_test.c
@@ -91,10 +91,10 @@
 static void test_values(void) {
   int i;
 
-  gpr_timespec x = gpr_time_0;
+  gpr_timespec x = gpr_time_0(GPR_CLOCK_REALTIME);
   GPR_ASSERT(x.tv_sec == 0 && x.tv_nsec == 0);
 
-  x = gpr_inf_future;
+  x = gpr_inf_future(GPR_CLOCK_REALTIME);
   fprintf(stderr, "far future ");
   u_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
   fprintf(stderr, "\n");
@@ -103,7 +103,7 @@
   ts_to_s(x, &to_fp, stderr);
   fprintf(stderr, "\n");
 
-  x = gpr_inf_past;
+  x = gpr_inf_past(GPR_CLOCK_REALTIME);
   fprintf(stderr, "far past   ");
   u_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
   fprintf(stderr, "\n");
@@ -113,37 +113,37 @@
   fprintf(stderr, "\n");
 
   for (i = 1; i != 1000 * 1000 * 1000; i *= 10) {
-    x = gpr_time_from_micros(i);
+    x = gpr_time_from_micros(i, GPR_TIMESPAN);
     GPR_ASSERT(x.tv_sec == i / GPR_US_PER_SEC &&
                x.tv_nsec == (i % GPR_US_PER_SEC) * GPR_NS_PER_US);
-    x = gpr_time_from_nanos(i);
+    x = gpr_time_from_nanos(i, GPR_TIMESPAN);
     GPR_ASSERT(x.tv_sec == i / GPR_NS_PER_SEC &&
                x.tv_nsec == (i % GPR_NS_PER_SEC));
-    x = gpr_time_from_millis(i);
+    x = gpr_time_from_millis(i, GPR_TIMESPAN);
     GPR_ASSERT(x.tv_sec == i / GPR_MS_PER_SEC &&
                x.tv_nsec == (i % GPR_MS_PER_SEC) * GPR_NS_PER_MS);
   }
 
   /* Test possible overflow in conversion of -ve values. */
-  x = gpr_time_from_micros(-(LONG_MAX - 999997));
+  x = gpr_time_from_micros(-(LONG_MAX - 999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_nanos(-(LONG_MAX - 999999997));
+  x = gpr_time_from_nanos(-(LONG_MAX - 999999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_millis(-(LONG_MAX - 997));
+  x = gpr_time_from_millis(-(LONG_MAX - 997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
   /* Test general -ve values. */
   for (i = -1; i > -1000 * 1000 * 1000; i *= 7) {
-    x = gpr_time_from_micros(i);
+    x = gpr_time_from_micros(i, GPR_TIMESPAN);
     GPR_ASSERT(x.tv_sec * GPR_US_PER_SEC + x.tv_nsec / GPR_NS_PER_US == i);
-    x = gpr_time_from_nanos(i);
+    x = gpr_time_from_nanos(i, GPR_TIMESPAN);
     GPR_ASSERT(x.tv_sec * GPR_NS_PER_SEC + x.tv_nsec == i);
-    x = gpr_time_from_millis(i);
+    x = gpr_time_from_millis(i, GPR_TIMESPAN);
     GPR_ASSERT(x.tv_sec * GPR_MS_PER_SEC + x.tv_nsec / GPR_NS_PER_MS == i);
   }
 }
@@ -158,17 +158,19 @@
       for (k = 1; k <= 10000000; k *= 10) {
         int sum = i + j;
         int diff = i - j;
-        gpr_timespec it = gpr_time_from_micros(i * k);
-        gpr_timespec jt = gpr_time_from_micros(j * k);
+        gpr_timespec it = gpr_time_from_micros(i * k, GPR_TIMESPAN);
+        gpr_timespec jt = gpr_time_from_micros(j * k, GPR_TIMESPAN);
         gpr_timespec sumt = gpr_time_add(it, jt);
         gpr_timespec difft = gpr_time_sub(it, jt);
-        if (gpr_time_cmp(gpr_time_from_micros(sum * k), sumt) != 0) {
+        if (gpr_time_cmp(gpr_time_from_micros(sum * k, GPR_TIMESPAN), sumt) !=
+            0) {
           fprintf(stderr, "i %d  j %d  sum %d    sumt ", i, j, sum);
           ts_to_s(sumt, &to_fp, stderr);
           fprintf(stderr, "\n");
           GPR_ASSERT(0);
         }
-        if (gpr_time_cmp(gpr_time_from_micros(diff * k), difft) != 0) {
+        if (gpr_time_cmp(gpr_time_from_micros(diff * k, GPR_TIMESPAN), difft) !=
+            0) {
           fprintf(stderr, "i %d  j %d  diff %d    diff ", i, j, diff);
           ts_to_s(sumt, &to_fp, stderr);
           fprintf(stderr, "\n");
@@ -181,66 +183,76 @@
 
 static void test_overflow(void) {
   /* overflow */
-  gpr_timespec x = gpr_time_from_micros(1);
+  gpr_timespec x = gpr_time_from_micros(1, GPR_TIMESPAN);
   do {
     x = gpr_time_add(x, x);
-  } while (gpr_time_cmp(x, gpr_inf_future) < 0);
-  GPR_ASSERT(gpr_time_cmp(x, gpr_inf_future) == 0);
-  x = gpr_time_from_micros(-1);
+  } while (gpr_time_cmp(x, gpr_inf_future(GPR_TIMESPAN)) < 0);
+  GPR_ASSERT(gpr_time_cmp(x, gpr_inf_future(GPR_TIMESPAN)) == 0);
+  x = gpr_time_from_micros(-1, GPR_TIMESPAN);
   do {
     x = gpr_time_add(x, x);
-  } while (gpr_time_cmp(x, gpr_inf_past) > 0);
-  GPR_ASSERT(gpr_time_cmp(x, gpr_inf_past) == 0);
+  } while (gpr_time_cmp(x, gpr_inf_past(GPR_TIMESPAN)) > 0);
+  GPR_ASSERT(gpr_time_cmp(x, gpr_inf_past(GPR_TIMESPAN)) == 0);
 }
 
 static void test_sticky_infinities(void) {
   int i;
   int j;
   int k;
-  static const gpr_timespec *infinity[] = {&gpr_inf_future, &gpr_inf_past};
-  static const gpr_timespec *addend[] = {&gpr_inf_future, &gpr_inf_past,
-                                         &gpr_time_0, NULL};
+  gpr_timespec infinity[2];
+  gpr_timespec addend[3];
+  infinity[0] = gpr_inf_future(GPR_TIMESPAN);
+  infinity[1] = gpr_inf_past(GPR_TIMESPAN);
+  addend[0] = gpr_inf_future(GPR_TIMESPAN);
+  addend[1] = gpr_inf_past(GPR_TIMESPAN);
+  addend[2] = gpr_time_0(GPR_TIMESPAN);
 
   /* Infinities are sticky */
   for (i = 0; i != sizeof(infinity) / sizeof(infinity[0]); i++) {
     for (j = 0; j != sizeof(addend) / sizeof(addend[0]); j++) {
-      if (addend[j] == NULL) {
-        for (k = -200; k <= 200; k++) {
-          gpr_timespec y = gpr_time_from_micros(k * 100000);
-          gpr_timespec x = gpr_time_add(*infinity[i], y);
-          GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
-          x = gpr_time_sub(*infinity[i], y);
-          GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
-        }
-      } else {
-        gpr_timespec x = gpr_time_add(*infinity[i], *addend[j]);
-        GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
-        x = gpr_time_sub(*infinity[i], *addend[j]);
-        GPR_ASSERT(gpr_time_cmp(x, *infinity[i]) == 0);
-      }
+      gpr_timespec x = gpr_time_add(infinity[i], addend[j]);
+      GPR_ASSERT(gpr_time_cmp(x, infinity[i]) == 0);
+      x = gpr_time_sub(infinity[i], addend[j]);
+      GPR_ASSERT(gpr_time_cmp(x, infinity[i]) == 0);
+    }
+    for (k = -200; k <= 200; k++) {
+      gpr_timespec y = gpr_time_from_micros(k * 100000, GPR_TIMESPAN);
+      gpr_timespec x = gpr_time_add(infinity[i], y);
+      GPR_ASSERT(gpr_time_cmp(x, infinity[i]) == 0);
+      x = gpr_time_sub(infinity[i], y);
+      GPR_ASSERT(gpr_time_cmp(x, infinity[i]) == 0);
     }
   }
 }
 
 static void test_similar(void) {
-  GPR_ASSERT(1 == gpr_time_similar(gpr_inf_future, gpr_inf_future, gpr_time_0));
-  GPR_ASSERT(1 == gpr_time_similar(gpr_inf_past, gpr_inf_past, gpr_time_0));
-  GPR_ASSERT(0 == gpr_time_similar(gpr_inf_past, gpr_inf_future, gpr_time_0));
-  GPR_ASSERT(0 == gpr_time_similar(gpr_inf_future, gpr_inf_past, gpr_time_0));
-  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10),
-                                   gpr_time_from_micros(10), gpr_time_0));
-  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10),
-                                   gpr_time_from_micros(15),
-                                   gpr_time_from_micros(10)));
-  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(15),
-                                   gpr_time_from_micros(10),
-                                   gpr_time_from_micros(10)));
-  GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(10),
-                                   gpr_time_from_micros(25),
-                                   gpr_time_from_micros(10)));
-  GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(25),
-                                   gpr_time_from_micros(10),
-                                   gpr_time_from_micros(10)));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_inf_future(GPR_TIMESPAN),
+                                   gpr_inf_future(GPR_TIMESPAN),
+                                   gpr_time_0(GPR_TIMESPAN)));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_inf_past(GPR_TIMESPAN),
+                                   gpr_inf_past(GPR_TIMESPAN),
+                                   gpr_time_0(GPR_TIMESPAN)));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_inf_past(GPR_TIMESPAN),
+                                   gpr_inf_future(GPR_TIMESPAN),
+                                   gpr_time_0(GPR_TIMESPAN)));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_inf_future(GPR_TIMESPAN),
+                                   gpr_inf_past(GPR_TIMESPAN),
+                                   gpr_time_0(GPR_TIMESPAN)));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN),
+                                   gpr_time_0(GPR_TIMESPAN)));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(10, GPR_TIMESPAN),
+                                   gpr_time_from_micros(15, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN)));
+  GPR_ASSERT(1 == gpr_time_similar(gpr_time_from_micros(15, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN)));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(10, GPR_TIMESPAN),
+                                   gpr_time_from_micros(25, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN)));
+  GPR_ASSERT(0 == gpr_time_similar(gpr_time_from_micros(25, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN),
+                                   gpr_time_from_micros(10, GPR_TIMESPAN)));
 }
 
 int main(int argc, char *argv[]) {
diff --git a/test/core/support/useful_test.c b/test/core/support/useful_test.c
index feaf436..cbf4f02 100644
--- a/test/core/support/useful_test.c
+++ b/test/core/support/useful_test.c
@@ -39,6 +39,7 @@
 int main(int argc, char **argv) {
   int four[4];
   int five[5];
+  gpr_uint32 bitset = 0;
   grpc_test_init(argc, argv);
 
   GPR_ASSERT(GPR_MIN(1, 2) == 1);
@@ -55,5 +56,18 @@
   GPR_ASSERT(GPR_ARRAY_SIZE(four) == 4);
   GPR_ASSERT(GPR_ARRAY_SIZE(five) == 5);
 
+  GPR_ASSERT(GPR_BITCOUNT((1u << 31) - 1) == 31);
+  GPR_ASSERT(GPR_BITCOUNT(1u << 3) == 1);
+  GPR_ASSERT(GPR_BITCOUNT(0) == 0);
+
+  GPR_ASSERT(GPR_BITSET(&bitset, 3) == 8);
+  GPR_ASSERT(GPR_BITCOUNT(bitset) == 1);
+  GPR_ASSERT(GPR_BITGET(bitset, 3) == 1);
+  GPR_ASSERT(GPR_BITSET(&bitset, 1) == 10);
+  GPR_ASSERT(GPR_BITCOUNT(bitset) == 2);
+  GPR_ASSERT(GPR_BITCLEAR(&bitset, 3) == 2);
+  GPR_ASSERT(GPR_BITCOUNT(bitset) == 1);
+  GPR_ASSERT(GPR_BITGET(bitset, 3) == 0);
+
   return 0;
 }
diff --git a/test/core/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c
index 87a2cd7..d9c60e4 100644
--- a/test/core/surface/byte_buffer_reader_test.c
+++ b/test/core/surface/byte_buffer_reader_test.c
@@ -127,11 +127,11 @@
 
   input_slice = gpr_slice_malloc(input_size);
   memset(GPR_SLICE_START_PTR(input_slice), 'a', input_size);
-  gpr_slice_buffer_add(&sliceb_in, input_slice);  /* takes ownership */
+  gpr_slice_buffer_add(&sliceb_in, input_slice); /* takes ownership */
   GPR_ASSERT(grpc_msg_compress(algorithm, &sliceb_in, &sliceb_out));
 
-  buffer = grpc_raw_compressed_byte_buffer_create(
-      sliceb_out.slices, sliceb_out.count, algorithm);
+  buffer = grpc_raw_compressed_byte_buffer_create(sliceb_out.slices,
+                                                  sliceb_out.count, algorithm);
   grpc_byte_buffer_reader_init(&reader, buffer);
 
   while (grpc_byte_buffer_reader_next(&reader, &read_slice)) {
@@ -160,6 +160,30 @@
   read_compressed_slice(GRPC_COMPRESS_DEFLATE, INPUT_SIZE);
 }
 
+static void test_byte_buffer_from_reader(void) {
+  gpr_slice slice;
+  grpc_byte_buffer *buffer, *buffer_from_reader;
+  grpc_byte_buffer_reader reader;
+
+  LOG_TEST("test_byte_buffer_from_reader");
+  slice = gpr_slice_malloc(4);
+  memcpy(GPR_SLICE_START_PTR(slice), "test", 4);
+  buffer = grpc_raw_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+  grpc_byte_buffer_reader_init(&reader, buffer);
+
+  buffer_from_reader = grpc_raw_byte_buffer_from_reader(&reader);
+  GPR_ASSERT(buffer->type == buffer_from_reader->type);
+  GPR_ASSERT(buffer_from_reader->data.raw.compression == GRPC_COMPRESS_NONE);
+  GPR_ASSERT(buffer_from_reader->data.raw.slice_buffer.count == 1);
+  GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(
+                        buffer_from_reader->data.raw.slice_buffer.slices[0]),
+                    "test", 4) == 0);
+
+  grpc_byte_buffer_destroy(buffer);
+  grpc_byte_buffer_destroy(buffer_from_reader);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_read_one_slice();
@@ -167,6 +191,7 @@
   test_read_none_compressed_slice();
   test_read_gzip_compressed_slice();
   test_read_deflate_compressed_slice();
+  test_byte_buffer_from_reader();
 
   return 0;
 }
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index 9e7b2ea..0e59ea4 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);
+  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME));
   GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
@@ -69,24 +69,27 @@
   LOG_TEST("test_wait_empty");
 
   cc = grpc_completion_queue_create();
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_now()).type ==
+  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_now(GPR_CLOCK_REALTIME)).type ==
              GRPC_QUEUE_TIMEOUT);
   shutdown_and_destroy(cc);
 }
 
+static void do_nothing_end_completion(void *arg, grpc_cq_completion *c) {}
+
 static void test_cq_end_op(void) {
   grpc_event ev;
   grpc_completion_queue *cc;
+  grpc_cq_completion completion;
   void *tag = create_test_tag();
 
   LOG_TEST("test_cq_end_op");
 
   cc = grpc_completion_queue_create();
 
-  grpc_cq_begin_op(cc, NULL);
-  grpc_cq_end_op(cc, tag, NULL, 1);
+  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);
+  ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME));
   GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
   GPR_ASSERT(ev.tag == tag);
   GPR_ASSERT(ev.success);
@@ -100,7 +103,8 @@
 
   cc = grpc_completion_queue_create();
   grpc_completion_queue_shutdown(cc);
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_inf_past).type == GRPC_QUEUE_SHUTDOWN);
+  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME))
+                 .type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
 
@@ -110,7 +114,8 @@
 
   cc = grpc_completion_queue_create();
   grpc_completion_queue_shutdown(cc);
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_inf_future).type == GRPC_QUEUE_SHUTDOWN);
+  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_inf_future(GPR_CLOCK_REALTIME))
+                 .type == GRPC_QUEUE_SHUTDOWN);
   grpc_completion_queue_destroy(cc);
 }
 
@@ -118,6 +123,7 @@
   grpc_event ev;
   grpc_completion_queue *cc;
   void *tags[128];
+  grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
   unsigned i, j;
 
   LOG_TEST("test_pluck");
@@ -132,23 +138,26 @@
   cc = grpc_completion_queue_create();
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    grpc_cq_begin_op(cc, NULL);
-    grpc_cq_end_op(cc, tags[i], NULL, 1);
+    grpc_cq_begin_op(cc);
+    grpc_cq_end_op(cc, tags[i], 1, do_nothing_end_completion, NULL,
+                   &completions[i]);
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    ev = grpc_completion_queue_pluck(cc, tags[i], gpr_inf_past);
+    ev = grpc_completion_queue_pluck(cc, tags[i],
+                                     gpr_inf_past(GPR_CLOCK_REALTIME));
     GPR_ASSERT(ev.tag == tags[i]);
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    grpc_cq_begin_op(cc, NULL);
-    grpc_cq_end_op(cc, tags[i], NULL, 1);
+    grpc_cq_begin_op(cc);
+    grpc_cq_end_op(cc, tags[i], 1, do_nothing_end_completion, NULL,
+                   &completions[i]);
   }
 
   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_inf_past(GPR_CLOCK_REALTIME));
     GPR_ASSERT(ev.tag == tags[GPR_ARRAY_SIZE(tags) - i - 1]);
   }
 
@@ -169,7 +178,11 @@
 } test_thread_options;
 
 gpr_timespec ten_seconds_time(void) {
-  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
+}
+
+static void free_completion(void *arg, grpc_cq_completion *completion) {
+  gpr_free(completion);
 }
 
 static void producer_thread(void *arg) {
@@ -177,26 +190,27 @@
   int i;
 
   gpr_log(GPR_INFO, "producer %d started", opt->id);
-  gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1);
+  gpr_event_set(&opt->on_started, (void *)(gpr_intptr)1);
   GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
   for (i = 0; i < TEST_THREAD_EVENTS; i++) {
-    grpc_cq_begin_op(opt->cc, NULL);
+    grpc_cq_begin_op(opt->cc);
   }
 
   gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);
-  gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr) 1);
+  gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr)1);
   GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "producer %d phase 2", opt->id);
   for (i = 0; i < TEST_THREAD_EVENTS; i++) {
-    grpc_cq_end_op(opt->cc, (void *)(gpr_intptr)1, NULL, 1);
+    grpc_cq_end_op(opt->cc, (void *)(gpr_intptr)1, 1, free_completion, NULL,
+                   gpr_malloc(sizeof(grpc_cq_completion)));
     opt->events_triggered++;
   }
 
   gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id);
-  gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1);
+  gpr_event_set(&opt->on_finished, (void *)(gpr_intptr)1);
 }
 
 static void consumer_thread(void *arg) {
@@ -204,13 +218,13 @@
   grpc_event ev;
 
   gpr_log(GPR_INFO, "consumer %d started", opt->id);
-  gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1);
+  gpr_event_set(&opt->on_started, (void *)(gpr_intptr)1);
   GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "consumer %d phase 1", opt->id);
 
   gpr_log(GPR_INFO, "consumer %d phase 1 done", opt->id);
-  gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr) 1);
+  gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr)1);
   GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "consumer %d phase 2", opt->id);
@@ -223,7 +237,7 @@
         break;
       case GRPC_QUEUE_SHUTDOWN:
         gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id);
-        gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1);
+        gpr_event_set(&opt->on_finished, (void *)(gpr_intptr)1);
         return;
       case GRPC_QUEUE_TIMEOUT:
         gpr_log(GPR_ERROR, "Invalid timeout received");
@@ -242,10 +256,8 @@
   int total_consumed = 0;
   static int optid = 101;
 
-  gpr_log(GPR_INFO, "%s: %d producers, %d consumers", "test_threading", producers,
-          consumers);
-
-  grpc_completion_queue_dont_poll_test_only(cc);
+  gpr_log(GPR_INFO, "%s: %d producers, %d consumers", "test_threading",
+          producers, consumers);
 
   /* start all threads: they will wait for phase1 */
   for (i = 0; i < producers + consumers; i++) {
@@ -267,7 +279,7 @@
   /* start phase1: producers will pre-declare all operations they will
      complete */
   gpr_log(GPR_INFO, "start phase 1");
-  gpr_event_set(&phase1, (void *)(gpr_intptr) 1);
+  gpr_event_set(&phase1, (void *)(gpr_intptr)1);
 
   gpr_log(GPR_INFO, "wait phase 1");
   for (i = 0; i < producers + consumers; i++) {
@@ -277,7 +289,7 @@
 
   /* start phase2: operations will complete, and consumers will consume them */
   gpr_log(GPR_INFO, "start phase 2");
-  gpr_event_set(&phase2, (void *)(gpr_intptr) 1);
+  gpr_event_set(&phase2, (void *)(gpr_intptr)1);
 
   /* in parallel, we shutdown the completion channel - all events should still
      be consumed */
diff --git a/test/core/transport/chttp2/bin_encoder_test.c b/test/core/transport/chttp2/bin_encoder_test.c
index 983eaf5..1ffd8ed 100644
--- a/test/core/transport/chttp2/bin_encoder_test.c
+++ b/test/core/transport/chttp2/bin_encoder_test.c
@@ -44,10 +44,8 @@
 static void expect_slice_eq(gpr_slice expected, gpr_slice slice, char *debug,
                             int line) {
   if (0 != gpr_slice_cmp(slice, expected)) {
-    char *hs = gpr_hexdump((const char *)GPR_SLICE_START_PTR(slice),
-                           GPR_SLICE_LENGTH(slice), GPR_HEXDUMP_PLAINTEXT);
-    char *he = gpr_hexdump((const char *)GPR_SLICE_START_PTR(expected),
-                           GPR_SLICE_LENGTH(expected), GPR_HEXDUMP_PLAINTEXT);
+    char *hs = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+    char *he = gpr_dump_slice(expected, GPR_DUMP_HEX | GPR_DUMP_ASCII);
     gpr_log(GPR_ERROR, "FAILED:%d: %s\ngot:  %s\nwant: %s", line, debug, hs,
             he);
     gpr_free(hs);
@@ -83,12 +81,9 @@
   gpr_slice expect = grpc_chttp2_huffman_compress(base64);
   gpr_slice got = grpc_chttp2_base64_encode_and_huffman_compress(input);
   if (0 != gpr_slice_cmp(expect, got)) {
-    char *t = gpr_hexdump((const char *)GPR_SLICE_START_PTR(input),
-                          GPR_SLICE_LENGTH(input), GPR_HEXDUMP_PLAINTEXT);
-    char *e = gpr_hexdump((const char *)GPR_SLICE_START_PTR(expect),
-                          GPR_SLICE_LENGTH(expect), GPR_HEXDUMP_PLAINTEXT);
-    char *g = gpr_hexdump((const char *)GPR_SLICE_START_PTR(got),
-                          GPR_SLICE_LENGTH(got), GPR_HEXDUMP_PLAINTEXT);
+    char *t = gpr_dump_slice(input, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+    char *e = gpr_dump_slice(expect, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+    char *g = gpr_dump_slice(got, GPR_DUMP_HEX | GPR_DUMP_ASCII);
     gpr_log(GPR_ERROR, "FAILED:%d:\ntest: %s\ngot:  %s\nwant: %s", t, g, e);
     gpr_free(t);
     gpr_free(e);
diff --git a/test/core/transport/chttp2/hpack_parser_test.c b/test/core/transport/chttp2/hpack_parser_test.c
index 1d6ad2a..3a31337 100644
--- a/test/core/transport/chttp2/hpack_parser_test.c
+++ b/test/core/transport/chttp2/hpack_parser_test.c
@@ -53,7 +53,7 @@
   GPR_ASSERT(evalue);
   GPR_ASSERT(gpr_slice_str_cmp(md->key->slice, ekey) == 0);
   GPR_ASSERT(gpr_slice_str_cmp(md->value->slice, evalue) == 0);
-  grpc_mdelem_unref(md);
+  GRPC_MDELEM_UNREF(md);
 }
 
 static void test_vector(grpc_chttp2_hpack_parser *parser,
diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c
index 8b86e08..15b37d1 100644
--- a/test/core/transport/chttp2/hpack_table_test.c
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -167,7 +167,7 @@
                                                  const char *value) {
   grpc_mdelem *md = grpc_mdelem_from_strings(tbl->mdctx, key, value);
   grpc_chttp2_hptbl_find_result r = grpc_chttp2_hptbl_find(tbl, md);
-  grpc_mdelem_unref(md);
+  GRPC_MDELEM_UNREF(md);
   return r;
 }
 
diff --git a/test/core/transport/chttp2/stream_encoder_test.c b/test/core/transport/chttp2/stream_encoder_test.c
index bf70d43..e6731ff 100644
--- a/test/core/transport/chttp2/stream_encoder_test.c
+++ b/test/core/transport/chttp2/stream_encoder_test.c
@@ -85,12 +85,8 @@
   grpc_sopb_destroy(&encops);
 
   if (0 != gpr_slice_cmp(merged, expect)) {
-    char *expect_str =
-        gpr_hexdump((char *)GPR_SLICE_START_PTR(expect),
-                    GPR_SLICE_LENGTH(expect), GPR_HEXDUMP_PLAINTEXT);
-    char *got_str =
-        gpr_hexdump((char *)GPR_SLICE_START_PTR(merged),
-                    GPR_SLICE_LENGTH(merged), GPR_HEXDUMP_PLAINTEXT);
+    char *expect_str = gpr_dump_slice(expect, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+    char *got_str = gpr_dump_slice(merged, GPR_DUMP_HEX | GPR_DUMP_ASCII);
     gpr_log(GPR_ERROR, "mismatched output for %s", expected);
     gpr_log(GPR_ERROR, "EXPECT: %s", expect_str);
     gpr_log(GPR_ERROR, "GOT:    %s", got_str);
@@ -266,7 +262,7 @@
   GPR_ASSERT(0 == gpr_slice_str_cmp(el->key->slice, st->key));
   GPR_ASSERT(0 == gpr_slice_str_cmp(el->value->slice, st->value));
   st->got_hdr = 1;
-  grpc_mdelem_unref(el);
+  GRPC_MDELEM_UNREF(el);
 }
 
 static void test_decode_random_headers_inner(int max_len) {
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c
index 5bfb9cf..ba6c319 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -54,34 +54,35 @@
 
 void test_encoding(void) {
   LOG_TEST("test_encoding");
-  assert_encodes_as(gpr_time_from_micros(-1), "1n");
-  assert_encodes_as(gpr_time_from_seconds(-10), "1n");
-  assert_encodes_as(gpr_time_from_nanos(10), "10n");
-  assert_encodes_as(gpr_time_from_nanos(999999999), "1S");
-  assert_encodes_as(gpr_time_from_micros(1), "1u");
-  assert_encodes_as(gpr_time_from_micros(10), "10u");
-  assert_encodes_as(gpr_time_from_micros(100), "100u");
-  assert_encodes_as(gpr_time_from_micros(890), "890u");
-  assert_encodes_as(gpr_time_from_micros(900), "900u");
-  assert_encodes_as(gpr_time_from_micros(901), "901u");
-  assert_encodes_as(gpr_time_from_millis(1), "1m");
-  assert_encodes_as(gpr_time_from_millis(2), "2m");
-  assert_encodes_as(gpr_time_from_micros(10001), "10100u");
-  assert_encodes_as(gpr_time_from_micros(999999), "1S");
-  assert_encodes_as(gpr_time_from_millis(1000), "1S");
-  assert_encodes_as(gpr_time_from_millis(2000), "2S");
-  assert_encodes_as(gpr_time_from_millis(2500), "2500m");
-  assert_encodes_as(gpr_time_from_millis(59900), "59900m");
-  assert_encodes_as(gpr_time_from_seconds(50), "50S");
-  assert_encodes_as(gpr_time_from_seconds(59), "59S");
-  assert_encodes_as(gpr_time_from_seconds(60), "1M");
-  assert_encodes_as(gpr_time_from_seconds(80), "80S");
-  assert_encodes_as(gpr_time_from_seconds(90), "90S");
-  assert_encodes_as(gpr_time_from_minutes(2), "2M");
-  assert_encodes_as(gpr_time_from_minutes(20), "20M");
-  assert_encodes_as(gpr_time_from_hours(1), "1H");
-  assert_encodes_as(gpr_time_from_hours(10), "10H");
-  assert_encodes_as(gpr_time_from_seconds(1000000000), "1000000000S");
+  assert_encodes_as(gpr_time_from_micros(-1, GPR_TIMESPAN), "1n");
+  assert_encodes_as(gpr_time_from_seconds(-10, GPR_TIMESPAN), "1n");
+  assert_encodes_as(gpr_time_from_nanos(10, GPR_TIMESPAN), "10n");
+  assert_encodes_as(gpr_time_from_nanos(999999999, GPR_TIMESPAN), "1S");
+  assert_encodes_as(gpr_time_from_micros(1, GPR_TIMESPAN), "1u");
+  assert_encodes_as(gpr_time_from_micros(10, GPR_TIMESPAN), "10u");
+  assert_encodes_as(gpr_time_from_micros(100, GPR_TIMESPAN), "100u");
+  assert_encodes_as(gpr_time_from_micros(890, GPR_TIMESPAN), "890u");
+  assert_encodes_as(gpr_time_from_micros(900, GPR_TIMESPAN), "900u");
+  assert_encodes_as(gpr_time_from_micros(901, GPR_TIMESPAN), "901u");
+  assert_encodes_as(gpr_time_from_millis(1, GPR_TIMESPAN), "1m");
+  assert_encodes_as(gpr_time_from_millis(2, GPR_TIMESPAN), "2m");
+  assert_encodes_as(gpr_time_from_micros(10001, GPR_TIMESPAN), "10100u");
+  assert_encodes_as(gpr_time_from_micros(999999, GPR_TIMESPAN), "1S");
+  assert_encodes_as(gpr_time_from_millis(1000, GPR_TIMESPAN), "1S");
+  assert_encodes_as(gpr_time_from_millis(2000, GPR_TIMESPAN), "2S");
+  assert_encodes_as(gpr_time_from_millis(2500, GPR_TIMESPAN), "2500m");
+  assert_encodes_as(gpr_time_from_millis(59900, GPR_TIMESPAN), "59900m");
+  assert_encodes_as(gpr_time_from_seconds(50, GPR_TIMESPAN), "50S");
+  assert_encodes_as(gpr_time_from_seconds(59, GPR_TIMESPAN), "59S");
+  assert_encodes_as(gpr_time_from_seconds(60, GPR_TIMESPAN), "1M");
+  assert_encodes_as(gpr_time_from_seconds(80, GPR_TIMESPAN), "80S");
+  assert_encodes_as(gpr_time_from_seconds(90, GPR_TIMESPAN), "90S");
+  assert_encodes_as(gpr_time_from_minutes(2, GPR_TIMESPAN), "2M");
+  assert_encodes_as(gpr_time_from_minutes(20, GPR_TIMESPAN), "20M");
+  assert_encodes_as(gpr_time_from_hours(1, GPR_TIMESPAN), "1H");
+  assert_encodes_as(gpr_time_from_hours(10, GPR_TIMESPAN), "10H");
+  assert_encodes_as(gpr_time_from_seconds(1000000000, GPR_TIMESPAN),
+                    "1000000000S");
 }
 
 static void assert_decodes_as(const char *buffer, gpr_timespec expected) {
@@ -91,7 +92,8 @@
   GPR_ASSERT(0 == gpr_time_cmp(got, expected));
 }
 
-void decode_suite(char ext, gpr_timespec (*answer)(long x)) {
+void decode_suite(char ext,
+                  gpr_timespec (*answer)(long x, gpr_clock_type clock)) {
   long test_vals[] = {1,       12,       123,       1234,     12345,   123456,
                       1234567, 12345678, 123456789, 98765432, 9876543, 987654,
                       98765,   9876,     987,       98,       9};
@@ -99,19 +101,19 @@
   char *input;
   for (i = 0; i < GPR_ARRAY_SIZE(test_vals); i++) {
     gpr_asprintf(&input, "%ld%c", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i]));
+    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
     gpr_free(input);
 
     gpr_asprintf(&input, "   %ld%c", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i]));
+    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
     gpr_free(input);
 
     gpr_asprintf(&input, "%ld %c", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i]));
+    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
     gpr_free(input);
 
     gpr_asprintf(&input, "%ld %c  ", test_vals[i], ext);
-    assert_decodes_as(input, answer(test_vals[i]));
+    assert_decodes_as(input, answer(test_vals[i], GPR_TIMESPAN));
     gpr_free(input);
   }
 }
@@ -124,7 +126,8 @@
   decode_suite('S', gpr_time_from_seconds);
   decode_suite('M', gpr_time_from_minutes);
   decode_suite('H', gpr_time_from_hours);
-  assert_decodes_as("1000000000000000000000u", gpr_inf_future);
+  assert_decodes_as("1000000000000000000000u",
+                    gpr_inf_future(GPR_CLOCK_REALTIME));
 }
 
 void test_decoding_fails(void) {
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
index 89deee5..a932e04 100644
--- a/test/core/transport/metadata_test.c
+++ b/test/core/transport/metadata_test.c
@@ -70,10 +70,10 @@
   GPR_ASSERT(s3 != s1);
   GPR_ASSERT(gpr_slice_str_cmp(s1->slice, "hello") == 0);
   GPR_ASSERT(gpr_slice_str_cmp(s3->slice, "very much not hello") == 0);
-  grpc_mdstr_unref(s1);
-  grpc_mdstr_unref(s2);
+  GRPC_MDSTR_UNREF(s1);
+  GRPC_MDSTR_UNREF(s2);
   grpc_mdctx_unref(ctx);
-  grpc_mdstr_unref(s3);
+  GRPC_MDSTR_UNREF(s3);
 }
 
 static void test_create_metadata(void) {
@@ -93,9 +93,9 @@
   GPR_ASSERT(gpr_slice_str_cmp(m1->key->slice, "a") == 0);
   GPR_ASSERT(gpr_slice_str_cmp(m1->value->slice, "b") == 0);
   GPR_ASSERT(gpr_slice_str_cmp(m3->value->slice, "c") == 0);
-  grpc_mdelem_unref(m1);
-  grpc_mdelem_unref(m2);
-  grpc_mdelem_unref(m3);
+  GRPC_MDELEM_UNREF(m1);
+  GRPC_MDELEM_UNREF(m2);
+  GRPC_MDELEM_UNREF(m3);
   grpc_mdctx_unref(ctx);
 }
 
@@ -112,7 +112,7 @@
   /* add, and immediately delete a bunch of different elements */
   for (i = 0; i < MANY; i++) {
     gpr_ltoa(i, buffer);
-    grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", buffer));
+    GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", buffer));
   }
   /* capacity should not grow */
   GPR_ASSERT(mdtab_capacity_before ==
@@ -140,11 +140,11 @@
     gpr_ltoa(i, buffer);
     md = grpc_mdelem_from_strings(ctx, "a", buffer);
     GPR_ASSERT(md == created[i]);
-    grpc_mdelem_unref(md);
+    GRPC_MDELEM_UNREF(md);
   }
   /* cleanup phase */
   for (i = 0; i < MANY; i++) {
-    grpc_mdelem_unref(created[i]);
+    GRPC_MDELEM_UNREF(created[i]);
   }
   grpc_mdctx_unref(ctx);
 
@@ -160,15 +160,15 @@
   GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 0);
   GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 0);
 
-  grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b"));
+  GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", "b"));
   GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1);
   GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1);
 
-  grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b"));
+  GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", "b"));
   GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1);
   GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1);
 
-  grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", "b"));
+  GRPC_MDELEM_UNREF(grpc_mdelem_from_strings(ctx, "a", "b"));
   GPR_ASSERT(grpc_mdctx_get_mdtab_count_test_only(ctx) == 1);
   GPR_ASSERT(grpc_mdctx_get_mdtab_free_test_only(ctx) == 1);
 
@@ -196,8 +196,8 @@
   }
 
   for (i = 0; i < nstrs; i++) {
-    grpc_mdstr_ref(strs[i]);
-    grpc_mdstr_unref(strs[i]);
+    GRPC_MDSTR_REF(strs[i]);
+    GRPC_MDSTR_UNREF(strs[i]);
   }
 
   for (i = 0; i < nstrs; i++) {
@@ -209,12 +209,12 @@
   }
 
   for (i = 0; i < nstrs; i++) {
-    grpc_mdstr_unref(strs[shuf[i]]);
+    GRPC_MDSTR_UNREF(strs[shuf[i]]);
     for (j = i + 1; j < nstrs; j++) {
       gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]);
       test = grpc_mdstr_from_string(ctx, buffer);
       GPR_ASSERT(test == strs[shuf[j]]);
-      grpc_mdstr_unref(test);
+      GRPC_MDSTR_UNREF(test);
       gpr_free(buffer);
     }
   }
@@ -237,14 +237,14 @@
   str = grpc_mdstr_from_string(
       ctx, "123456789012345678901234567890123456789012345678901234567890");
   slice = gpr_slice_ref(str->slice);
-  grpc_mdstr_unref(str);
+  GRPC_MDSTR_UNREF(str);
   gpr_slice_unref(slice);
 
   str = grpc_mdstr_from_string(
       ctx, "123456789012345678901234567890123456789012345678901234567890");
   slice = gpr_slice_ref(str->slice);
   gpr_slice_unref(slice);
-  grpc_mdstr_unref(str);
+  GRPC_MDSTR_UNREF(str);
 
   grpc_mdctx_unref(ctx);
 }
@@ -264,7 +264,7 @@
   GPR_ASSERT(0 == gpr_slice_cmp(slice1, slice2));
 
   gpr_slice_unref(slice2);
-  grpc_mdstr_unref(str);
+  GRPC_MDSTR_UNREF(str);
   grpc_mdctx_unref(ctx);
 }
 
diff --git a/test/core/tsi/transport_security_test.c b/test/core/tsi/transport_security_test.c
index bba6744..bec3866 100644
--- a/test/core/tsi/transport_security_test.c
+++ b/test/core/tsi/transport_security_test.c
@@ -46,9 +46,6 @@
 #include "src/core/tsi/ssl_transport_security.h"
 #include "test/core/util/test_config.h"
 
-/* Currently points to 1.0.2a. */
-#define GRPC_MIN_OPENSSL_VERSION_NUMBER 0x1000201fL
-
 typedef struct {
   /* 1 if success, 0 if failure. */
   int expected;
@@ -299,13 +296,8 @@
   }
 }
 
-static void test_openssl_version(void) {
-  GPR_ASSERT(OPENSSL_VERSION_NUMBER >= GRPC_MIN_OPENSSL_VERSION_NUMBER);
-}
-
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_peer_matches_name();
-  test_openssl_version();
   return 0;
 }
diff --git a/test/core/util/grpc_profiler.c b/test/core/util/grpc_profiler.c
index d5b6cfe..c2c0c9c 100644
--- a/test/core/util/grpc_profiler.c
+++ b/test/core/util/grpc_profiler.c
@@ -43,11 +43,17 @@
 #include <grpc/support/log.h>
 
 void grpc_profiler_start(const char *filename) {
-  gpr_log(GPR_DEBUG,
-          "You do not have google-perftools installed, profiling is disabled [for %s]", filename);
-  gpr_log(GPR_DEBUG,
-          "To install on ubuntu: sudo apt-get install google-perftools "
-          "libgoogle-perftools-dev");
+  static int printed_warning = 0;
+  if (!printed_warning) {
+    gpr_log(GPR_DEBUG,
+            "You do not have google-perftools installed, profiling is disabled "
+            "[for %s]",
+            filename);
+    gpr_log(GPR_DEBUG,
+            "To install on ubuntu: sudo apt-get install google-perftools "
+            "libgoogle-perftools-dev");
+    printed_warning = 1;
+  }
 }
 
 void grpc_profiler_stop(void) {}
diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c
index 20ab67e..225658f 100644
--- a/test/core/util/test_config.c
+++ b/test/core/util/test_config.c
@@ -48,7 +48,45 @@
 static int seed(void) { return _getpid(); }
 #endif
 
+#if GPR_WINDOWS_CRASH_HANDLER
+LONG crash_handler(struct _EXCEPTION_POINTERS* ex_info) {
+  gpr_log(GPR_DEBUG, "Exception handler called, dumping information");
+  while (ex_info->ExceptionRecord) {
+    DWORD code = ex_info->ExceptionRecord->ExceptionCode;
+    DWORD flgs = ex_info->ExceptionRecord->ExceptionFlags;
+    PVOID addr = ex_info->ExceptionRecord->ExceptionAddress;
+    gpr_log("code: %x - flags: %d - address: %p", code, flgs, addr);
+    ex_info->ExceptionRecord = ex_info->ExceptionRecord->ExceptionRecord;
+  }
+  if (IsDebuggerPresent()) {
+    __debugbreak();
+  } else {
+    _exit(1);
+  }
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+
+void abort_handler(int sig) {
+  gpr_log(GPR_DEBUG, "Abort handler called.");
+  if (IsDebuggerPresent()) {
+    __debugbreak();
+  } else {
+    _exit(1);
+  }
+}
+
+static void install_crash_handler() {
+  SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) crash_handler);
+  _set_abort_behavior(0, _WRITE_ABORT_MSG);
+  _set_abort_behavior(0, _CALL_REPORTFAULT);
+  signal(SIGABRT, abort_handler);
+}
+#else
+static void install_crash_handler() { }
+#endif
+
 void grpc_test_init(int argc, char **argv) {
+  install_crash_handler();
   gpr_log(GPR_DEBUG, "test slowdown: machine=%f build=%f total=%f",
           (double)GRPC_TEST_SLOWDOWN_MACHINE_FACTOR,
           (double)GRPC_TEST_SLOWDOWN_BUILD_FACTOR,
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 0b3c543..063c797 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -51,13 +51,15 @@
 #define GRPC_TEST_SLOWDOWN_FACTOR \
   (GRPC_TEST_SLOWDOWN_BUILD_FACTOR * GRPC_TEST_SLOWDOWN_MACHINE_FACTOR)
 
-#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x) \
-  gpr_time_add(gpr_now(),                   \
-               gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e6 * (x)))
+#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                                \
+  gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),                                \
+               gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e6 * (x), \
+                                    GPR_TIMESPAN))
 
-#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x) \
-  gpr_time_add(gpr_now(),                  \
-               gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)))
+#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                 \
+  gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),                                \
+               gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x), \
+                                    GPR_TIMESPAN))
 
 #ifndef GRPC_TEST_CUSTOM_PICK_PORT
 #define GRPC_TEST_PICK_PORT
@@ -69,4 +71,4 @@
 }
 #endif /*  __cplusplus */
 
-#endif  /* GRPC_TEST_CORE_UTIL_TEST_CONFIG_H */
+#endif /* GRPC_TEST_CORE_UTIL_TEST_CONFIG_H */
diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc
new file mode 100644
index 0000000..3d983fa
--- /dev/null
+++ b/test/cpp/common/auth_property_iterator_test.cc
@@ -0,0 +1,101 @@
+/*
+ *
+ * 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 <grpc++/auth_context.h>
+#include <gtest/gtest.h>
+#include "src/cpp/common/secure_auth_context.h"
+#include "src/core/security/security_context.h"
+
+namespace grpc {
+namespace {
+
+class TestAuthPropertyIterator : public AuthPropertyIterator {
+ public:
+  TestAuthPropertyIterator() {}
+  TestAuthPropertyIterator(const grpc_auth_property* property,
+                           const grpc_auth_property_iterator* iter)
+      : AuthPropertyIterator(property, iter) {}
+};
+
+class AuthPropertyIteratorTest : public ::testing::Test {
+ protected:
+  void SetUp() GRPC_OVERRIDE {
+    ctx_ = grpc_auth_context_create(NULL, 3);
+    ctx_->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi");
+    ctx_->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo");
+    ctx_->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar");
+    ctx_->peer_identity_property_name = ctx_->properties[0].name;
+  }
+  void TearDown() GRPC_OVERRIDE {
+    GRPC_AUTH_CONTEXT_UNREF(ctx_, "AuthPropertyIteratorTest");
+  }
+  grpc_auth_context* ctx_;
+
+};
+
+TEST_F(AuthPropertyIteratorTest, DefaultCtor) {
+  TestAuthPropertyIterator iter1;
+  TestAuthPropertyIterator iter2;
+  EXPECT_EQ(iter1, iter2);
+}
+
+TEST_F(AuthPropertyIteratorTest, GeneralTest) {
+  grpc_auth_property_iterator c_iter =
+      grpc_auth_context_property_iterator(ctx_);
+  const grpc_auth_property* property =
+      grpc_auth_property_iterator_next(&c_iter);
+  TestAuthPropertyIterator iter(property, &c_iter);
+  TestAuthPropertyIterator empty_iter;
+  EXPECT_FALSE(iter == empty_iter);
+  AuthProperty p0 = *iter;
+  ++iter;
+  AuthProperty p1 = *iter;
+  iter++;
+  AuthProperty p2 = *iter;
+  EXPECT_EQ("name", p0.first);
+  EXPECT_EQ("chapi", p0.second);
+  EXPECT_EQ("name", p1.first);
+  EXPECT_EQ("chapo", p1.second);
+  EXPECT_EQ("foo", p2.first);
+  EXPECT_EQ("bar", p2.second);
+  ++iter;
+  EXPECT_EQ(empty_iter, iter);
+}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc
new file mode 100644
index 0000000..f18a041
--- /dev/null
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -0,0 +1,123 @@
+/*
+ *
+ * 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 <grpc++/auth_context.h>
+#include <gtest/gtest.h>
+#include "src/cpp/common/secure_auth_context.h"
+#include "src/core/security/security_context.h"
+
+namespace grpc {
+namespace {
+
+class SecureAuthContextTest : public ::testing::Test {};
+
+// Created with nullptr
+TEST_F(SecureAuthContextTest, EmptyContext) {
+  SecureAuthContext context(nullptr);
+  EXPECT_TRUE(context.GetPeerIdentity().empty());
+  EXPECT_TRUE(context.GetPeerIdentityPropertyName().empty());
+  EXPECT_TRUE(context.FindPropertyValues("").empty());
+  EXPECT_TRUE(context.FindPropertyValues("whatever").empty());
+  EXPECT_TRUE(context.begin() == context.end());
+}
+
+TEST_F(SecureAuthContextTest, Properties) {
+  grpc_auth_context* ctx = grpc_auth_context_create(NULL, 3);
+  ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi");
+  ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo");
+  ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar");
+  ctx->peer_identity_property_name = ctx->properties[0].name;
+
+  SecureAuthContext context(ctx);
+  std::vector<grpc::string> peer_identity = context.GetPeerIdentity();
+  EXPECT_EQ(2u, peer_identity.size());
+  EXPECT_EQ("chapi", peer_identity[0]);
+  EXPECT_EQ("chapo", peer_identity[1]);
+  EXPECT_EQ("name", context.GetPeerIdentityPropertyName());
+  std::vector<grpc::string> bar = context.FindPropertyValues("foo");
+  EXPECT_EQ(1u, bar.size());
+  EXPECT_EQ("bar", bar[0]);
+}
+
+TEST_F(SecureAuthContextTest, Iterators) {
+  grpc_auth_context* ctx = grpc_auth_context_create(NULL, 3);
+  ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi");
+  ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo");
+  ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar");
+  ctx->peer_identity_property_name = ctx->properties[0].name;
+
+  SecureAuthContext context(ctx);
+  AuthPropertyIterator iter = context.begin();
+  EXPECT_TRUE(context.end() != iter);
+  AuthProperty p0 = *iter;
+  ++iter;
+  AuthProperty p1 = *iter;
+  iter++;
+  AuthProperty p2 = *iter;
+  EXPECT_EQ("name", p0.first);
+  EXPECT_EQ("chapi", p0.second);
+  EXPECT_EQ("name", p1.first);
+  EXPECT_EQ("chapo", p1.second);
+  EXPECT_EQ("foo", p2.first);
+  EXPECT_EQ("bar", p2.second);
+  ++iter;
+  EXPECT_EQ(context.end(), iter);
+  // Range-based for loop test.
+  int i = 0;
+  for (auto p : context) {
+    switch (i++) {
+      case 0:
+        EXPECT_EQ("name", p.first);
+        EXPECT_EQ("chapi", p.second);
+        break;
+      case 1:
+        EXPECT_EQ("name", p.first);
+        EXPECT_EQ("chapo", p.second);
+        break;
+      case 2:
+        EXPECT_EQ("foo", p.first);
+        EXPECT_EQ("bar", p.second);
+        break;
+      default:
+        EXPECT_TRUE(0);
+    }
+  }
+}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 871f956..117d8bb 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -67,27 +67,45 @@
 
 void* tag(int i) { return (void*)(gpr_intptr) i; }
 
-void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
-  bool ok;
-  void* got_tag;
-  EXPECT_TRUE(cq->Next(&got_tag, &ok));
-  EXPECT_EQ(expect_ok, ok);
-  EXPECT_EQ(tag(i), got_tag);
-}
-
-void verify_timed_ok(
-    CompletionQueue* cq, int i, bool expect_ok,
-    std::chrono::system_clock::time_point deadline =
-        std::chrono::system_clock::time_point::max(),
-    CompletionQueue::NextStatus expected_outcome = CompletionQueue::GOT_EVENT) {
-  bool ok;
-  void* got_tag;
-  EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline), expected_outcome);
-  if (expected_outcome == CompletionQueue::GOT_EVENT) {
-    EXPECT_EQ(expect_ok, ok);
-    EXPECT_EQ(tag(i), got_tag);
+class Verifier {
+ public:
+  Verifier& Expect(int i, bool expect_ok) {
+    expectations_[tag(i)] = expect_ok;
+    return *this;
   }
-}
+  void Verify(CompletionQueue *cq) {
+    GPR_ASSERT(!expectations_.empty());
+    while (!expectations_.empty()) {
+      bool ok;
+      void* got_tag;
+      EXPECT_TRUE(cq->Next(&got_tag, &ok));
+      auto it = expectations_.find(got_tag);
+      EXPECT_TRUE(it != expectations_.end());
+      EXPECT_EQ(it->second, ok);
+      expectations_.erase(it);
+    }
+  }
+  void Verify(CompletionQueue *cq, std::chrono::system_clock::time_point deadline) {
+    if (expectations_.empty()) {
+      bool ok;
+      void *got_tag;
+      EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline), CompletionQueue::TIMEOUT);
+    } else {
+      while (!expectations_.empty()) {
+        bool ok;
+        void *got_tag;
+        EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline), CompletionQueue::GOT_EVENT);
+        auto it = expectations_.find(got_tag);
+        EXPECT_TRUE(it != expectations_.end());
+        EXPECT_EQ(it->second, ok);
+        expectations_.erase(it);
+      }
+    }
+  }
+
+ private:
+  std::map<void*, bool> expectations_;
+};
 
 class AsyncEnd2endTest : public ::testing::Test {
  protected:
@@ -100,7 +118,7 @@
     ServerBuilder builder;
     builder.AddListeningPort(server_address_.str(), grpc::InsecureServerCredentials());
     builder.RegisterAsyncService(&service_);
-    srv_cq_ = builder.AddCompletionQueue();
+    cq_ = builder.AddCompletionQueue();
     server_ = builder.BuildAndStart();
   }
 
@@ -108,11 +126,8 @@
     server_->Shutdown();
     void* ignored_tag;
     bool ignored_ok;
-    cli_cq_.Shutdown();
-    srv_cq_->Shutdown();
-    while (cli_cq_.Next(&ignored_tag, &ignored_ok))
-      ;
-    while (srv_cq_->Next(&ignored_tag, &ignored_ok))
+    cq_->Shutdown();
+    while (cq_->Next(&ignored_tag, &ignored_ok))
       ;
   }
 
@@ -122,11 +137,6 @@
     stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel));
   }
 
-  void server_ok(int i) { verify_ok(srv_cq_.get(), i, true); }
-  void client_ok(int i) { verify_ok(&cli_cq_, i, true); }
-  void server_fail(int i) { verify_ok(srv_cq_.get(), i, false); }
-  void client_fail(int i) { verify_ok(&cli_cq_, i, false); }
-
   void SendRpc(int num_rpcs) {
     for (int i = 0; i < num_rpcs; i++) {
       EchoRequest send_request;
@@ -141,28 +151,27 @@
 
       send_request.set_message("Hello");
       std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-          stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_));
+          stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
       service_.RequestEcho(&srv_ctx, &recv_request, &response_writer,
-                           srv_cq_.get(), srv_cq_.get(), tag(2));
+                           cq_.get(), cq_.get(), tag(2));
 
-      server_ok(2);
+      Verifier().Expect(2, true).Verify(cq_.get());
       EXPECT_EQ(send_request.message(), recv_request.message());
 
       send_response.set_message(recv_request.message());
       response_writer.Finish(send_response, Status::OK, tag(3));
-      server_ok(3);
+      Verifier().Expect(3, true).Verify(cq_.get());
 
       response_reader->Finish(&recv_response, &recv_status, tag(4));
-      client_ok(4);
+      Verifier().Expect(4, true).Verify(cq_.get());
 
       EXPECT_EQ(send_response.message(), recv_response.message());
       EXPECT_TRUE(recv_status.ok());
     }
   }
 
-  CompletionQueue cli_cq_;
-  std::unique_ptr<ServerCompletionQueue> srv_cq_;
+  std::unique_ptr<ServerCompletionQueue> cq_;
   std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
   std::unique_ptr<Server> server_;
   grpc::cpp::test::util::TestService::AsyncService service_;
@@ -195,27 +204,27 @@
 
   send_request.set_message("Hello");
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-      stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_));
+      stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   std::chrono::system_clock::time_point time_now(
       std::chrono::system_clock::now());
   std::chrono::system_clock::time_point time_limit(
       std::chrono::system_clock::now() + std::chrono::seconds(10));
-  verify_timed_ok(srv_cq_.get(), -1, true, time_now, CompletionQueue::TIMEOUT);
-  verify_timed_ok(&cli_cq_, -1, true, time_now, CompletionQueue::TIMEOUT);
+  Verifier().Verify(cq_.get(), time_now);
+  Verifier().Verify(cq_.get(), time_now);
 
-  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, srv_cq_.get(),
-                       srv_cq_.get(), tag(2));
+  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
+                       cq_.get(), tag(2));
 
-  verify_timed_ok(srv_cq_.get(), 2, true, time_limit);
+  Verifier().Expect(2, true).Verify(cq_.get(), time_limit);
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(3));
-  verify_timed_ok(srv_cq_.get(), 3, true);
+  Verifier().Expect(3, true).Verify(cq_.get(), std::chrono::system_clock::time_point::max());
 
   response_reader->Finish(&recv_response, &recv_status, tag(4));
-  verify_timed_ok(&cli_cq_, 4, true);
+  Verifier().Expect(4, true).Verify(cq_.get(), std::chrono::system_clock::time_point::max());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -236,40 +245,39 @@
 
   send_request.set_message("Hello");
   std::unique_ptr<ClientAsyncWriter<EchoRequest> > cli_stream(
-      stub_->AsyncRequestStream(&cli_ctx, &recv_response, &cli_cq_, tag(1)));
+      stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
 
-  service_.RequestRequestStream(&srv_ctx, &srv_stream, srv_cq_.get(),
-                                srv_cq_.get(), tag(2));
+  service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(),
+                                cq_.get(), tag(2));
 
-  server_ok(2);
-  client_ok(1);
+  Verifier().Expect(2, true).Expect(1, true).Verify(cq_.get());
 
   cli_stream->Write(send_request, tag(3));
-  client_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
-  server_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   cli_stream->Write(send_request, tag(5));
-  client_ok(5);
+  Verifier().Expect(5, true).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(6));
-  server_ok(6);
+  Verifier().Expect(6, true).Verify(cq_.get());
 
   EXPECT_EQ(send_request.message(), recv_request.message());
   cli_stream->WritesDone(tag(7));
-  client_ok(7);
+  Verifier().Expect(7, true).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(8));
-  server_fail(8);
+  Verifier().Expect(8, false).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_stream.Finish(send_response, Status::OK, tag(9));
-  server_ok(9);
+  Verifier().Expect(9, true).Verify(cq_.get());
 
   cli_stream->Finish(&recv_status, tag(10));
-  client_ok(10);
+  Verifier().Expect(10, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -290,38 +298,37 @@
 
   send_request.set_message("Hello");
   std::unique_ptr<ClientAsyncReader<EchoResponse> > cli_stream(
-      stub_->AsyncResponseStream(&cli_ctx, send_request, &cli_cq_, tag(1)));
+      stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
 
   service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
-                                 srv_cq_.get(), srv_cq_.get(), tag(2));
+                                 cq_.get(), cq_.get(), tag(2));
 
-  server_ok(2);
-  client_ok(1);
+  Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   srv_stream.Write(send_response, tag(3));
-  server_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   cli_stream->Read(&recv_response, tag(4));
-  client_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   srv_stream.Write(send_response, tag(5));
-  server_ok(5);
+  Verifier().Expect(5, true).Verify(cq_.get());
 
   cli_stream->Read(&recv_response, tag(6));
-  client_ok(6);
+  Verifier().Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   srv_stream.Finish(Status::OK, tag(7));
-  server_ok(7);
+  Verifier().Expect(7, true).Verify(cq_.get());
 
   cli_stream->Read(&recv_response, tag(8));
-  client_fail(8);
+  Verifier().Expect(8, false).Verify(cq_.get());
 
   cli_stream->Finish(&recv_status, tag(9));
-  client_ok(9);
+  Verifier().Expect(9, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -341,40 +348,39 @@
 
   send_request.set_message("Hello");
   std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse> >
-      cli_stream(stub_->AsyncBidiStream(&cli_ctx, &cli_cq_, tag(1)));
+      cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
 
-  service_.RequestBidiStream(&srv_ctx, &srv_stream, srv_cq_.get(),
-                             srv_cq_.get(), tag(2));
+  service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(),
+                             cq_.get(), tag(2));
 
-  server_ok(2);
-  client_ok(1);
+  Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
 
   cli_stream->Write(send_request, tag(3));
-  client_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
-  server_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   srv_stream.Write(send_response, tag(5));
-  server_ok(5);
+  Verifier().Expect(5, true).Verify(cq_.get());
 
   cli_stream->Read(&recv_response, tag(6));
-  client_ok(6);
+  Verifier().Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->WritesDone(tag(7));
-  client_ok(7);
+  Verifier().Expect(7, true).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(8));
-  server_fail(8);
+  Verifier().Expect(8, false).Verify(cq_.get());
 
   srv_stream.Finish(Status::OK, tag(9));
-  server_ok(9);
+  Verifier().Expect(9, true).Verify(cq_.get());
 
   cli_stream->Finish(&recv_status, tag(10));
-  client_ok(10);
+  Verifier().Expect(10, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -400,11 +406,11 @@
   cli_ctx.AddMetadata(meta2.first, meta2.second);
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-      stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_));
+      stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
-  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, srv_cq_.get(),
-                       srv_cq_.get(), tag(2));
-  server_ok(2);
+  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
+                       cq_.get(), tag(2));
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   auto client_initial_metadata = srv_ctx.client_metadata();
   EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second);
@@ -414,10 +420,10 @@
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(3));
 
-  server_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   response_reader->Finish(&recv_response, &recv_status, tag(4));
-  client_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -441,19 +447,19 @@
   std::pair<grpc::string, grpc::string> meta2("key2", "val2");
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-      stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_));
+      stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
-  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, srv_cq_.get(),
-                       srv_cq_.get(), tag(2));
-  server_ok(2);
+  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
+                       cq_.get(), tag(2));
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   srv_ctx.AddInitialMetadata(meta1.first, meta1.second);
   srv_ctx.AddInitialMetadata(meta2.first, meta2.second);
   response_writer.SendInitialMetadata(tag(3));
-  server_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   response_reader->ReadInitialMetadata(tag(4));
-  client_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
   auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
   EXPECT_EQ(meta1.second, server_initial_metadata.find(meta1.first)->second);
   EXPECT_EQ(meta2.second, server_initial_metadata.find(meta2.first)->second);
@@ -461,10 +467,10 @@
 
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(5));
-  server_ok(5);
+  Verifier().Expect(5, true).Verify(cq_.get());
 
   response_reader->Finish(&recv_response, &recv_status, tag(6));
-  client_ok(6);
+  Verifier().Expect(6, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -488,24 +494,24 @@
   std::pair<grpc::string, grpc::string> meta2("key2", "val2");
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-      stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_));
+      stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
-  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, srv_cq_.get(),
-                       srv_cq_.get(), tag(2));
-  server_ok(2);
+  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
+                       cq_.get(), tag(2));
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   response_writer.SendInitialMetadata(tag(3));
-  server_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_ctx.AddTrailingMetadata(meta1.first, meta1.second);
   srv_ctx.AddTrailingMetadata(meta2.first, meta2.second);
   response_writer.Finish(send_response, Status::OK, tag(4));
 
-  server_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
 
   response_reader->Finish(&recv_response, &recv_status, tag(5));
-  client_ok(5);
+  Verifier().Expect(5, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
   auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata();
@@ -548,11 +554,11 @@
   cli_ctx.AddMetadata(meta2.first, meta2.second);
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-      stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_));
+      stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
-  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, srv_cq_.get(),
-                       srv_cq_.get(), tag(2));
-  server_ok(2);
+  service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
+                       cq_.get(), tag(2));
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   auto client_initial_metadata = srv_ctx.client_metadata();
   EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second);
@@ -562,9 +568,9 @@
   srv_ctx.AddInitialMetadata(meta3.first, meta3.second);
   srv_ctx.AddInitialMetadata(meta4.first, meta4.second);
   response_writer.SendInitialMetadata(tag(3));
-  server_ok(3);
+  Verifier().Expect(3, true).Verify(cq_.get());
   response_reader->ReadInitialMetadata(tag(4));
-  client_ok(4);
+  Verifier().Expect(4, true).Verify(cq_.get());
   auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
   EXPECT_EQ(meta3.second, server_initial_metadata.find(meta3.first)->second);
   EXPECT_EQ(meta4.second, server_initial_metadata.find(meta4.first)->second);
@@ -575,10 +581,10 @@
   srv_ctx.AddTrailingMetadata(meta6.first, meta6.second);
   response_writer.Finish(send_response, Status::OK, tag(5));
 
-  server_ok(5);
+  Verifier().Expect(5, true).Verify(cq_.get());
 
   response_reader->Finish(&recv_response, &recv_status, tag(6));
-  client_ok(6);
+  Verifier().Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
   auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata();
diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc
index aeba295..906f124 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -31,13 +31,10 @@
  *
  */
 
-#include <thread>
-
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/echo_duplicate.grpc.pb.h"
 #include "test/cpp/util/echo.grpc.pb.h"
-#include "src/cpp/server/thread_pool.h"
 #include <grpc++/channel_arguments.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
@@ -90,14 +87,37 @@
 
   void KillServer() {
     server_.reset();
-    // give some time for the TCP connection to drop
-    gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
   }
 
  private:
   std::unique_ptr<SubProcess> server_;
 };
 
+TEST_F(CrashTest, KillBeforeWrite) {
+  auto stub = CreateServerAndStub();
+
+  EchoRequest request;
+  EchoResponse response;
+  ClientContext context;
+
+  auto stream = stub->BidiStream(&context);
+
+  request.set_message("Hello");
+  EXPECT_TRUE(stream->Write(request));
+  EXPECT_TRUE(stream->Read(&response));
+  EXPECT_EQ(response.message(), request.message());
+
+  KillServer();
+
+  request.set_message("You should be dead");
+  // This may succeed or fail depending on the state of the TCP connection
+  stream->Write(request);
+  // But the read will definitely fail
+  EXPECT_FALSE(stream->Read(&response));
+
+  EXPECT_FALSE(stream->Finish().ok());
+}
+
 TEST_F(CrashTest, KillAfterWrite) {
   auto stub = CreateServerAndStub();
 
@@ -117,30 +137,8 @@
 
   KillServer();
 
-  EXPECT_FALSE(stream->Read(&response));
-
-  EXPECT_FALSE(stream->Finish().ok());
-}
-
-TEST_F(CrashTest, KillBeforeWrite) {
-  auto stub = CreateServerAndStub();
-
-  EchoRequest request;
-  EchoResponse response;
-  ClientContext context;
-
-  auto stream = stub->BidiStream(&context);
-
-  request.set_message("Hello");
-  EXPECT_TRUE(stream->Write(request));
-  EXPECT_TRUE(stream->Read(&response));
-  EXPECT_EQ(response.message(), request.message());
-
-  KillServer();
-
-  request.set_message("You should be dead");
-  EXPECT_FALSE(stream->Write(request));
-  EXPECT_FALSE(stream->Read(&response));
+  // This may succeed or fail depending on how quick the server was
+  stream->Read(&response);
 
   EXPECT_FALSE(stream->Finish().ok());
 }
@@ -161,5 +159,11 @@
 
   grpc_test_init(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  // Order seems to matter on these tests: run three times to eliminate that
+  for (int i = 0; i < 3; i++) {
+    if (RUN_ALL_TESTS() != 0) {
+      return 1;
+    }
+  }
+  return 0;
 }
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 45ba8b0..8b4424c 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -35,7 +35,6 @@
 #include <thread>
 
 #include "src/core/security/credentials.h"
-#include "src/cpp/server/thread_pool.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/echo_duplicate.grpc.pb.h"
@@ -46,6 +45,7 @@
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
+#include <grpc++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -68,12 +68,14 @@
 
 namespace {
 
+const char* kServerCancelAfterReads = "cancel_after_reads";
+
 // When echo_deadline is requested, deadline seen in the ServerContext is set in
 // the response in seconds.
 void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
                        EchoResponse* response) {
   if (request->has_param() && request->param().echo_deadline()) {
-    gpr_timespec deadline = gpr_inf_future;
+    gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
     if (context->deadline() != system_clock::time_point::max()) {
       Timepoint2Timespec(context->deadline(), &deadline);
     }
@@ -81,16 +83,32 @@
   }
 }
 
+template <typename T>
+void CheckAuthContext(T* context) {
+  std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
+  std::vector<grpc::string> fake =
+      auth_ctx->FindPropertyValues("transport_security_type");
+  EXPECT_EQ(1u, fake.size());
+  EXPECT_EQ("fake", fake[0]);
+  EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
+  EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
+}
+
 }  // namespace
 
 class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
  public:
-  TestServiceImpl() : signal_client_(false) {}
+  TestServiceImpl() : signal_client_(false), host_() {}
+  explicit TestServiceImpl(const grpc::string& host)
+      : signal_client_(false), host_(new grpc::string(host)) {}
 
   Status Echo(ServerContext* context, const EchoRequest* request,
               EchoResponse* response) GRPC_OVERRIDE {
     response->set_message(request->message());
     MaybeEchoDeadline(context, request, response);
+    if (host_) {
+      response->mutable_param()->set_host(*host_);
+    }
     if (request->has_param() && request->param().client_cancel_after_us()) {
       {
         std::unique_lock<std::mutex> lock(mu_);
@@ -98,15 +116,17 @@
       }
       while (!context->IsCancelled()) {
         gpr_sleep_until(gpr_time_add(
-            gpr_now(),
-            gpr_time_from_micros(request->param().client_cancel_after_us())));
+            gpr_now(GPR_CLOCK_REALTIME),
+            gpr_time_from_micros(request->param().client_cancel_after_us(),
+                                 GPR_TIMESPAN)));
       }
       return Status::CANCELLED;
     } else if (request->has_param() &&
                request->param().server_cancel_after_us()) {
       gpr_sleep_until(gpr_time_add(
-            gpr_now(),
-            gpr_time_from_micros(request->param().server_cancel_after_us())));
+          gpr_now(GPR_CLOCK_REALTIME),
+          gpr_time_from_micros(request->param().server_cancel_after_us(),
+                               GPR_TIMESPAN)));
       return Status::CANCELLED;
     } else {
       EXPECT_FALSE(context->IsCancelled());
@@ -121,6 +141,9 @@
         context->AddTrailingMetadata((*iter).first, (*iter).second);
       }
     }
+    if (request->has_param() && request->param().check_auth_context()) {
+      CheckAuthContext(context);
+    }
     return Status::OK;
   }
 
@@ -131,7 +154,23 @@
                        EchoResponse* response) GRPC_OVERRIDE {
     EchoRequest request;
     response->set_message("");
+    int cancel_after_reads = 0;
+    const std::multimap<grpc::string, grpc::string> client_initial_metadata =
+        context->client_metadata();
+    if (client_initial_metadata.find(kServerCancelAfterReads) !=
+        client_initial_metadata.end()) {
+      std::istringstream iss(
+          client_initial_metadata.find(kServerCancelAfterReads)->second);
+      iss >> cancel_after_reads;
+      gpr_log(GPR_INFO, "cancel_after_reads %d", cancel_after_reads);
+    }
     while (reader->Read(&request)) {
+      if (cancel_after_reads == 1) {
+        gpr_log(GPR_INFO, "return cancel status");
+        return Status::CANCELLED;
+      } else if (cancel_after_reads > 0) {
+        cancel_after_reads--;
+      }
       response->mutable_message()->append(request.message());
     }
     return Status::OK;
@@ -173,6 +212,7 @@
  private:
   bool signal_client_;
   std::mutex mu_;
+  std::unique_ptr<grpc::string> host_;
 };
 
 class TestServiceImplDupPkg
@@ -187,7 +227,8 @@
 
 class End2endTest : public ::testing::Test {
  protected:
-  End2endTest() : kMaxMessageSize_(8192), thread_pool_(2) {}
+  End2endTest()
+      : kMaxMessageSize_(8192), special_service_("special"), thread_pool_(2) {}
 
   void SetUp() GRPC_OVERRIDE {
     int port = grpc_pick_unused_port_or_die();
@@ -197,6 +238,7 @@
     builder.AddListeningPort(server_address_.str(),
                              FakeTransportSecurityServerCredentials());
     builder.RegisterService(&service_);
+    builder.RegisterService("special", &special_service_);
     builder.SetMaxMessageSize(
         kMaxMessageSize_);  // For testing max message size.
     builder.RegisterService(&dup_pkg_service_);
@@ -218,24 +260,42 @@
   std::ostringstream server_address_;
   const int kMaxMessageSize_;
   TestServiceImpl service_;
+  TestServiceImpl special_service_;
   TestServiceImplDupPkg dup_pkg_service_;
-  ThreadPool thread_pool_;
+  FixedSizeThreadPool thread_pool_;
 };
 
 static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub,
                     int num_rpcs) {
   EchoRequest request;
   EchoResponse response;
-  request.set_message("Hello");
+  request.set_message("Hello hello hello hello");
 
   for (int i = 0; i < num_rpcs; ++i) {
     ClientContext context;
+    context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
     Status s = stub->Echo(&context, request, &response);
     EXPECT_EQ(response.message(), request.message());
     EXPECT_TRUE(s.ok());
   }
 }
 
+TEST_F(End2endTest, SimpleRpcWithHost) {
+  ResetStub();
+
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+
+  ClientContext context;
+  context.set_authority("special");
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_EQ(response.message(), request.message());
+  EXPECT_TRUE(response.has_param());
+  EXPECT_EQ(response.param().host(), "special");
+  EXPECT_TRUE(s.ok());
+}
+
 TEST_F(End2endTest, SimpleRpc) {
   ResetStub();
   SendRpc(stub_.get(), 1);
@@ -318,7 +378,8 @@
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(response.message(), request.message());
   EXPECT_TRUE(s.ok());
-  EXPECT_EQ(response.param().request_deadline(), gpr_inf_future.tv_sec);
+  EXPECT_EQ(response.param().request_deadline(),
+            gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec);
 }
 
 TEST_F(End2endTest, UnimplementedRpc) {
@@ -472,7 +533,8 @@
 }
 
 void CancelRpc(ClientContext* context, int delay_us, TestServiceImpl* service) {
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_micros(delay_us)));
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_micros(delay_us, GPR_TIMESPAN)));
   while (!service->signal_client()) {
   }
   context->TryCancel();
@@ -687,6 +749,42 @@
   EXPECT_TRUE(s.ok());
 }
 
+// Client sends 20 requests and the server returns CANCELLED status after
+// reading 10 requests.
+TEST_F(End2endTest, RequestStreamServerEarlyCancelTest) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  ClientContext context;
+
+  context.AddMetadata(kServerCancelAfterReads, "10");
+  auto stream = stub_->RequestStream(&context, &response);
+  request.set_message("hello");
+  int send_messages = 20;
+  while (send_messages > 0) {
+    EXPECT_TRUE(stream->Write(request));
+    send_messages--;
+  }
+  stream->WritesDone();
+  Status s = stream->Finish();
+  EXPECT_EQ(s.error_code(), StatusCode::CANCELLED);
+}
+
+TEST_F(End2endTest, ClientAuthContext) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+  request.mutable_param()->set_check_auth_context(true);
+
+  ClientContext context;
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_EQ(response.message(), request.message());
+  EXPECT_TRUE(s.ok());
+
+  CheckAuthContext(&context);
+}
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 7132b6b..4951c82 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -33,10 +33,10 @@
 
 #include <memory>
 
-#include "src/cpp/proto/proto_utils.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/echo.grpc.pb.h"
+#include <grpc++/impl/proto_utils.h>
 #include <grpc++/async_generic_service.h>
 #include <grpc++/async_unary_call.h>
 #include <grpc++/byte_buffer.h>
@@ -227,6 +227,7 @@
   GenericServerContext srv_ctx;
   GenericServerAsyncReaderWriter srv_stream(&srv_ctx);
 
+  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
   send_request.set_message("Hello");
   std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
       generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index 2809ab8..74b40d5 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -37,12 +37,12 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/echo_duplicate.grpc.pb.h"
 #include "test/cpp/util/echo.grpc.pb.h"
-#include "src/cpp/server/thread_pool.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++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -86,7 +86,9 @@
     msg->set_message(last_message_);
     return true;
   }
-  bool Write(const EchoRequest& msg) GRPC_OVERRIDE {
+
+  bool Write(const EchoRequest& msg,
+             const WriteOptions& options) GRPC_OVERRIDE {
     gpr_log(GPR_INFO, "mock recv msg %s", msg.message().c_str());
     last_message_ = msg.message();
     return true;
@@ -258,7 +260,7 @@
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
   TestServiceImpl service_;
-  ThreadPool thread_pool_;
+  FixedSizeThreadPool thread_pool_;
 };
 
 // Do one real rpc and one mocked one
diff --git a/test/cpp/end2end/server_crash_test.cc b/test/cpp/end2end/server_crash_test.cc
index 3fdae9b..5c7bb4e 100644
--- a/test/cpp/end2end/server_crash_test.cc
+++ b/test/cpp/end2end/server_crash_test.cc
@@ -31,13 +31,10 @@
  *
  */
 
-#include <thread>
-
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/echo_duplicate.grpc.pb.h"
 #include "test/cpp/util/echo.grpc.pb.h"
-#include "src/cpp/server/thread_pool.h"
 #include <grpc++/channel_arguments.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
@@ -84,7 +81,8 @@
       gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
       response.set_message(request.message());
       stream->Write(response);
-      gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
+      gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                   gpr_time_from_seconds(1, GPR_TIMESPAN)));
     }
     return Status::OK;
   }
@@ -98,7 +96,8 @@
       msg << "Hello " << i;
       response.set_message(msg.str());
       if (!writer->Write(response)) break;
-      gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
+      gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                   gpr_time_from_seconds(1, GPR_TIMESPAN)));
     }
     return Status::OK;
   }
@@ -145,7 +144,8 @@
 TEST_F(CrashTest, ResponseStream) {
   auto server = CreateServerAndClient("response");
 
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
   KillClient();
   server->Shutdown();
   GPR_ASSERT(HadOneResponseStream());
@@ -154,7 +154,8 @@
 TEST_F(CrashTest, BidiStream) {
   auto server = CreateServerAndClient("bidi");
 
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
   KillClient();
   server->Shutdown();
   GPR_ASSERT(HadOneBidiStream());
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 0b43dfd..e471396 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -38,12 +38,12 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/echo_duplicate.grpc.pb.h"
 #include "test/cpp/util/echo.grpc.pb.h"
-#include "src/cpp/server/thread_pool.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++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -71,7 +71,7 @@
 void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
                        EchoResponse* response) {
   if (request->has_param() && request->param().echo_deadline()) {
-    gpr_timespec deadline = gpr_inf_future;
+    gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
     if (context->deadline() != system_clock::time_point::max()) {
       Timepoint2Timespec(context->deadline(), &deadline);
     }
@@ -96,15 +96,17 @@
       }
       while (!context->IsCancelled()) {
         gpr_sleep_until(gpr_time_add(
-            gpr_now(),
-            gpr_time_from_micros(request->param().client_cancel_after_us())));
+            gpr_now(GPR_CLOCK_REALTIME),
+            gpr_time_from_micros(request->param().client_cancel_after_us(),
+                                 GPR_TIMESPAN)));
       }
       return Status::CANCELLED;
     } else if (request->has_param() &&
                request->param().server_cancel_after_us()) {
       gpr_sleep_until(gpr_time_add(
-          gpr_now(),
-          gpr_time_from_micros(request->param().server_cancel_after_us())));
+          gpr_now(GPR_CLOCK_REALTIME),
+          gpr_time_from_micros(request->param().server_cancel_after_us(),
+                               GPR_TIMESPAN)));
       return Status::CANCELLED;
     } else {
       EXPECT_FALSE(context->IsCancelled());
@@ -206,7 +208,7 @@
   const int kMaxMessageSize_;
   TestServiceImpl service_;
   TestServiceImplDupPkg dup_pkg_service_;
-  ThreadPool thread_pool_;
+  FixedSizeThreadPool thread_pool_;
 };
 
 static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub,
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 65ce2e9..1f1e6c1 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -64,9 +64,11 @@
               "ping_pong : full-duplex streaming; "
               "cancel_after_begin : cancel stream after starting it; "
               "cancel_after_first_response: cancel on first response; "
+              "timeout_on_sleeping_server: deadline exceeds on stream; "
               "service_account_creds : large_unary with service_account auth; "
               "compute_engine_creds: large_unary with compute engine auth; "
               "jwt_token_creds: large_unary with JWT token auth; "
+              "oauth2_auth_token: raw oauth2 access token auth; "
               "all : all of above.");
 DEFINE_string(default_service_account, "",
               "Email of GCE default service account");
@@ -101,6 +103,8 @@
     client.DoCancelAfterBegin();
   } else if (FLAGS_test_case == "cancel_after_first_response") {
     client.DoCancelAfterFirstResponse();
+  } else if (FLAGS_test_case == "timeout_on_sleeping_server") {
+    client.DoTimeoutOnSleepingServer();
   } else if (FLAGS_test_case == "service_account_creds") {
     grpc::string json_key = GetServiceAccountJsonKey();
     client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope);
@@ -110,6 +114,9 @@
   } else if (FLAGS_test_case == "jwt_token_creds") {
     grpc::string json_key = GetServiceAccountJsonKey();
     client.DoJwtTokenCreds(json_key);
+  } else if (FLAGS_test_case == "oauth2_auth_token") {
+    grpc::string json_key = GetServiceAccountJsonKey();
+    client.DoOauth2AuthToken(json_key, FLAGS_oauth_scope);
   } else if (FLAGS_test_case == "all") {
     client.DoEmpty();
     client.DoLargeUnary();
@@ -119,11 +126,13 @@
     client.DoPingPong();
     client.DoCancelAfterBegin();
     client.DoCancelAfterFirstResponse();
+    client.DoTimeoutOnSleepingServer();
     // service_account_creds and jwt_token_creds can only run with ssl.
     if (FLAGS_enable_ssl) {
       grpc::string json_key = GetServiceAccountJsonKey();
       client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope);
       client.DoJwtTokenCreds(json_key);
+      client.DoOauth2AuthToken(json_key, FLAGS_oauth_scope);
     }
     // compute_engine_creds only runs in GCE.
   } else {
@@ -132,7 +141,8 @@
         "Unsupported test case %s. Valid options are all|empty_unary|"
         "large_unary|client_streaming|server_streaming|half_duplex|ping_pong|"
         "cancel_after_begin|cancel_after_first_response|"
-        "service_account_creds|compute_engine_creds|jwt_token_creds",
+        "timeout_on_sleeping_server|service_account_creds|compute_engine_creds|"
+        "jwt_token_creds|oauth2_auth_token",
         FLAGS_test_case.c_str());
     ret = 1;
   }
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index 09fd1c8..48b1b2e 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -40,6 +40,7 @@
 #include <unistd.h>
 
 #include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <gflags/gflags.h>
 #include <grpc++/channel_arguments.h>
@@ -47,6 +48,8 @@
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
 #include <grpc++/stream.h>
+#include "src/cpp/client/secure_credentials.h"
+#include "test/core/security/oauth2_utils.h"
 #include "test/cpp/util/create_test_channel.h"
 
 DECLARE_bool(enable_ssl);
@@ -62,6 +65,16 @@
 namespace grpc {
 namespace testing {
 
+namespace {
+std::shared_ptr<Credentials> CreateServiceAccountCredentials() {
+  GPR_ASSERT(FLAGS_enable_ssl);
+  grpc::string json_key = GetServiceAccountJsonKey();
+  std::chrono::seconds token_lifetime = std::chrono::hours(1);
+  return ServiceAccountCredentials(json_key, FLAGS_oauth_scope,
+                                   token_lifetime.count());
+}
+}  // namespace
+
 grpc::string GetServiceAccountJsonKey() {
   static grpc::string json_key;
   if (json_key.empty()) {
@@ -73,6 +86,20 @@
   return json_key;
 }
 
+grpc::string GetOauth2AccessToken() {
+  std::shared_ptr<Credentials> creds = CreateServiceAccountCredentials();
+  SecureCredentials* secure_creds =
+      dynamic_cast<SecureCredentials*>(creds.get());
+  GPR_ASSERT(secure_creds != nullptr);
+  grpc_credentials* c_creds = secure_creds->GetRawCreds();
+  char* token = grpc_test_fetch_oauth2_token_with_credentials(c_creds);
+  GPR_ASSERT(token != nullptr);
+  gpr_log(GPR_INFO, "Get raw oauth2 access token: %s", token);
+  grpc::string access_token(token + sizeof("Bearer ") - 1);
+  gpr_free(token);
+  return access_token;
+}
+
 std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
     const grpc::string& test_case) {
   GPR_ASSERT(FLAGS_server_port);
@@ -82,12 +109,7 @@
            FLAGS_server_port);
 
   if (test_case == "service_account_creds") {
-    std::shared_ptr<Credentials> creds;
-    GPR_ASSERT(FLAGS_enable_ssl);
-    grpc::string json_key = GetServiceAccountJsonKey();
-    std::chrono::seconds token_lifetime = std::chrono::hours(1);
-    creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope,
-                                      token_lifetime.count());
+    std::shared_ptr<Credentials> creds = CreateServiceAccountCredentials();
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
   } else if (test_case == "compute_engine_creds") {
@@ -104,6 +126,11 @@
     creds = JWTCredentials(json_key, token_lifetime.count());
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
+  } else if (test_case == "oauth2_auth_token") {
+    grpc::string raw_token = GetOauth2AccessToken();
+    std::shared_ptr<Credentials> creds = AccessTokenCredentials(raw_token);
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
   } else {
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_enable_ssl, FLAGS_use_prod_roots);
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index 897f974..c4361bb 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -44,6 +44,8 @@
 
 grpc::string GetServiceAccountJsonKey();
 
+grpc::string GetOauth2AccessToken();
+
 std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
     const grpc::string& test_case);
 
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index f08f90b..4dcd8ad 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -143,6 +143,29 @@
   gpr_log(GPR_INFO, "Large unary with service account creds done.");
 }
 
+void InteropClient::DoOauth2AuthToken(const grpc::string& username,
+                                      const grpc::string& oauth_scope) {
+  gpr_log(GPR_INFO,
+          "Sending a unary rpc with raw oauth2 access token credentials ...");
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_fill_username(true);
+  request.set_fill_oauth_scope(true);
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+
+  Status s = stub->UnaryCall(&context, request, &response);
+
+  AssertOkOrPrintErrorStatus(s);
+  GPR_ASSERT(!response.username().empty());
+  GPR_ASSERT(!response.oauth_scope().empty());
+  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
+  const char* oauth_scope_str = response.oauth_scope().c_str();
+  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
+  gpr_log(GPR_INFO, "Unary with oauth2 access token credentials done.");
+}
+
 void InteropClient::DoJwtTokenCreds(const grpc::string& username) {
   gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ...");
   SimpleRequest request;
@@ -351,5 +374,26 @@
   gpr_log(GPR_INFO, "Canceling pingpong streaming done.");
 }
 
+void InteropClient::DoTimeoutOnSleepingServer() {
+  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc with a short deadline...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  std::chrono::system_clock::time_point deadline =
+      std::chrono::system_clock::now() + std::chrono::milliseconds(1);
+  context.set_deadline(deadline);
+  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
+                                     StreamingOutputCallResponse>>
+      stream(stub->FullDuplexCall(&context));
+
+  StreamingOutputCallRequest request;
+  request.mutable_payload()->set_body(grpc::string(27182, '\0'));
+  stream->Write(request);
+
+  Status s = stream->Finish();
+  GPR_ASSERT(s.error_code() == StatusCode::DEADLINE_EXCEEDED);
+  gpr_log(GPR_INFO, "Pingpong streaming timeout done.");
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index d9c895d..67eecd9 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -59,6 +59,7 @@
   void DoResponseStreamingWithSlowConsumer();
   void DoCancelAfterBegin();
   void DoCancelAfterFirstResponse();
+  void DoTimeoutOnSleepingServer();
   // Auth tests.
   // username is a string containing the user email
   void DoJwtTokenCreds(const grpc::string& username);
@@ -67,6 +68,9 @@
   // username is a string containing the user email
   void DoServiceAccountCreds(const grpc::string& username,
                              const grpc::string& oauth_scope);
+  // username is a string containing the user email
+  void DoOauth2AuthToken(const grpc::string& username,
+                         const grpc::string& oauth_scope);
 
  private:
   void PerformLargeUnary(SimpleRequest* request, SimpleResponse* response);
diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc
index 22b8910..db87872 100644
--- a/test/cpp/interop/server.cc
+++ b/test/cpp/interop/server.cc
@@ -149,14 +149,12 @@
     StreamingOutputCallResponse response;
     bool write_success = true;
     while (write_success && stream->Read(&request)) {
-      response.mutable_payload()->set_type(request.payload().type());
-      if (request.response_parameters_size() == 0) {
-        return Status(grpc::StatusCode::INTERNAL,
-                      "Request does not have response parameters.");
+      if (request.response_parameters_size() != 0) {
+        response.mutable_payload()->set_type(request.payload().type());
+        response.mutable_payload()->set_body(
+            grpc::string(request.response_parameters(0).size(), '\0'));
+        write_success = stream->Write(response);
       }
-      response.mutable_payload()->set_body(
-          grpc::string(request.response_parameters(0).size(), '\0'));
-      write_success = stream->Write(response);
     }
     if (write_success) {
       return Status::OK;
diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc
index c2e750d..30a78ff 100644
--- a/test/cpp/interop/server_helper.cc
+++ b/test/cpp/interop/server_helper.cc
@@ -58,5 +58,18 @@
   }
 }
 
+InteropContextInspector::InteropContextInspector(
+    const ::grpc::ServerContext& context)
+    : context_(context) {}
+
+std::shared_ptr<const AuthContext> InteropContextInspector::GetAuthContext()
+    const {
+  return context_.auth_context();
+}
+
+bool InteropContextInspector::IsCancelled() const {
+  return context_.IsCancelled();
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h
index f98e67b..ce977b4 100644
--- a/test/cpp/interop/server_helper.h
+++ b/test/cpp/interop/server_helper.h
@@ -36,6 +36,7 @@
 
 #include <memory>
 
+#include <grpc++/server_context.h>
 #include <grpc++/server_credentials.h>
 
 namespace grpc {
@@ -43,6 +44,18 @@
 
 std::shared_ptr<ServerCredentials> CreateInteropServerCredentials();
 
+class InteropContextInspector {
+ public:
+  InteropContextInspector(const ::grpc::ServerContext& context);
+
+  // Inspector methods, able to peek inside ServerContext, follow.
+  std::shared_ptr<const AuthContext> GetAuthContext() const;
+  bool IsCancelled() const;
+
+ private:
+  const ::grpc::ServerContext& context_;
+};
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 1b7a8d2..e1e44f9 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -168,7 +168,7 @@
       if (!closed_loop_) {
         rpc_deadlines_.emplace_back();
         next_channel_.push_back(i % channel_count_);
-        issue_allowed_.push_back(true);
+        issue_allowed_.emplace_back(true);
 
         grpc_time next_issue;
         NextIssueTime(i, &next_issue);
@@ -199,6 +199,15 @@
         delete ClientRpcContext::detag(got_tag);
       }
     }
+    // Now clear out all the pre-allocated idle contexts
+    for (int ch = 0; ch < channel_count_; ch++) {
+      while (!contexts_[ch].empty()) {
+        // Get an idle context from the front of the list
+        auto* ctx = *(contexts_[ch].begin());
+        contexts_[ch].pop_front();
+        delete ctx;
+      }
+    }
   }
 
   bool ThreadFunc(Histogram* histogram,
@@ -234,12 +243,6 @@
         GPR_ASSERT(false);
         break;
     }
-    if ((closed_loop_ || !rpc_deadlines_[thread_idx].empty()) &&
-        grpc_time_source::now() > deadline) {
-      // we have missed some 1-second deadline, which is worth noting
-      gpr_log(GPR_INFO, "Missed an RPC deadline");
-      // Don't give up, as there might be some truly heavy tails
-    }
     if (got_event) {
       ClientRpcContext* ctx = ClientRpcContext::detag(got_tag);
       if (ctx->RunNextState(ok, histogram) == false) {
@@ -313,11 +316,20 @@
   }
 
  private:
+  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;}
+   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<bool> issue_allowed_;    // may this thread attempt to issue
+  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_;
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index c8cc11e..a036029 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -185,8 +185,9 @@
 
   // Let everything warmup
   gpr_log(GPR_INFO, "Warming up");
-  gpr_timespec start = gpr_now();
-  gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(warmup_seconds)));
+  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
+  gpr_sleep_until(
+      gpr_time_add(start, gpr_time_from_seconds(warmup_seconds, GPR_TIMESPAN)));
 
   // Start a run
   gpr_log(GPR_INFO, "Starting");
@@ -211,8 +212,8 @@
 
   // Wait some time
   gpr_log(GPR_INFO, "Running");
-  gpr_sleep_until(
-      gpr_time_add(start, gpr_time_from_seconds(benchmark_seconds)));
+  gpr_sleep_until(gpr_time_add(
+      start, gpr_time_from_seconds(benchmark_seconds, GPR_TIMESPAN)));
 
   // Finish a run
   std::unique_ptr<ScenarioResult> result(new ScenarioResult);
diff --git a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs b/test/cpp/qps/perf_db.proto
similarity index 62%
copy from src/csharp/Grpc.Core/Stub/StubConfiguration.cs
copy to test/cpp/qps/perf_db.proto
index 5bcb5b4..60e0384 100644
--- a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
+++ b/test/cpp/qps/perf_db.proto
@@ -1,5 +1,3 @@
-#region Copyright notice and license
-
 // Copyright 2015, Google Inc.
 // All rights reserved.
 //
@@ -29,36 +27,45 @@
 // (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
+syntax = "proto3";
 
-using System;
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+import "test/cpp/qps/qpstest.proto";
 
-namespace Grpc.Core
-{
-    public delegate void HeaderInterceptorDelegate(Metadata.Builder headerBuilder);
+package grpc.testing;
 
-    public class StubConfiguration
-    {
-        /// <summary>
-        /// The default stub configuration.
-        /// </summary>
-        public static readonly StubConfiguration Default = new StubConfiguration((headerBuilder) => { });
+service PerfDbTransfer {
+  // Sends client info
+  rpc RecordSingleClientData(SingleUserRecordRequest)
+      returns (SingleUserRecordReply) {
+  }
+}
 
-        readonly HeaderInterceptorDelegate headerInterceptor;
+// Metrics to be stored
+message Metrics {
+  double qps = 1;
+  double qps_per_core = 2;
+  double perc_lat_50 = 3;
+  double perc_lat_90 = 4;
+  double perc_lat_95 = 5;
+  double perc_lat_99 = 6;
+  double perc_lat_99_point_9 = 7;
+  double server_system_time = 8;
+  double server_user_time = 9;
+  double client_system_time = 10;
+  double client_user_time = 11;
+}
 
-        public StubConfiguration(HeaderInterceptorDelegate headerInterceptor)
-        {
-            this.headerInterceptor = Preconditions.CheckNotNull(headerInterceptor);
-        }
+// Request for storing a single user's data
+message SingleUserRecordRequest {
+  string hashed_id = 1;
+  string test_name = 2;
+  string sys_info = 3;
+  string tag = 4;
+  Metrics metrics = 5;
+  ClientConfig client_config = 6;
+  ServerConfig server_config = 7;
+}
 
-        public HeaderInterceptorDelegate HeaderInterceptor
-        {
-            get
-            {
-                return headerInterceptor;
-            }
-        }
-    }
+// Reply to request for storing single user's data
+message SingleUserRecordReply {
 }
diff --git a/test/cpp/qps/perf_db_client.cc b/test/cpp/qps/perf_db_client.cc
new file mode 100644
index 0000000..08d20f0
--- /dev/null
+++ b/test/cpp/qps/perf_db_client.cc
@@ -0,0 +1,143 @@
+/*
+ *
+ * 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/cpp/qps/perf_db_client.h"
+
+namespace grpc {
+namespace testing {
+
+// sets the client and server config information
+void PerfDbClient::setConfigs(const ClientConfig& client_config,
+                              const ServerConfig& server_config) {
+  client_config_ = client_config;
+  server_config_ = server_config;
+}
+
+// sets the QPS
+void PerfDbClient::setQps(double qps) {
+  qps_ = qps;
+}
+
+// sets the QPS per core
+void PerfDbClient::setQpsPerCore(double qps_per_core) {
+  qps_per_core_ = qps_per_core;
+}
+
+// sets the 50th, 90th, 95th, 99th and 99.9th percentile latency
+void PerfDbClient::setLatencies(double perc_lat_50,
+                                double perc_lat_90,
+                                double perc_lat_95,
+                                double perc_lat_99,
+                                double perc_lat_99_point_9) {
+  perc_lat_50_ = perc_lat_50;
+  perc_lat_90_ = perc_lat_90;
+  perc_lat_95_ = perc_lat_95;
+  perc_lat_99_ = perc_lat_99;
+  perc_lat_99_point_9_ = perc_lat_99_point_9;
+}
+
+// sets the server and client, user and system times
+void PerfDbClient::setTimes(double server_system_time, double server_user_time,
+                            double client_system_time, double client_user_time) {
+  server_system_time_ = server_system_time;
+  server_user_time_ = server_user_time;
+  client_system_time_ = client_system_time;
+  client_user_time_ = client_user_time;
+}
+
+// sends the data to the performance database server
+bool PerfDbClient::sendData(std::string hashed_id, std::string test_name,
+                            std::string sys_info, std::string tag) {
+  // Data record request object
+  SingleUserRecordRequest single_user_record_request;
+
+  // setting access token, name of the test and the system information
+  single_user_record_request.set_hashed_id(hashed_id);
+  single_user_record_request.set_test_name(test_name);
+  single_user_record_request.set_sys_info(sys_info);
+  single_user_record_request.set_tag(tag);
+
+  // setting configs
+  *(single_user_record_request.mutable_client_config()) = client_config_;
+  *(single_user_record_request.mutable_server_config()) = server_config_;
+
+  Metrics* metrics = single_user_record_request.mutable_metrics();
+
+  // setting metrcs in data record request
+  if (qps_ != DBL_MIN) {
+    metrics->set_qps(qps_);
+  }
+  if (qps_per_core_ != DBL_MIN) {
+    metrics->set_qps_per_core(qps_per_core_);
+  }
+  if (perc_lat_50_ != DBL_MIN) {
+    metrics->set_perc_lat_50(perc_lat_50_);
+  }
+  if (perc_lat_90_ != DBL_MIN) {
+    metrics->set_perc_lat_90(perc_lat_90_);
+  }
+  if (perc_lat_95_ != DBL_MIN) {
+    metrics->set_perc_lat_95(perc_lat_95_);
+  }
+  if (perc_lat_99_ != DBL_MIN) {
+    metrics->set_perc_lat_99(perc_lat_99_);
+  }
+  if (perc_lat_99_point_9_ != DBL_MIN) {
+    metrics->set_perc_lat_99_point_9(perc_lat_99_point_9_);
+  }
+  if (server_system_time_ != DBL_MIN) {
+    metrics->set_server_system_time(server_system_time_);
+  }
+  if (server_user_time_ != DBL_MIN) {
+    metrics->set_server_user_time(server_user_time_);
+  }
+  if (client_system_time_ != DBL_MIN) {
+    metrics->set_client_system_time(client_system_time_);
+  }
+  if (client_user_time_ != DBL_MIN) {
+    metrics->set_client_user_time(client_user_time_);
+  }
+
+  SingleUserRecordReply single_user_record_reply;
+  ClientContext context;
+
+  Status status = stub_->RecordSingleClientData(
+      &context, single_user_record_request, &single_user_record_reply);
+  if (status.ok()) {
+    return true;  // data sent to database successfully
+  } else {
+    return false;  // error in data sending
+  }
+}
+}  // testing
+}  // grpc
diff --git a/test/cpp/qps/perf_db_client.h b/test/cpp/qps/perf_db_client.h
new file mode 100644
index 0000000..ce7a88b
--- /dev/null
+++ b/test/cpp/qps/perf_db_client.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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 <iostream>
+#include <memory>
+#include <string>
+#include <cfloat>
+
+#include <grpc/grpc.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++/status.h>
+#include "test/cpp/qps/perf_db.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+// Manages data sending to performance database server
+class PerfDbClient {
+ public:
+  PerfDbClient() {
+    qps_ = DBL_MIN;
+    qps_per_core_ = DBL_MIN;
+    perc_lat_50_ = DBL_MIN;
+    perc_lat_90_ = DBL_MIN;
+    perc_lat_95_ = DBL_MIN;
+    perc_lat_99_ = DBL_MIN;
+    perc_lat_99_point_9_ = DBL_MIN;
+    server_system_time_ = DBL_MIN;
+    server_user_time_ = DBL_MIN;
+    client_system_time_ = DBL_MIN;
+    client_user_time_ = DBL_MIN;
+  }
+
+  void init(std::shared_ptr<ChannelInterface> channel) {
+    stub_ = PerfDbTransfer::NewStub(channel);
+  }
+
+  ~PerfDbClient() {}
+
+  // sets the client and server config information
+  void setConfigs(const ClientConfig& client_config,
+                  const ServerConfig& server_config);
+
+  // sets the qps
+  void setQps(double qps);
+
+  // sets the qps per core
+  void setQpsPerCore(double qps_per_core);
+
+  // sets the 50th, 90th, 95th, 99th and 99.9th percentile latency
+  void setLatencies(double perc_lat_50, double perc_lat_90,
+                    double perc_lat_95, double perc_lat_99,
+                    double perc_lat_99_point_9);
+
+  // sets the server and client, user and system times
+  void setTimes(double server_system_time, double server_user_time,
+                double client_system_time, double client_user_time);
+
+  // sends the data to the performance database server
+  bool sendData(std::string hashed_id, std::string test_name,
+                std::string sys_info, std::string tag);
+
+ private:
+  std::unique_ptr<PerfDbTransfer::Stub> stub_;
+  ClientConfig client_config_;
+  ServerConfig server_config_;
+  double qps_;
+  double qps_per_core_;
+  double perc_lat_50_;
+  double perc_lat_90_;
+  double perc_lat_95_;
+  double perc_lat_99_;
+  double perc_lat_99_point_9_;
+  double server_system_time_;
+  double server_user_time_;
+  double client_system_time_;
+  double client_user_time_;
+};
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/qps/qps_test_openloop.cc b/test/cpp/qps/qps_openloop_test.cc
similarity index 97%
rename from test/cpp/qps/qps_test_openloop.cc
rename to test/cpp/qps/qps_openloop_test.cc
index 52873b2..96a9b45 100644
--- a/test/cpp/qps/qps_test_openloop.cc
+++ b/test/cpp/qps/qps_openloop_test.cc
@@ -60,7 +60,7 @@
   client_config.set_rpc_type(UNARY);
   client_config.set_load_type(POISSON);
   client_config.mutable_load_params()->
-    mutable_poisson()->set_offered_load(10000.0);
+    mutable_poisson()->set_offered_load(1000.0);
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
diff --git a/test/cpp/qps/qps_test_openloop.cc b/test/cpp/qps/qps_test_with_poll.cc
similarity index 92%
copy from test/cpp/qps/qps_test_openloop.cc
copy to test/cpp/qps/qps_test_with_poll.cc
index 52873b2..90a8da8 100644
--- a/test/cpp/qps/qps_test_openloop.cc
+++ b/test/cpp/qps/qps_test_with_poll.cc
@@ -41,14 +41,18 @@
 #include "test/cpp/qps/report.h"
 #include "test/cpp/util/benchmark_config.h"
 
+extern "C" {
+#include "src/core/iomgr/pollset_posix.h"
+}
+
 namespace grpc {
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunQPS() {
-  gpr_log(GPR_INFO, "Running QPS test, open-loop");
+  gpr_log(GPR_INFO, "Running QPS test");
 
   ClientConfig client_config;
   client_config.set_client_type(ASYNC_CLIENT);
@@ -58,9 +62,6 @@
   client_config.set_payload_size(1);
   client_config.set_async_client_threads(8);
   client_config.set_rpc_type(UNARY);
-  client_config.set_load_type(POISSON);
-  client_config.mutable_load_params()->
-    mutable_poisson()->set_offered_load(10000.0);
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
@@ -80,6 +81,8 @@
 int main(int argc, char** argv) {
   grpc::testing::InitBenchmark(&argc, &argv, true);
 
+  grpc_platform_become_multipoller = grpc_poll_become_multipoller;
+
   signal(SIGPIPE, SIG_IGN);
   grpc::testing::RunQPS();
 
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index 423275e..f1cea5e 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -31,7 +31,7 @@
  *
  */
 
-#include "qps_worker.h"
+#include "test/cpp/qps/qps_worker.h"
 
 #include <cassert>
 #include <memory>
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index 678ea08..ff01ec1 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -43,49 +43,47 @@
   reporters_.emplace_back(std::move(reporter));
 }
 
-void CompositeReporter::ReportQPS(const ScenarioResult& result) const {
+void CompositeReporter::ReportQPS(const ScenarioResult& result) {
   for (size_t i = 0; i < reporters_.size(); ++i) {
     reporters_[i]->ReportQPS(result);
   }
 }
 
-void CompositeReporter::ReportQPSPerCore(const ScenarioResult& result) const {
+void CompositeReporter::ReportQPSPerCore(const ScenarioResult& result) {
   for (size_t i = 0; i < reporters_.size(); ++i) {
     reporters_[i]->ReportQPSPerCore(result);
   }
 }
 
-void CompositeReporter::ReportLatency(const ScenarioResult& result) const {
+void CompositeReporter::ReportLatency(const ScenarioResult& result) {
   for (size_t i = 0; i < reporters_.size(); ++i) {
     reporters_[i]->ReportLatency(result);
   }
 }
 
-void CompositeReporter::ReportTimes(const ScenarioResult& result) const {
+void CompositeReporter::ReportTimes(const ScenarioResult& result) {
   for (size_t i = 0; i < reporters_.size(); ++i) {
     reporters_[i]->ReportTimes(result);
   }
 }
 
-
-void GprLogReporter::ReportQPS(const ScenarioResult& result) const {
+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; }));
 }
 
-void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result)  const {
-  auto qps =
-      result.latencies.Count() /
-      average(result.client_resources,
-          [](ResourceUsage u) { return u.wall_time; });
+void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) {
+  auto qps = result.latencies.Count() /
+             average(result.client_resources,
+                     [](ResourceUsage u) { return u.wall_time; });
 
   gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps,
           qps / result.server_config.threads());
 }
 
-void GprLogReporter::ReportLatency(const ScenarioResult& result) const {
+void GprLogReporter::ReportLatency(const ScenarioResult& result) {
   gpr_log(GPR_INFO,
           "Latencies (50/90/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f/%.1f us",
           result.latencies.Percentile(50) / 1000,
@@ -95,7 +93,7 @@
           result.latencies.Percentile(99.9) / 1000);
 }
 
-void GprLogReporter::ReportTimes(const ScenarioResult& result) const {
+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; }) /
@@ -118,5 +116,71 @@
                   [](ResourceUsage u) { return u.wall_time; }));
 }
 
+void PerfDbReporter::ReportQPS(const ScenarioResult& result) {
+  auto qps = result.latencies.Count() /
+             average(result.client_resources,
+                     [](ResourceUsage u) { return u.wall_time; });
+
+  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 qpsPerCore = qps / result.server_config.threads();
+
+  perf_db_client_.setQps(qps);
+  perf_db_client_.setQpsPerCore(qpsPerCore);
+  perf_db_client_.setConfigs(result.client_config, result.server_config);
+}
+
+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);
+  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; });
+
+  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);
+}
+
+void PerfDbReporter::SendData() {
+  // send data to performance database
+  bool data_state =
+      perf_db_client_.sendData(hashed_id_, test_name_, sys_info_, tag_);
+
+  // check state of data sending
+  if (data_state) {
+    gpr_log(GPR_INFO, "Data sent to performance database successfully");
+  } else {
+    gpr_log(GPR_INFO, "Data could not be sent to performance database");
+  }
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index 0cce088..aec3cbe 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -41,6 +41,7 @@
 
 #include "test/cpp/qps/driver.h"
 #include "test/cpp/qps/qpstest.grpc.pb.h"
+#include "test/cpp/qps/perf_db_client.h"
 
 namespace grpc {
 namespace testing {
@@ -59,16 +60,16 @@
   string name() const { return name_; }
 
   /** Reports QPS for the given \a result. */
-  virtual void ReportQPS(const ScenarioResult& result) const = 0;
+  virtual void ReportQPS(const ScenarioResult& result) = 0;
 
   /** Reports QPS per core as (YYY/server core). */
-  virtual void ReportQPSPerCore(const ScenarioResult& result) const = 0;
+  virtual void ReportQPSPerCore(const ScenarioResult& result) = 0;
 
   /** Reports latencies for the 50, 90, 95, 99 and 99.9 percentiles, in ms. */
-  virtual void ReportLatency(const ScenarioResult& result) const = 0;
+  virtual void ReportLatency(const ScenarioResult& result) = 0;
 
   /** Reports system and user time for client and server systems. */
-  virtual void ReportTimes(const ScenarioResult& result) const = 0;
+  virtual void ReportTimes(const ScenarioResult& result) = 0;
 
  private:
   const string name_;
@@ -82,10 +83,10 @@
   /** Adds a \a reporter to the composite. */
   void add(std::unique_ptr<Reporter> reporter);
 
-  void ReportQPS(const ScenarioResult& result) const GRPC_OVERRIDE;
-  void ReportQPSPerCore(const ScenarioResult& result) const GRPC_OVERRIDE;
-  void ReportLatency(const ScenarioResult& result) const GRPC_OVERRIDE;
-  void ReportTimes(const ScenarioResult& result) const GRPC_OVERRIDE;
+  void ReportQPS(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportQPSPerCore(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportLatency(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportTimes(const ScenarioResult& result) GRPC_OVERRIDE;
 
  private:
   std::vector<std::unique_ptr<Reporter> > reporters_;
@@ -97,10 +98,39 @@
   GprLogReporter(const string& name) : Reporter(name) {}
 
  private:
-  void ReportQPS(const ScenarioResult& result) const GRPC_OVERRIDE;
-  void ReportQPSPerCore(const ScenarioResult& result) const GRPC_OVERRIDE;
-  void ReportLatency(const ScenarioResult& result) const GRPC_OVERRIDE;
-  void ReportTimes(const ScenarioResult& result) const GRPC_OVERRIDE;
+  void ReportQPS(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportQPSPerCore(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportLatency(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportTimes(const ScenarioResult& result) GRPC_OVERRIDE;
+};
+
+/** Reporter for performance database tool */
+class PerfDbReporter : public Reporter {
+ public:
+  PerfDbReporter(const string& name, const string& hashed_id,
+                 const string& test_name, const string& sys_info,
+                 const string& server_address, const string& tag)
+      : Reporter(name),
+        hashed_id_(hashed_id),
+        test_name_(test_name),
+        sys_info_(sys_info),
+        tag_(tag) {
+    perf_db_client_.init(grpc::CreateChannel(
+        server_address, grpc::InsecureCredentials(), ChannelArguments()));
+  }
+  ~PerfDbReporter() GRPC_OVERRIDE { SendData(); };
+
+ private:
+  PerfDbClient perf_db_client_;
+  std::string hashed_id_;
+  std::string test_name_;
+  std::string sys_info_;
+  std::string tag_;
+  void ReportQPS(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportQPSPerCore(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportLatency(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportTimes(const ScenarioResult& result) GRPC_OVERRIDE;
+  void SendData();
 };
 
 }  // namespace testing
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 210aef4..846f8f3 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -45,6 +45,7 @@
 #include <grpc/support/host_port.h>
 #include <grpc++/async_unary_call.h>
 #include <grpc++/config.h>
+#include <grpc++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -52,7 +53,6 @@
 #include <grpc++/status.h>
 #include <grpc++/stream.h>
 #include <gtest/gtest.h>
-#include "src/cpp/server/thread_pool.h"
 #include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/server.h"
 
@@ -64,7 +64,7 @@
 
 class AsyncQpsServerTest : public Server {
  public:
-  AsyncQpsServerTest(const ServerConfig &config, int port) : shutdown_(false) {
+  AsyncQpsServerTest(const ServerConfig &config, int port) {
     char *server_address = NULL;
     gpr_join_host_port(&server_address, "::", port);
 
@@ -80,7 +80,7 @@
     server_ = builder.BuildAndStart();
 
     using namespace std::placeholders;
-    for (int i = 0; i < 10; i++) {
+    for (int i = 0; i < 10000 / config.threads(); i++) {
       for (int j = 0; j < config.threads(); j++) {
         auto request_unary = std::bind(
             &TestService::AsyncService::RequestUnaryCall, &async_service_, _1,
@@ -97,6 +97,9 @@
       }
     }
     for (int i = 0; i < config.threads(); i++) {
+      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;
@@ -105,11 +108,9 @@
           ServerRpcContext *ctx = detag(got_tag);
           // The tag is a pointer to an RPC context to invoke
           bool still_going = ctx->RunNextState(ok);
-          std::unique_lock<std::mutex> g(shutdown_mutex_);
-          if (!shutdown_) {
+          if (!shutdown_state_[i]->shutdown()) {
             // this RPC context is done, so refresh it
             if (!still_going) {
-              g.unlock();
               ctx->Reset();
             }
           } else {
@@ -122,9 +123,8 @@
   }
   ~AsyncQpsServerTest() {
     server_->Shutdown();
-    {
-      std::lock_guard<std::mutex> g(shutdown_mutex_);
-      shutdown_ = true;
+    for (auto ss = shutdown_state_.begin(); ss != shutdown_state_.end(); ++ss) {
+      (*ss)->set_shutdown();
     }
     for (auto thr = threads_.begin(); thr != threads_.end(); thr++) {
       thr->join();
@@ -316,8 +316,25 @@
   TestService::AsyncService async_service_;
   std::forward_list<ServerRpcContext *> contexts_;
 
-  std::mutex shutdown_mutex_;
-  bool shutdown_;
+  class PerThreadShutdownState {
+   public:
+    PerThreadShutdownState() : shutdown_(false) {}
+
+    bool shutdown() const {
+      std::lock_guard<std::mutex> lock(mutex_);
+      return shutdown_;
+    }
+
+    void set_shutdown() {
+      std::lock_guard<std::mutex> lock(mutex_);
+      shutdown_ = true;
+    }
+
+   private:
+    mutable std::mutex mutex_;
+    bool shutdown_;
+  };
+  std::vector<std::unique_ptr<PerThreadShutdownState>> shutdown_state_;
 };
 
 std::unique_ptr<Server> CreateAsyncServer(const ServerConfig &config,
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index bc00de9..d90ff22 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -40,13 +40,13 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc++/config.h>
+#include <grpc++/fixed_size_thread_pool.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 <grpc++/stream.h>
-#include "src/cpp/server/thread_pool.h"
 #include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/server.h"
 #include "test/cpp/qps/timer.h"
@@ -111,7 +111,7 @@
   }
 
   TestServiceImpl service_;
-  ThreadPool thread_pool_;
+  FixedSizeThreadPool thread_pool_;
   std::unique_ptr<grpc::Server> impl_;
 };
 
diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc
index d1b6bc1..07289f6 100644
--- a/test/cpp/qps/timer.cc
+++ b/test/cpp/qps/timer.cc
@@ -41,7 +41,7 @@
 Timer::Timer() : start_(Sample()) {}
 
 double Timer::Now() {
-  auto ts = gpr_now();
+  auto ts = gpr_now(GPR_CLOCK_REALTIME);
   return ts.tv_sec + 1e-9 * ts.tv_nsec;
 }
 
diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc
index dfc102f..7cf4903 100644
--- a/test/cpp/qps/worker.cc
+++ b/test/cpp/qps/worker.cc
@@ -40,7 +40,7 @@
 #include <grpc/support/time.h>
 #include <gflags/gflags.h>
 
-#include "qps_worker.h"
+#include "test/cpp/qps/qps_worker.h"
 #include "test/cpp/util/test_config.h"
 
 DEFINE_int32(driver_port, 0, "Driver server port.");
@@ -57,7 +57,8 @@
   QpsWorker worker(FLAGS_driver_port, FLAGS_server_port);
 
   while (!got_sigint) {
-    gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+    gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                 gpr_time_from_seconds(5, GPR_TIMESPAN)));
   }
 }
 
diff --git a/test/cpp/server/thread_pool_test.cc b/test/cpp/server/fixed_size_thread_pool_test.cc
similarity index 89%
rename from test/cpp/server/thread_pool_test.cc
rename to test/cpp/server/fixed_size_thread_pool_test.cc
index 824d785..442e974 100644
--- a/test/cpp/server/thread_pool_test.cc
+++ b/test/cpp/server/fixed_size_thread_pool_test.cc
@@ -35,17 +35,17 @@
 #include <functional>
 #include <mutex>
 
-#include "src/cpp/server/thread_pool.h"
+#include <grpc++/fixed_size_thread_pool.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
 
-class ThreadPoolTest : public ::testing::Test {
+class FixedSizeThreadPoolTest : public ::testing::Test {
  public:
-  ThreadPoolTest() : thread_pool_(4) {}
+  FixedSizeThreadPoolTest() : thread_pool_(4) {}
 
  protected:
-  ThreadPool thread_pool_;
+  FixedSizeThreadPool thread_pool_;
 };
 
 void Callback(std::mutex* mu, std::condition_variable* cv, bool* done) {
@@ -54,12 +54,12 @@
   cv->notify_all();
 }
 
-TEST_F(ThreadPoolTest, ScheduleCallback) {
+TEST_F(FixedSizeThreadPoolTest, Add) {
   std::mutex mu;
   std::condition_variable cv;
   bool done = false;
   std::function<void()> callback = std::bind(Callback, &mu, &cv, &done);
-  thread_pool_.ScheduleCallback(callback);
+  thread_pool_.Add(callback);
 
   // Wait for the callback to finish.
   std::unique_lock<std::mutex> lock(mu);
diff --git a/test/cpp/util/benchmark_config.cc b/test/cpp/util/benchmark_config.cc
index 5b3c1da..91fbbf9 100644
--- a/test/cpp/util/benchmark_config.cc
+++ b/test/cpp/util/benchmark_config.cc
@@ -37,6 +37,18 @@
 DEFINE_bool(enable_log_reporter, true,
             "Enable reporting of benchmark results through GprLog");
 
+DEFINE_bool(report_metrics_db, false, "True if metrics to be reported to performance database");
+
+DEFINE_string(hashed_id, "", "Hash of the user id");
+
+DEFINE_string(test_name, "", "Name of the test being executed");
+
+DEFINE_string(sys_info, "", "System information");
+
+DEFINE_string(server_address, "localhost:50052", "Address of the performance database server");
+
+DEFINE_string(tag, "", "Optional tag for the test");
+
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
 namespace google {}
@@ -57,6 +69,12 @@
     composite_reporter->add(
         std::unique_ptr<Reporter>(new GprLogReporter("LogReporter")));
   }
+  if(FLAGS_report_metrics_db) {
+    composite_reporter->add(
+      std::unique_ptr<Reporter>(new PerfDbReporter("PerfDbReporter", FLAGS_hashed_id, FLAGS_test_name, 
+        FLAGS_sys_info, FLAGS_server_address, FLAGS_tag)));
+  }
+
   return std::shared_ptr<Reporter>(composite_reporter);
 }
 
diff --git a/test/cpp/util/byte_buffer_test.cc b/test/cpp/util/byte_buffer_test.cc
new file mode 100644
index 0000000..13eb497
--- /dev/null
+++ b/test/cpp/util/byte_buffer_test.cc
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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 <grpc++/byte_buffer.h>
+
+#include <cstring>
+#include <vector>
+
+#include <grpc/support/slice.h>
+#include <grpc++/slice.h>
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace {
+
+const char* kContent1 = "hello xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char* kContent2 = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy world";
+
+class ByteBufferTest : public ::testing::Test {
+};
+
+TEST_F(ByteBufferTest, CreateFromSingleSlice) {
+  gpr_slice hello = gpr_slice_from_copied_string(kContent1);
+  Slice s(hello, Slice::STEAL_REF);
+  ByteBuffer buffer(&s, 1);
+}
+
+TEST_F(ByteBufferTest, CreateFromVector) {
+  gpr_slice hello = gpr_slice_from_copied_string(kContent1);
+  gpr_slice world = gpr_slice_from_copied_string(kContent2);
+  std::vector<Slice> slices;
+  slices.push_back(Slice(hello, Slice::STEAL_REF));
+  slices.push_back(Slice(world, Slice::STEAL_REF));
+  ByteBuffer buffer(&slices[0], 2);
+}
+
+TEST_F(ByteBufferTest, Clear) {
+  gpr_slice hello = gpr_slice_from_copied_string(kContent1);
+  Slice s(hello, Slice::STEAL_REF);
+  ByteBuffer buffer(&s, 1);
+  buffer.Clear();
+}
+
+TEST_F(ByteBufferTest, Length) {
+  gpr_slice hello = gpr_slice_from_copied_string(kContent1);
+  gpr_slice world = gpr_slice_from_copied_string(kContent2);
+  std::vector<Slice> slices;
+  slices.push_back(Slice(hello, Slice::STEAL_REF));
+  slices.push_back(Slice(world, Slice::STEAL_REF));
+  ByteBuffer buffer(&slices[0], 2);
+  EXPECT_EQ(strlen(kContent1) + strlen(kContent2), buffer.Length());
+}
+
+bool SliceEqual(const Slice& a, gpr_slice b) {
+  if (a.size() != GPR_SLICE_LENGTH(b)) {
+    return false;
+  }
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a.begin()[i] != GPR_SLICE_START_PTR(b)[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+TEST_F(ByteBufferTest, Dump) {
+  gpr_slice hello = gpr_slice_from_copied_string(kContent1);
+  gpr_slice world = gpr_slice_from_copied_string(kContent2);
+  std::vector<Slice> slices;
+  slices.push_back(Slice(hello, Slice::STEAL_REF));
+  slices.push_back(Slice(world, Slice::STEAL_REF));
+  ByteBuffer buffer(&slices[0], 2);
+  slices.clear();
+  buffer.Dump(&slices);
+  EXPECT_TRUE(SliceEqual(slices[0], hello));
+  EXPECT_TRUE(SliceEqual(slices[1], world));
+}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
index 6cf86ea..00bb821 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -34,12 +34,12 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/cli_call.h"
 #include "test/cpp/util/echo.grpc.pb.h"
-#include "src/cpp/server/thread_pool.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++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -102,7 +102,7 @@
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
   TestServiceImpl service_;
-  ThreadPool thread_pool_;
+  FixedSizeThreadPool thread_pool_;
 };
 
 // Send a rpc with a normal stub and then a CliCall. Verify they match.
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
index 32d61b0..3c3baeb 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -88,7 +88,7 @@
     return;
   }
   std::vector<grpc::string> fields;
-  grpc::string delim(":");
+  const char* delim = ":";
   size_t cur, next = -1;
   do {
     cur = next + 1;
diff --git a/test/cpp/util/messages.proto b/test/cpp/util/messages.proto
index 062f66c..3708972 100644
--- a/test/cpp/util/messages.proto
+++ b/test/cpp/util/messages.proto
@@ -37,6 +37,7 @@
   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;
 }
 
 message EchoRequest {
@@ -46,6 +47,7 @@
 
 message ResponseParams {
   optional int64 request_deadline = 1;
+  optional string host = 2;
 }
 
 message EchoResponse {
diff --git a/test/cpp/server/thread_pool_test.cc b/test/cpp/util/slice_test.cc
similarity index 67%
copy from test/cpp/server/thread_pool_test.cc
copy to test/cpp/util/slice_test.cc
index 824d785..eb32849 100644
--- a/test/cpp/server/thread_pool_test.cc
+++ b/test/cpp/util/slice_test.cc
@@ -31,47 +31,47 @@
  *
  */
 
-#include <condition_variable>
-#include <functional>
-#include <mutex>
+#include <grpc++/slice.h>
 
-#include "src/cpp/server/thread_pool.h"
+#include <grpc/support/slice.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
+namespace {
 
-class ThreadPoolTest : public ::testing::Test {
- public:
-  ThreadPoolTest() : thread_pool_(4) {}
+const char* kContent = "hello xxxxxxxxxxxxxxxxxxxx world";
 
+class SliceTest : public ::testing::Test {
  protected:
-  ThreadPool thread_pool_;
+  void CheckSlice(const Slice& s, const grpc::string& content) {
+    EXPECT_EQ(content.size(), s.size());
+    EXPECT_EQ(content,
+              grpc::string(reinterpret_cast<const char*>(s.begin()), s.size()));
+  }
 };
 
-void Callback(std::mutex* mu, std::condition_variable* cv, bool* done) {
-  std::unique_lock<std::mutex> lock(*mu);
-  *done = true;
-  cv->notify_all();
+TEST_F(SliceTest, Steal) {
+  gpr_slice s = gpr_slice_from_copied_string(kContent);
+  Slice spp(s, Slice::STEAL_REF);
+  CheckSlice(spp, kContent);
 }
 
-TEST_F(ThreadPoolTest, ScheduleCallback) {
-  std::mutex mu;
-  std::condition_variable cv;
-  bool done = false;
-  std::function<void()> callback = std::bind(Callback, &mu, &cv, &done);
-  thread_pool_.ScheduleCallback(callback);
-
-  // Wait for the callback to finish.
-  std::unique_lock<std::mutex> lock(mu);
-  while (!done) {
-    cv.wait(lock);
-  }
+TEST_F(SliceTest, Add) {
+  gpr_slice s = gpr_slice_from_copied_string(kContent);
+  Slice spp(s, Slice::ADD_REF);
+  gpr_slice_unref(s);
+  CheckSlice(spp, kContent);
 }
 
+TEST_F(SliceTest, Empty) {
+  Slice empty_slice;
+  CheckSlice(empty_slice, "");
+}
+
+}  // namespace
 }  // namespace grpc
 
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
-  int result = RUN_ALL_TESTS();
-  return result;
+  return RUN_ALL_TESTS();
 }
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index a3cfb1c..4cb6ec4 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -46,7 +46,8 @@
 
 TEST_F(TimeTest, AbsolutePointTest) {
   long us = 10000000L;
-  gpr_timespec ts = gpr_time_from_micros(us);
+  gpr_timespec ts = gpr_time_from_micros(us, GPR_TIMESPAN);
+  ts.clock_type = GPR_CLOCK_REALTIME;
   system_clock::time_point tp{microseconds(us)};
   system_clock::time_point tp_converted = Timespec2Timepoint(ts);
   gpr_timespec ts_converted;
@@ -61,15 +62,17 @@
 // gpr_inf_future is treated specially and mapped to/from time_point::max()
 TEST_F(TimeTest, InfFuture) {
   EXPECT_EQ(system_clock::time_point::max(),
-            Timespec2Timepoint(gpr_inf_future));
+            Timespec2Timepoint(gpr_inf_future(GPR_CLOCK_REALTIME)));
   gpr_timespec from_time_point_max;
   Timepoint2Timespec(system_clock::time_point::max(), &from_time_point_max);
-  EXPECT_EQ(0, gpr_time_cmp(gpr_inf_future, from_time_point_max));
+  EXPECT_EQ(
+      0, gpr_time_cmp(gpr_inf_future(GPR_CLOCK_REALTIME), from_time_point_max));
   // This will cause an overflow
   Timepoint2Timespec(
       std::chrono::time_point<system_clock, std::chrono::seconds>::max(),
       &from_time_point_max);
-  EXPECT_EQ(0, gpr_time_cmp(gpr_inf_future, from_time_point_max));
+  EXPECT_EQ(
+      0, gpr_time_cmp(gpr_inf_future(GPR_CLOCK_REALTIME), from_time_point_max));
 }
 
 }  // namespace
diff --git a/test/proto/messages.proto b/test/proto/messages.proto
index 65a8140..500e79c 100644
--- a/test/proto/messages.proto
+++ b/test/proto/messages.proto
@@ -46,6 +46,14 @@
   RANDOM = 2;
 }
 
+// Compression algorithms
+enum CompressionType {
+  // No compression
+  NONE = 0;
+  GZIP = 1;
+  DEFLATE = 2;
+}
+
 // A block of data, to simply increase gRPC message size.
 message Payload {
   // The type of data in body.
@@ -54,6 +62,13 @@
   optional 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;
+}
+
 // Unary request.
 message SimpleRequest {
   // Desired payload type in the response from the server.
@@ -72,6 +87,12 @@
 
   // Whether SimpleResponse should include OAuth scope.
   optional bool fill_oauth_scope = 5;
+
+  // Compression algorithm to be used by the server for the response (stream)
+  optional CompressionType response_compression = 6;
+
+  // Whether server should return a given status
+  optional EchoStatus response_status = 7;
 }
 
 // Unary response, as configured by the request.
@@ -123,6 +144,12 @@
 
   // Optional input payload sent along with the request.
   optional Payload payload = 3;
+
+  // Compression algorithm to be used by the server for the response (stream)
+  optional CompressionType response_compression = 6;
+
+  // Whether server should return a given status
+  optional EchoStatus response_status = 7;
 }
 
 // Server-streaming response, as configured by the request and parameters.
diff --git a/test/proto/test.proto b/test/proto/test.proto
index b9483d8..1214152 100644
--- a/test/proto/test.proto
+++ b/test/proto/test.proto
@@ -71,3 +71,11 @@
   rpc HalfDuplexCall(stream StreamingOutputCallRequest)
       returns (stream StreamingOutputCallResponse);
 }
+
+
+// A simple service NOT implemented at servers so clients can test for
+// that case.
+service UnimplementedService {
+  // A call that no server should implement
+  rpc UnimplementedCall(grpc.testing.Empty) returns(grpc.testing.Empty);  
+}
diff --git a/tools/buildgen/generate_projects.py b/tools/buildgen/generate_projects.py
new file mode 100755
index 0000000..5de0635
--- /dev/null
+++ b/tools/buildgen/generate_projects.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+import glob
+import os
+import sys
+import tempfile
+sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..', 'run_tests'))
+
+assert sys.argv[1:], 'run generate_projects.sh instead of this directly'
+
+import jobset
+
+os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..', '..'))
+json = sys.argv[1:]
+
+test = {} if 'TEST' in os.environ else None
+
+plugins = sorted(glob.glob('tools/buildgen/plugins/*.py'))
+
+jobs = []
+for root, dirs, files in os.walk('templates'):
+  for f in files:
+    if os.path.splitext(f)[1] == '.template':
+      out_dir = '.' + root[len('templates'):]
+      out = out_dir + '/' + os.path.splitext(f)[0]
+      if not os.path.exists(out_dir):
+        os.makedirs(out_dir)
+      cmd = ['tools/buildgen/mako_renderer.py']
+      for plugin in plugins:
+        cmd.append('-p')
+        cmd.append(plugin)
+      for js in json:
+        cmd.append('-d')
+        cmd.append(js)
+      cmd.append('-o')
+      if test is None:
+        cmd.append(out)
+      else:
+        tf = tempfile.mkstemp()
+        test[out] = tf[1]
+        os.close(tf[0])
+        cmd.append(test[out])
+      cmd.append(root + '/' + f)
+      jobs.append(jobset.JobSpec(cmd, shortname=out))
+
+jobset.run(jobs)
+
+if test is not None:
+  for s, g in test.iteritems():
+    assert(0 == os.system('diff %s %s' % (s, g)))
+    os.unlink(g)
diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh
index 5399867..32fc90f 100755
--- a/tools/buildgen/generate_projects.sh
+++ b/tools/buildgen/generate_projects.sh
@@ -45,32 +45,6 @@
 
 . tools/buildgen/generate_build_additions.sh
 
-global_plugins=`find ./tools/buildgen/plugins -name '*.py' |
-  sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
-
-for dir in . ; do
-  local_plugins=`find $dir/templates -name '*.py' |
-    sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
-
-  plugins="$global_plugins $local_plugins"
-
-  find -L $dir/templates -type f -and -name *.template | while read file ; do
-    out=${dir}/${file#$dir/templates/}  # strip templates dir prefix
-    out=${out%.*}  # strip template extension
-    echo "generating file: $out"
-    json_files="build.json $gen_build_files"
-    data=`for i in $json_files ; do echo $i ; done | awk ' { printf "-d %s ", $0 } '`
-    if [ "x$TEST" = "xtrue" ] ; then
-      actual_out=$out
-      out=`mktemp /tmp/gentXXXXXX`
-    fi
-    mkdir -p `dirname $out`  # make sure dest directory exist
-    $mako_renderer $plugins $data -o $out $file
-    if [ "x$TEST" = "xtrue" ] ; then
-      diff -q $out $actual_out
-      rm $out
-    fi
-  done
-done
+tools/buildgen/generate_projects.py build.json $gen_build_files
 
 rm $gen_build_files
diff --git a/src/core/transport/chttp2/gen_hpack_tables.c b/tools/codegen/core/gen_hpack_tables.c
similarity index 91%
rename from src/core/transport/chttp2/gen_hpack_tables.c
rename to tools/codegen/core/gen_hpack_tables.c
index bdaa3cf..555f1e7 100644
--- a/src/core/transport/chttp2/gen_hpack_tables.c
+++ b/tools/codegen/core/gen_hpack_tables.c
@@ -55,19 +55,15 @@
   unsigned char index;
 } spec;
 
-static const spec fields[] = {{"INDEXED_FIELD", 0X80, 1, 1},
-                              {"INDEXED_FIELD_X", 0X80, 1, 2},
-                              {"LITHDR_INCIDX", 0X40, 2, 1},
-                              {"LITHDR_INCIDX_X", 0X40, 2, 2},
-                              {"LITHDR_INCIDX_V", 0X40, 2, 0},
-                              {"LITHDR_NOTIDX", 0X00, 4, 1},
-                              {"LITHDR_NOTIDX_X", 0X00, 4, 2},
-                              {"LITHDR_NOTIDX_V", 0X00, 4, 0},
-                              {"LITHDR_NVRIDX", 0X10, 4, 1},
-                              {"LITHDR_NVRIDX_X", 0X10, 4, 2},
-                              {"LITHDR_NVRIDX_V", 0X10, 4, 0},
-                              {"MAX_TBL_SIZE", 0X20, 3, 1},
-                              {"MAX_TBL_SIZE_X", 0X20, 3, 2}, };
+static const spec fields[] = {
+    {"INDEXED_FIELD", 0X80, 1, 1},   {"INDEXED_FIELD_X", 0X80, 1, 2},
+    {"LITHDR_INCIDX", 0X40, 2, 1},   {"LITHDR_INCIDX_X", 0X40, 2, 2},
+    {"LITHDR_INCIDX_V", 0X40, 2, 0}, {"LITHDR_NOTIDX", 0X00, 4, 1},
+    {"LITHDR_NOTIDX_X", 0X00, 4, 2}, {"LITHDR_NOTIDX_V", 0X00, 4, 0},
+    {"LITHDR_NVRIDX", 0X10, 4, 1},   {"LITHDR_NVRIDX_X", 0X10, 4, 2},
+    {"LITHDR_NVRIDX_V", 0X10, 4, 0}, {"MAX_TBL_SIZE", 0X20, 3, 1},
+    {"MAX_TBL_SIZE_X", 0X20, 3, 2},
+};
 
 static const int num_fields = sizeof(fields) / sizeof(*fields);
 
@@ -129,13 +125,9 @@
 #define MAXHUFFSTATES 1024
 
 /* represents a set of symbols as an array of booleans indicating inclusion */
-typedef struct {
-  char included[GRPC_CHTTP2_NUM_HUFFSYMS];
-} symset;
+typedef struct { char included[GRPC_CHTTP2_NUM_HUFFSYMS]; } symset;
 /* represents a lookup table indexed by a nibble */
-typedef struct {
-  int values[16];
-} nibblelut;
+typedef struct { int values[16]; } nibblelut;
 
 /* returns a symset that includes all possible symbols */
 static symset symset_all(void) {
@@ -268,8 +260,7 @@
     /* recurse down for this bit */
     build_dec_tbl(state, (nibble << 1) | bit, nibbits + 1, bitofs + 1, emit,
                   nextsyms);
-  next:
-    ;
+  next:;
   }
 }
 
diff --git a/tools/distrib/python/submit.py b/tools/distrib/python/submit.py
index dd48f44..a3615b3 100755
--- a/tools/distrib/python/submit.py
+++ b/tools/distrib/python/submit.py
@@ -66,6 +66,12 @@
 except:
   pass
 
+# Build the Cython C files
+build_env = os.environ.copy()
+build_env['GRPC_PYTHON_BUILD_WITH_CYTHON'] = "1"
+cmd = ['python', 'setup.py', 'build_ext', '--inplace']
+subprocess.call(cmd, cwd=pkgdir, env=build_env)
+
 # Make the push.
 cmd = ['python', 'setup.py', 'sdist']
 subprocess.call(cmd, cwd=pkgdir)
diff --git a/tools/dockerfile/grpc_java/Dockerfile b/tools/dockerfile/grpc_java/Dockerfile
index 15fce27..7b1fe56 100644
--- a/tools/dockerfile/grpc_java/Dockerfile
+++ b/tools/dockerfile/grpc_java/Dockerfile
@@ -30,10 +30,8 @@
 # Dockerfile for the gRPC Java dev image
 FROM grpc/java_base
 
-RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git /var/local/git/grpc-java
-RUN cd /var/local/git/grpc-java/lib/netty && \
-  mvn -pl codec-http2 -am -DskipTests install clean
-RUN cd /var/local/git/grpc-java && \
+RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git /var/local/git/grpc-java && \
+  cd /var/local/git/grpc-java && \
   ./gradlew :grpc-interop-testing:installDist -PskipCodegen=true
 
 # Add a service_account directory containing the auth creds file
diff --git a/tools/dockerfile/grpc_java_android/Dockerfile b/tools/dockerfile/grpc_java_android/Dockerfile
index 2dc2202..8df0707 100644
--- a/tools/dockerfile/grpc_java_android/Dockerfile
+++ b/tools/dockerfile/grpc_java_android/Dockerfile
@@ -43,27 +43,20 @@
 # Some old Docker versions consider '/' as HOME
 ENV HOME /root
 
-# Update sdk for android 5.1 (API level 22)
-RUN echo y | android update sdk --all --filter platform-tools,build-tools-22.0.1,sys-img-armeabi-v7a-addon-google_apis-google-22,sys-img-armeabi-v7a-addon-google_apis-google-21,sys-img-armeabi-v7a-android-19,addon-google_apis-google-22,addon-google_apis-google-21,addon-google_apis-google-19,extra-android-m2repository,extra-google-m2repository --no-ui --force
+# Update sdk for android API level 19 (4.4), 21 (5.0), 22 (5.1).
+RUN echo y | android update sdk --all --filter platform-tools,build-tools-22.0.1,sys-img-armeabi-v7a-addon-google_apis-google-22,sys-img-armeabi-v7a-addon-google_apis-google-21,sys-img-armeabi-v7a-android-19,android-22,android-21,android-19,addon-google_apis-google-22,addon-google_apis-google-21,addon-google_apis-google-19,extra-android-m2repository,extra-google-m2repository --no-ui --force
 
 
-# Create an AVD with API level 22
-RUN echo no | android create avd --force -n avd-google-api-22 -t "Google Inc.:Google APIs:22" --abi google_apis/armeabi-v7a
-RUN echo no | android create avd --force -n avd-google-api-21 -t "Google Inc.:Google APIs:21" --abi google_apis/armeabi-v7a
-RUN echo no | android create avd --force -n avd-google-api-19 -t "Google Inc.:Google APIs:19" --abi default/armeabi-v7a
+# Create AVDs with API level 19,21,22
+RUN echo no | android create avd --force -n avd-google-api-22 -t "Google Inc.:Google APIs:22" --abi google_apis/armeabi-v7a && \
+  echo no | android create avd --force -n avd-google-api-21 -t "Google Inc.:Google APIs:21" --abi google_apis/armeabi-v7a && \
+  echo no | android create avd --force -n avd-google-api-19 -t "Google Inc.:Google APIs:19" --abi default/armeabi-v7a
 
 # Pull gRPC Java and trigger download of needed Maven and Gradle artifacts.
 RUN git clone --depth 1 https://github.com/grpc/grpc-java.git /var/local/git/grpc-java && \
   cd /var/local/git/grpc-java && \
-  ./gradlew grpc-core:install grpc-stub:install grpc-okhttp:install grpc-protobuf-nano:install && \
-  rm -r "$(pwd)"
+  ./gradlew grpc-core:install grpc-stub:install grpc-okhttp:install grpc-protobuf-nano:install grpc-compiler:install
 
-# Pull gRPC Android integration test App
-RUN git clone --depth 1 https://github.com/madongfly/grpc-android-test.git /var/local/git/grpc-android-test
-
-# Config android sdk for gradle
-RUN cd /var/local/git/grpc-android-test && echo "sdk.dir=/usr/local/android-sdk-linux" > local.properties
-
-# Build apks to trigger download of needed Maven and Gradle artifacts.
-RUN cd /var/local/git/grpc-android-test && ./gradlew assembleDebug
-RUN cd /var/local/git/grpc-android-test && ./gradlew assembleDebugAndroidTest
+# Config android sdk for gradle and build apk to trigger download of needed Maven and Gradle artifacts.
+RUN cd /var/local/git/grpc-java/android-interop-testing && echo "sdk.dir=/usr/local/android-sdk-linux" > local.properties && \
+  ../gradlew assembleDebug
diff --git a/tools/dockerfile/grpc_java_android/README.md b/tools/dockerfile/grpc_java_android/README.md
index b4c9645..5c897cd 100644
--- a/tools/dockerfile/grpc_java_android/README.md
+++ b/tools/dockerfile/grpc_java_android/README.md
@@ -15,23 +15,23 @@
 Start the emulator in a detached container, the argument is the name of the AVD you want to start:
 
 ```
-$ sudo docker run --name=grpc_android_test -d grpc/android /var/local/git/grpc-android-test/start-emulator.sh avd-api-22
+$ sudo docker run --name=grpc_android_test -d grpc/android /var/local/git/grpc-java/android-interop-testing/start-emulator.sh avd-google-api-22
 ```
 
 You can use the following cammand to wait until the emulator is ready:
 ```
-$ sudo docker exec grpc_android_test /var/local/git/grpc-android-test/wait-for-emulator.sh
+$ sudo docker exec grpc_android_test /var/local/git/grpc-java/android-interop-testing/wait-for-emulator.sh
 ```
 
 When you want to update the apk, run:
 ```
-$ sudo docker exec grpc_android_test /var/local/git/grpc-android-test/update-apk.sh
+$ sudo docker exec grpc_android_test bash -c "cd /var/local/git/grpc-java && git pull origin master && ./gradlew grpc-core:install grpc-stub:install grpc-okhttp:install grpc-protobuf-nano:install grpc-compiler:install && cd android-interop-testing && ../gradlew installDebug"
 ```
-It will pull the fresh code of gRpc Java and our integration test app from github, build and install it to the runing emulator (so you need to make sure there is a runing emulator).
+It pulls the fresh code of gRpc Java and our interop test app from github, build and install it to the runing emulator (so you need to make sure there is a runing emulator).
 
 Trigger the integration test:
 ```
-$ sudo docker exec grpc_android_test /var/local/git/grpc-android-test/run-test.sh -e server_host <hostname or ip address> -e server_port 8030 -e server_host_override foo.test.google.fr -e use_tls true -e use_test_ca true
+$ sudo docker exec grpc_android_test adb -e shell am instrument -w -e server_host <hostname or ip address> -e server_port 8030 -e server_host_override foo.test.google.fr -e use_tls true -e use_test_ca true -e test_case all io.grpc.android.integrationtest/.TesterInstrumentation
 ```
 
 You can also use the android/adb cammands to get more info, such as:
diff --git a/tools/dockerfile/grpc_java_base/Dockerfile b/tools/dockerfile/grpc_java_base/Dockerfile
index 55fbe94..7bf79c8 100644
--- a/tools/dockerfile/grpc_java_base/Dockerfile
+++ b/tools/dockerfile/grpc_java_base/Dockerfile
@@ -44,20 +44,11 @@
       && \
   apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
 
-# Install maven
-RUN wget -O - http://mirror.olnevhost.net/pub/apache/maven/binaries/apache-maven-3.2.1-bin.tar.gz | \
-  tar xz -C /var/local
-
 ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
-ENV M2_HOME /var/local/apache-maven-3.2.1
-ENV PATH $PATH:$JAVA_HOME/bin:$M2_HOME/bin
-ENV LD_LIBRARY_PATH /usr/local/lib
+ENV PATH $PATH:$JAVA_HOME/bin
 
-# Trigger download of as many Maven and Gradle artifacts as possible. We don't build grpc-java
-# because we don't want to install netty
+# Trigger download of as many Gradle artifacts as possible.
 RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && \
-  cd grpc-java/lib/netty && \
-  mvn -pl codec-http2 -am -DskipTests verify && \
-  cd ../.. && \
-  ./gradlew && \
+  cd grpc-java && \
+  ./gradlew build -PskipCodegen=true && \
   rm -r "$(pwd)"
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 5616f2c..4bdd8ba 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -760,7 +760,46 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc++/async_generic_service.h include/grpc++/async_unary_call.h include/grpc++/byte_buffer.h include/grpc++/channel_arguments.h include/grpc++/channel_interface.h include/grpc++/client_context.h include/grpc++/completion_queue.h include/grpc++/config.h include/grpc++/create_channel.h include/grpc++/credentials.h include/grpc++/generic_stub.h include/grpc++/impl/call.h include/grpc++/impl/client_unary_call.h include/grpc++/impl/grpc_library.h include/grpc++/impl/internal_stub.h include/grpc++/impl/rpc_method.h include/grpc++/impl/rpc_service_method.h include/grpc++/impl/service_type.h include/grpc++/impl/sync.h include/grpc++/impl/sync_cxx11.h include/grpc++/impl/sync_no_cxx11.h include/grpc++/impl/thd.h include/grpc++/impl/thd_cxx11.h include/grpc++/impl/thd_no_cxx11.h include/grpc++/server.h include/grpc++/server_builder.h include/grpc++/server_context.h include/grpc++/server_credentials.h include/grpc++/slice.h include/grpc++/status.h include/grpc++/status_code_enum.h include/grpc++/stream.h include/grpc++/thread_pool_interface.h include/grpc++/time.h
+INPUT                  = include/grpc++/async_generic_service.h \
+include/grpc++/async_unary_call.h \
+include/grpc++/auth_context.h \
+include/grpc++/auth_property_iterator.h \
+include/grpc++/byte_buffer.h \
+include/grpc++/channel_arguments.h \
+include/grpc++/channel_interface.h \
+include/grpc++/client_context.h \
+include/grpc++/completion_queue.h \
+include/grpc++/config.h \
+include/grpc++/config_protobuf.h \
+include/grpc++/create_channel.h \
+include/grpc++/credentials.h \
+include/grpc++/fixed_size_thread_pool.h \
+include/grpc++/generic_stub.h \
+include/grpc++/impl/call.h \
+include/grpc++/impl/client_unary_call.h \
+include/grpc++/impl/grpc_library.h \
+include/grpc++/impl/internal_stub.h \
+include/grpc++/impl/proto_utils.h \
+include/grpc++/impl/rpc_method.h \
+include/grpc++/impl/rpc_service_method.h \
+include/grpc++/impl/serialization_traits.h \
+include/grpc++/impl/service_type.h \
+include/grpc++/impl/sync.h \
+include/grpc++/impl/sync_cxx11.h \
+include/grpc++/impl/sync_no_cxx11.h \
+include/grpc++/impl/thd.h \
+include/grpc++/impl/thd_cxx11.h \
+include/grpc++/impl/thd_no_cxx11.h \
+include/grpc++/server.h \
+include/grpc++/server_builder.h \
+include/grpc++/server_context.h \
+include/grpc++/server_credentials.h \
+include/grpc++/slice.h \
+include/grpc++/status.h \
+include/grpc++/status_code_enum.h \
+include/grpc++/stream.h \
+include/grpc++/thread_pool_interface.h \
+include/grpc++/time.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 6d32327..1c73ca6 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -760,7 +760,81 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc++/async_generic_service.h include/grpc++/async_unary_call.h include/grpc++/byte_buffer.h include/grpc++/channel_arguments.h include/grpc++/channel_interface.h include/grpc++/client_context.h include/grpc++/completion_queue.h include/grpc++/config.h include/grpc++/create_channel.h include/grpc++/credentials.h include/grpc++/generic_stub.h include/grpc++/impl/call.h include/grpc++/impl/client_unary_call.h include/grpc++/impl/grpc_library.h include/grpc++/impl/internal_stub.h include/grpc++/impl/rpc_method.h include/grpc++/impl/rpc_service_method.h include/grpc++/impl/service_type.h include/grpc++/impl/sync.h include/grpc++/impl/sync_cxx11.h include/grpc++/impl/sync_no_cxx11.h include/grpc++/impl/thd.h include/grpc++/impl/thd_cxx11.h include/grpc++/impl/thd_no_cxx11.h include/grpc++/server.h include/grpc++/server_builder.h include/grpc++/server_context.h include/grpc++/server_credentials.h include/grpc++/slice.h include/grpc++/status.h include/grpc++/status_code_enum.h include/grpc++/stream.h include/grpc++/thread_pool_interface.h include/grpc++/time.h src/cpp/client/secure_credentials.h src/cpp/server/secure_server_credentials.h src/cpp/client/channel.h src/cpp/proto/proto_utils.h src/cpp/server/thread_pool.h src/cpp/client/secure_credentials.cc src/cpp/server/secure_server_credentials.cc src/cpp/client/channel.cc src/cpp/client/channel_arguments.cc src/cpp/client/client_context.cc src/cpp/client/client_unary_call.cc src/cpp/client/create_channel.cc src/cpp/client/credentials.cc src/cpp/client/generic_stub.cc src/cpp/client/insecure_credentials.cc src/cpp/client/internal_stub.cc src/cpp/common/call.cc src/cpp/common/completion_queue.cc src/cpp/common/rpc_method.cc src/cpp/proto/proto_utils.cc src/cpp/server/async_generic_service.cc src/cpp/server/create_default_thread_pool.cc src/cpp/server/insecure_server_credentials.cc src/cpp/server/server.cc src/cpp/server/server_builder.cc src/cpp/server/server_context.cc src/cpp/server/server_credentials.cc src/cpp/server/thread_pool.cc src/cpp/util/byte_buffer.cc src/cpp/util/slice.cc src/cpp/util/status.cc src/cpp/util/time.cc
+INPUT                  = include/grpc++/async_generic_service.h \
+include/grpc++/async_unary_call.h \
+include/grpc++/auth_context.h \
+include/grpc++/auth_property_iterator.h \
+include/grpc++/byte_buffer.h \
+include/grpc++/channel_arguments.h \
+include/grpc++/channel_interface.h \
+include/grpc++/client_context.h \
+include/grpc++/completion_queue.h \
+include/grpc++/config.h \
+include/grpc++/config_protobuf.h \
+include/grpc++/create_channel.h \
+include/grpc++/credentials.h \
+include/grpc++/fixed_size_thread_pool.h \
+include/grpc++/generic_stub.h \
+include/grpc++/impl/call.h \
+include/grpc++/impl/client_unary_call.h \
+include/grpc++/impl/grpc_library.h \
+include/grpc++/impl/internal_stub.h \
+include/grpc++/impl/proto_utils.h \
+include/grpc++/impl/rpc_method.h \
+include/grpc++/impl/rpc_service_method.h \
+include/grpc++/impl/serialization_traits.h \
+include/grpc++/impl/service_type.h \
+include/grpc++/impl/sync.h \
+include/grpc++/impl/sync_cxx11.h \
+include/grpc++/impl/sync_no_cxx11.h \
+include/grpc++/impl/thd.h \
+include/grpc++/impl/thd_cxx11.h \
+include/grpc++/impl/thd_no_cxx11.h \
+include/grpc++/server.h \
+include/grpc++/server_builder.h \
+include/grpc++/server_context.h \
+include/grpc++/server_credentials.h \
+include/grpc++/slice.h \
+include/grpc++/status.h \
+include/grpc++/status_code_enum.h \
+include/grpc++/stream.h \
+include/grpc++/thread_pool_interface.h \
+include/grpc++/time.h \
+src/cpp/client/secure_credentials.h \
+src/cpp/common/secure_auth_context.h \
+src/cpp/server/secure_server_credentials.h \
+src/cpp/client/channel.h \
+src/cpp/common/create_auth_context.h \
+src/cpp/client/secure_channel_arguments.cc \
+src/cpp/client/secure_credentials.cc \
+src/cpp/common/auth_property_iterator.cc \
+src/cpp/common/secure_auth_context.cc \
+src/cpp/common/secure_create_auth_context.cc \
+src/cpp/server/secure_server_credentials.cc \
+src/cpp/client/channel.cc \
+src/cpp/client/channel_arguments.cc \
+src/cpp/client/client_context.cc \
+src/cpp/client/create_channel.cc \
+src/cpp/client/credentials.cc \
+src/cpp/client/generic_stub.cc \
+src/cpp/client/insecure_credentials.cc \
+src/cpp/client/internal_stub.cc \
+src/cpp/common/call.cc \
+src/cpp/common/completion_queue.cc \
+src/cpp/common/rpc_method.cc \
+src/cpp/proto/proto_utils.cc \
+src/cpp/server/async_generic_service.cc \
+src/cpp/server/create_default_thread_pool.cc \
+src/cpp/server/fixed_size_thread_pool.cc \
+src/cpp/server/insecure_server_credentials.cc \
+src/cpp/server/server.cc \
+src/cpp/server/server_builder.cc \
+src/cpp/server/server_context.cc \
+src/cpp/server/server_credentials.cc \
+src/cpp/util/byte_buffer.cc \
+src/cpp/util/slice.cc \
+src/cpp/util/status.cc \
+src/cpp/util/time.cc
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index 7cc96b2..1bfd787 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -760,7 +760,41 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/grpc_security.h include/grpc/byte_buffer.h include/grpc/byte_buffer_reader.h include/grpc/compression.h include/grpc/grpc.h include/grpc/status.h include/grpc/census.h include/grpc/support/alloc.h include/grpc/support/atm.h 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 include/grpc/support/host_port.h include/grpc/support/log.h include/grpc/support/log_win32.h include/grpc/support/port_platform.h include/grpc/support/slice.h include/grpc/support/slice_buffer.h include/grpc/support/string_util.h include/grpc/support/subprocess.h include/grpc/support/sync.h include/grpc/support/sync_generic.h include/grpc/support/sync_posix.h include/grpc/support/sync_win32.h include/grpc/support/thd.h include/grpc/support/time.h include/grpc/support/tls.h include/grpc/support/tls_gcc.h include/grpc/support/tls_msvc.h include/grpc/support/tls_pthread.h include/grpc/support/useful.h
+INPUT                  = include/grpc/grpc_security.h \
+include/grpc/byte_buffer.h \
+include/grpc/byte_buffer_reader.h \
+include/grpc/compression.h \
+include/grpc/grpc.h \
+include/grpc/status.h \
+include/grpc/census.h \
+include/grpc/support/alloc.h \
+include/grpc/support/atm.h \
+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 \
+include/grpc/support/host_port.h \
+include/grpc/support/log.h \
+include/grpc/support/log_win32.h \
+include/grpc/support/port_platform.h \
+include/grpc/support/slice.h \
+include/grpc/support/slice_buffer.h \
+include/grpc/support/string_util.h \
+include/grpc/support/subprocess.h \
+include/grpc/support/sync.h \
+include/grpc/support/sync_generic.h \
+include/grpc/support/sync_posix.h \
+include/grpc/support/sync_win32.h \
+include/grpc/support/thd.h \
+include/grpc/support/time.h \
+include/grpc/support/tls.h \
+include/grpc/support/tls_gcc.h \
+include/grpc/support/tls_msvc.h \
+include/grpc/support/tls_pthread.h \
+include/grpc/support/useful.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index c1c4b9f..31ad56a 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -760,7 +760,335 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/grpc_security.h include/grpc/byte_buffer.h include/grpc/byte_buffer_reader.h include/grpc/compression.h include/grpc/grpc.h include/grpc/status.h include/grpc/census.h src/core/httpcli/format_request.h src/core/httpcli/httpcli.h src/core/httpcli/httpcli_security_connector.h src/core/httpcli/parser.h src/core/security/auth_filters.h src/core/security/base64.h src/core/security/credentials.h src/core/security/json_token.h src/core/security/secure_endpoint.h src/core/security/secure_transport_setup.h src/core/security/security_connector.h src/core/security/security_context.h src/core/tsi/fake_transport_security.h src/core/tsi/ssl_transport_security.h src/core/tsi/transport_security.h src/core/tsi/transport_security_interface.h src/core/census/grpc_context.h src/core/channel/census_filter.h src/core/channel/channel_args.h src/core/channel/channel_stack.h src/core/channel/child_channel.h src/core/channel/client_channel.h src/core/channel/client_setup.h src/core/channel/connected_channel.h src/core/channel/context.h src/core/channel/http_client_filter.h src/core/channel/http_server_filter.h src/core/channel/noop_filter.h src/core/compression/message_compress.h src/core/debug/trace.h src/core/iomgr/alarm.h src/core/iomgr/alarm_heap.h src/core/iomgr/alarm_internal.h src/core/iomgr/endpoint.h src/core/iomgr/endpoint_pair.h src/core/iomgr/fd_posix.h src/core/iomgr/iocp_windows.h src/core/iomgr/iomgr.h src/core/iomgr/iomgr_internal.h src/core/iomgr/iomgr_posix.h src/core/iomgr/pollset.h src/core/iomgr/pollset_kick.h src/core/iomgr/pollset_kick_posix.h src/core/iomgr/pollset_kick_windows.h src/core/iomgr/pollset_posix.h src/core/iomgr/pollset_windows.h src/core/iomgr/resolve_address.h src/core/iomgr/sockaddr.h src/core/iomgr/sockaddr_posix.h src/core/iomgr/sockaddr_utils.h src/core/iomgr/sockaddr_win32.h src/core/iomgr/socket_utils_posix.h src/core/iomgr/socket_windows.h src/core/iomgr/tcp_client.h src/core/iomgr/tcp_posix.h src/core/iomgr/tcp_server.h src/core/iomgr/tcp_windows.h src/core/iomgr/time_averaged_stats.h src/core/iomgr/wakeup_fd_pipe.h src/core/iomgr/wakeup_fd_posix.h src/core/json/json.h src/core/json/json_common.h src/core/json/json_reader.h src/core/json/json_writer.h src/core/profiling/timers.h src/core/profiling/timers_preciseclock.h src/core/surface/byte_buffer_queue.h src/core/surface/call.h src/core/surface/channel.h src/core/surface/client.h src/core/surface/completion_queue.h src/core/surface/event_string.h src/core/surface/init.h src/core/surface/server.h src/core/surface/surface_trace.h src/core/transport/chttp2/alpn.h src/core/transport/chttp2/bin_encoder.h src/core/transport/chttp2/frame.h src/core/transport/chttp2/frame_data.h src/core/transport/chttp2/frame_goaway.h src/core/transport/chttp2/frame_ping.h src/core/transport/chttp2/frame_rst_stream.h src/core/transport/chttp2/frame_settings.h src/core/transport/chttp2/frame_window_update.h src/core/transport/chttp2/hpack_parser.h src/core/transport/chttp2/hpack_table.h src/core/transport/chttp2/http2_errors.h src/core/transport/chttp2/huffsyms.h src/core/transport/chttp2/status_conversion.h src/core/transport/chttp2/stream_encoder.h src/core/transport/chttp2/stream_map.h src/core/transport/chttp2/timeout_encoding.h src/core/transport/chttp2/varint.h src/core/transport/chttp2_transport.h src/core/transport/metadata.h src/core/transport/stream_op.h src/core/transport/transport.h src/core/transport/transport_impl.h src/core/census/context.h src/core/httpcli/format_request.c src/core/httpcli/httpcli.c src/core/httpcli/httpcli_security_connector.c src/core/httpcli/parser.c src/core/security/base64.c src/core/security/client_auth_filter.c src/core/security/credentials.c src/core/security/credentials_metadata.c src/core/security/credentials_posix.c src/core/security/credentials_win32.c src/core/security/google_default_credentials.c src/core/security/json_token.c src/core/security/secure_endpoint.c src/core/security/secure_transport_setup.c src/core/security/security_connector.c src/core/security/security_context.c src/core/security/server_auth_filter.c src/core/security/server_secure_chttp2.c src/core/surface/init_secure.c src/core/surface/secure_channel_create.c src/core/tsi/fake_transport_security.c src/core/tsi/ssl_transport_security.c src/core/tsi/transport_security.c src/core/census/grpc_context.c src/core/channel/channel_args.c src/core/channel/channel_stack.c src/core/channel/child_channel.c src/core/channel/client_channel.c src/core/channel/client_setup.c src/core/channel/connected_channel.c src/core/channel/http_client_filter.c src/core/channel/http_server_filter.c src/core/channel/noop_filter.c src/core/compression/algorithm.c src/core/compression/message_compress.c src/core/debug/trace.c src/core/iomgr/alarm.c src/core/iomgr/alarm_heap.c src/core/iomgr/endpoint.c src/core/iomgr/endpoint_pair_posix.c src/core/iomgr/endpoint_pair_windows.c src/core/iomgr/fd_posix.c src/core/iomgr/iocp_windows.c src/core/iomgr/iomgr.c src/core/iomgr/iomgr_posix.c src/core/iomgr/iomgr_windows.c src/core/iomgr/pollset_kick.c src/core/iomgr/pollset_multipoller_with_epoll.c src/core/iomgr/pollset_multipoller_with_poll_posix.c src/core/iomgr/pollset_posix.c src/core/iomgr/pollset_windows.c src/core/iomgr/resolve_address_posix.c src/core/iomgr/resolve_address_windows.c src/core/iomgr/sockaddr_utils.c src/core/iomgr/socket_utils_common_posix.c src/core/iomgr/socket_utils_linux.c src/core/iomgr/socket_utils_posix.c src/core/iomgr/socket_windows.c src/core/iomgr/tcp_client_posix.c src/core/iomgr/tcp_client_windows.c src/core/iomgr/tcp_posix.c src/core/iomgr/tcp_server_posix.c src/core/iomgr/tcp_server_windows.c src/core/iomgr/tcp_windows.c src/core/iomgr/time_averaged_stats.c src/core/iomgr/wakeup_fd_eventfd.c src/core/iomgr/wakeup_fd_nospecial.c src/core/iomgr/wakeup_fd_pipe.c src/core/iomgr/wakeup_fd_posix.c src/core/json/json.c src/core/json/json_reader.c src/core/json/json_string.c src/core/json/json_writer.c src/core/profiling/basic_timers.c src/core/profiling/stap_timers.c src/core/surface/byte_buffer.c src/core/surface/byte_buffer_queue.c src/core/surface/byte_buffer_reader.c src/core/surface/call.c src/core/surface/call_details.c src/core/surface/call_log_batch.c src/core/surface/channel.c src/core/surface/channel_create.c src/core/surface/client.c src/core/surface/completion_queue.c src/core/surface/event_string.c src/core/surface/init.c src/core/surface/lame_client.c src/core/surface/metadata_array.c src/core/surface/server.c src/core/surface/server_chttp2.c src/core/surface/server_create.c src/core/surface/surface_trace.c src/core/transport/chttp2/alpn.c src/core/transport/chttp2/bin_encoder.c src/core/transport/chttp2/frame_data.c src/core/transport/chttp2/frame_goaway.c src/core/transport/chttp2/frame_ping.c src/core/transport/chttp2/frame_rst_stream.c src/core/transport/chttp2/frame_settings.c src/core/transport/chttp2/frame_window_update.c src/core/transport/chttp2/hpack_parser.c src/core/transport/chttp2/hpack_table.c src/core/transport/chttp2/huffsyms.c src/core/transport/chttp2/status_conversion.c src/core/transport/chttp2/stream_encoder.c src/core/transport/chttp2/stream_map.c src/core/transport/chttp2/timeout_encoding.c src/core/transport/chttp2/varint.c src/core/transport/chttp2_transport.c src/core/transport/metadata.c src/core/transport/stream_op.c src/core/transport/transport.c src/core/transport/transport_op_string.c src/core/census/context.c src/core/census/initialize.c include/grpc/support/alloc.h include/grpc/support/atm.h 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 include/grpc/support/host_port.h include/grpc/support/log.h include/grpc/support/log_win32.h include/grpc/support/port_platform.h include/grpc/support/slice.h include/grpc/support/slice_buffer.h include/grpc/support/string_util.h include/grpc/support/subprocess.h include/grpc/support/sync.h include/grpc/support/sync_generic.h include/grpc/support/sync_posix.h include/grpc/support/sync_win32.h include/grpc/support/thd.h include/grpc/support/time.h include/grpc/support/tls.h include/grpc/support/tls_gcc.h include/grpc/support/tls_msvc.h include/grpc/support/tls_pthread.h include/grpc/support/useful.h src/core/support/env.h src/core/support/file.h src/core/support/murmur_hash.h src/core/support/string.h 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 src/core/support/cpu_posix.c src/core/support/cpu_windows.c src/core/support/env_linux.c src/core/support/env_posix.c src/core/support/env_win32.c src/core/support/file.c src/core/support/file_posix.c src/core/support/file_win32.c src/core/support/histogram.c src/core/support/host_port.c src/core/support/log.c src/core/support/log_android.c src/core/support/log_linux.c src/core/support/log_posix.c src/core/support/log_win32.c src/core/support/murmur_hash.c src/core/support/slice.c src/core/support/slice_buffer.c src/core/support/string.c src/core/support/string_posix.c src/core/support/string_win32.c src/core/support/subprocess_posix.c src/core/support/sync.c src/core/support/sync_posix.c src/core/support/sync_win32.c src/core/support/thd.c src/core/support/thd_posix.c src/core/support/thd_win32.c src/core/support/time.c src/core/support/time_posix.c src/core/support/time_win32.c src/core/support/tls_pthread.c
+INPUT                  = include/grpc/grpc_security.h \
+include/grpc/byte_buffer.h \
+include/grpc/byte_buffer_reader.h \
+include/grpc/compression.h \
+include/grpc/grpc.h \
+include/grpc/status.h \
+include/grpc/census.h \
+src/core/httpcli/format_request.h \
+src/core/httpcli/httpcli.h \
+src/core/httpcli/httpcli_security_connector.h \
+src/core/httpcli/parser.h \
+src/core/security/auth_filters.h \
+src/core/security/base64.h \
+src/core/security/credentials.h \
+src/core/security/json_token.h \
+src/core/security/jwt_verifier.h \
+src/core/security/secure_endpoint.h \
+src/core/security/secure_transport_setup.h \
+src/core/security/security_connector.h \
+src/core/security/security_context.h \
+src/core/tsi/fake_transport_security.h \
+src/core/tsi/ssl_transport_security.h \
+src/core/tsi/transport_security.h \
+src/core/tsi/transport_security_interface.h \
+src/core/census/grpc_context.h \
+src/core/channel/census_filter.h \
+src/core/channel/channel_args.h \
+src/core/channel/channel_stack.h \
+src/core/channel/client_channel.h \
+src/core/channel/compress_filter.h \
+src/core/channel/connected_channel.h \
+src/core/channel/context.h \
+src/core/channel/http_client_filter.h \
+src/core/channel/http_server_filter.h \
+src/core/channel/noop_filter.h \
+src/core/client_config/client_config.h \
+src/core/client_config/connector.h \
+src/core/client_config/lb_policies/pick_first.h \
+src/core/client_config/lb_policy.h \
+src/core/client_config/resolver.h \
+src/core/client_config/resolver_factory.h \
+src/core/client_config/resolver_registry.h \
+src/core/client_config/resolvers/dns_resolver.h \
+src/core/client_config/resolvers/unix_resolver_posix.h \
+src/core/client_config/subchannel.h \
+src/core/client_config/subchannel_factory.h \
+src/core/client_config/uri_parser.h \
+src/core/compression/message_compress.h \
+src/core/debug/trace.h \
+src/core/iomgr/alarm.h \
+src/core/iomgr/alarm_heap.h \
+src/core/iomgr/alarm_internal.h \
+src/core/iomgr/endpoint.h \
+src/core/iomgr/endpoint_pair.h \
+src/core/iomgr/fd_posix.h \
+src/core/iomgr/iocp_windows.h \
+src/core/iomgr/iomgr.h \
+src/core/iomgr/iomgr_internal.h \
+src/core/iomgr/iomgr_posix.h \
+src/core/iomgr/pollset.h \
+src/core/iomgr/pollset_kick_posix.h \
+src/core/iomgr/pollset_posix.h \
+src/core/iomgr/pollset_set.h \
+src/core/iomgr/pollset_set_posix.h \
+src/core/iomgr/pollset_set_windows.h \
+src/core/iomgr/pollset_windows.h \
+src/core/iomgr/resolve_address.h \
+src/core/iomgr/sockaddr.h \
+src/core/iomgr/sockaddr_posix.h \
+src/core/iomgr/sockaddr_utils.h \
+src/core/iomgr/sockaddr_win32.h \
+src/core/iomgr/socket_utils_posix.h \
+src/core/iomgr/socket_windows.h \
+src/core/iomgr/tcp_client.h \
+src/core/iomgr/tcp_posix.h \
+src/core/iomgr/tcp_server.h \
+src/core/iomgr/tcp_windows.h \
+src/core/iomgr/time_averaged_stats.h \
+src/core/iomgr/wakeup_fd_pipe.h \
+src/core/iomgr/wakeup_fd_posix.h \
+src/core/json/json.h \
+src/core/json/json_common.h \
+src/core/json/json_reader.h \
+src/core/json/json_writer.h \
+src/core/profiling/timers.h \
+src/core/profiling/timers_preciseclock.h \
+src/core/surface/byte_buffer_queue.h \
+src/core/surface/call.h \
+src/core/surface/channel.h \
+src/core/surface/completion_queue.h \
+src/core/surface/event_string.h \
+src/core/surface/init.h \
+src/core/surface/server.h \
+src/core/surface/surface_trace.h \
+src/core/transport/chttp2/alpn.h \
+src/core/transport/chttp2/bin_encoder.h \
+src/core/transport/chttp2/frame.h \
+src/core/transport/chttp2/frame_data.h \
+src/core/transport/chttp2/frame_goaway.h \
+src/core/transport/chttp2/frame_ping.h \
+src/core/transport/chttp2/frame_rst_stream.h \
+src/core/transport/chttp2/frame_settings.h \
+src/core/transport/chttp2/frame_window_update.h \
+src/core/transport/chttp2/hpack_parser.h \
+src/core/transport/chttp2/hpack_table.h \
+src/core/transport/chttp2/http2_errors.h \
+src/core/transport/chttp2/huffsyms.h \
+src/core/transport/chttp2/incoming_metadata.h \
+src/core/transport/chttp2/internal.h \
+src/core/transport/chttp2/status_conversion.h \
+src/core/transport/chttp2/stream_encoder.h \
+src/core/transport/chttp2/stream_map.h \
+src/core/transport/chttp2/timeout_encoding.h \
+src/core/transport/chttp2/varint.h \
+src/core/transport/chttp2_transport.h \
+src/core/transport/connectivity_state.h \
+src/core/transport/metadata.h \
+src/core/transport/stream_op.h \
+src/core/transport/transport.h \
+src/core/transport/transport_impl.h \
+src/core/census/context.h \
+src/core/httpcli/format_request.c \
+src/core/httpcli/httpcli.c \
+src/core/httpcli/httpcli_security_connector.c \
+src/core/httpcli/parser.c \
+src/core/security/base64.c \
+src/core/security/client_auth_filter.c \
+src/core/security/credentials.c \
+src/core/security/credentials_metadata.c \
+src/core/security/credentials_posix.c \
+src/core/security/credentials_win32.c \
+src/core/security/google_default_credentials.c \
+src/core/security/json_token.c \
+src/core/security/jwt_verifier.c \
+src/core/security/secure_endpoint.c \
+src/core/security/secure_transport_setup.c \
+src/core/security/security_connector.c \
+src/core/security/security_context.c \
+src/core/security/server_auth_filter.c \
+src/core/security/server_secure_chttp2.c \
+src/core/surface/init_secure.c \
+src/core/surface/secure_channel_create.c \
+src/core/tsi/fake_transport_security.c \
+src/core/tsi/ssl_transport_security.c \
+src/core/tsi/transport_security.c \
+src/core/census/grpc_context.c \
+src/core/channel/channel_args.c \
+src/core/channel/channel_stack.c \
+src/core/channel/client_channel.c \
+src/core/channel/compress_filter.c \
+src/core/channel/connected_channel.c \
+src/core/channel/http_client_filter.c \
+src/core/channel/http_server_filter.c \
+src/core/channel/noop_filter.c \
+src/core/client_config/client_config.c \
+src/core/client_config/connector.c \
+src/core/client_config/lb_policies/pick_first.c \
+src/core/client_config/lb_policy.c \
+src/core/client_config/resolver.c \
+src/core/client_config/resolver_factory.c \
+src/core/client_config/resolver_registry.c \
+src/core/client_config/resolvers/dns_resolver.c \
+src/core/client_config/resolvers/unix_resolver_posix.c \
+src/core/client_config/subchannel.c \
+src/core/client_config/subchannel_factory.c \
+src/core/client_config/uri_parser.c \
+src/core/compression/algorithm.c \
+src/core/compression/message_compress.c \
+src/core/debug/trace.c \
+src/core/iomgr/alarm.c \
+src/core/iomgr/alarm_heap.c \
+src/core/iomgr/endpoint.c \
+src/core/iomgr/endpoint_pair_posix.c \
+src/core/iomgr/endpoint_pair_windows.c \
+src/core/iomgr/fd_posix.c \
+src/core/iomgr/iocp_windows.c \
+src/core/iomgr/iomgr.c \
+src/core/iomgr/iomgr_posix.c \
+src/core/iomgr/iomgr_windows.c \
+src/core/iomgr/pollset_kick_posix.c \
+src/core/iomgr/pollset_multipoller_with_epoll.c \
+src/core/iomgr/pollset_multipoller_with_poll_posix.c \
+src/core/iomgr/pollset_posix.c \
+src/core/iomgr/pollset_set_posix.c \
+src/core/iomgr/pollset_set_windows.c \
+src/core/iomgr/pollset_windows.c \
+src/core/iomgr/resolve_address_posix.c \
+src/core/iomgr/resolve_address_windows.c \
+src/core/iomgr/sockaddr_utils.c \
+src/core/iomgr/socket_utils_common_posix.c \
+src/core/iomgr/socket_utils_linux.c \
+src/core/iomgr/socket_utils_posix.c \
+src/core/iomgr/socket_windows.c \
+src/core/iomgr/tcp_client_posix.c \
+src/core/iomgr/tcp_client_windows.c \
+src/core/iomgr/tcp_posix.c \
+src/core/iomgr/tcp_server_posix.c \
+src/core/iomgr/tcp_server_windows.c \
+src/core/iomgr/tcp_windows.c \
+src/core/iomgr/time_averaged_stats.c \
+src/core/iomgr/wakeup_fd_eventfd.c \
+src/core/iomgr/wakeup_fd_nospecial.c \
+src/core/iomgr/wakeup_fd_pipe.c \
+src/core/iomgr/wakeup_fd_posix.c \
+src/core/json/json.c \
+src/core/json/json_reader.c \
+src/core/json/json_string.c \
+src/core/json/json_writer.c \
+src/core/profiling/basic_timers.c \
+src/core/profiling/stap_timers.c \
+src/core/surface/byte_buffer.c \
+src/core/surface/byte_buffer_queue.c \
+src/core/surface/byte_buffer_reader.c \
+src/core/surface/call.c \
+src/core/surface/call_details.c \
+src/core/surface/call_log_batch.c \
+src/core/surface/channel.c \
+src/core/surface/channel_create.c \
+src/core/surface/completion_queue.c \
+src/core/surface/event_string.c \
+src/core/surface/init.c \
+src/core/surface/lame_client.c \
+src/core/surface/metadata_array.c \
+src/core/surface/server.c \
+src/core/surface/server_chttp2.c \
+src/core/surface/server_create.c \
+src/core/surface/surface_trace.c \
+src/core/surface/version.c \
+src/core/transport/chttp2/alpn.c \
+src/core/transport/chttp2/bin_encoder.c \
+src/core/transport/chttp2/frame_data.c \
+src/core/transport/chttp2/frame_goaway.c \
+src/core/transport/chttp2/frame_ping.c \
+src/core/transport/chttp2/frame_rst_stream.c \
+src/core/transport/chttp2/frame_settings.c \
+src/core/transport/chttp2/frame_window_update.c \
+src/core/transport/chttp2/hpack_parser.c \
+src/core/transport/chttp2/hpack_table.c \
+src/core/transport/chttp2/huffsyms.c \
+src/core/transport/chttp2/incoming_metadata.c \
+src/core/transport/chttp2/parsing.c \
+src/core/transport/chttp2/status_conversion.c \
+src/core/transport/chttp2/stream_encoder.c \
+src/core/transport/chttp2/stream_lists.c \
+src/core/transport/chttp2/stream_map.c \
+src/core/transport/chttp2/timeout_encoding.c \
+src/core/transport/chttp2/varint.c \
+src/core/transport/chttp2/writing.c \
+src/core/transport/chttp2_transport.c \
+src/core/transport/connectivity_state.c \
+src/core/transport/metadata.c \
+src/core/transport/stream_op.c \
+src/core/transport/transport.c \
+src/core/transport/transport_op_string.c \
+src/core/census/context.c \
+src/core/census/initialize.c \
+include/grpc/support/alloc.h \
+include/grpc/support/atm.h \
+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 \
+include/grpc/support/host_port.h \
+include/grpc/support/log.h \
+include/grpc/support/log_win32.h \
+include/grpc/support/port_platform.h \
+include/grpc/support/slice.h \
+include/grpc/support/slice_buffer.h \
+include/grpc/support/string_util.h \
+include/grpc/support/subprocess.h \
+include/grpc/support/sync.h \
+include/grpc/support/sync_generic.h \
+include/grpc/support/sync_posix.h \
+include/grpc/support/sync_win32.h \
+include/grpc/support/thd.h \
+include/grpc/support/time.h \
+include/grpc/support/tls.h \
+include/grpc/support/tls_gcc.h \
+include/grpc/support/tls_msvc.h \
+include/grpc/support/tls_pthread.h \
+include/grpc/support/useful.h \
+src/core/support/env.h \
+src/core/support/file.h \
+src/core/support/murmur_hash.h \
+src/core/support/stack_lockfree.h \
+src/core/support/string.h \
+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 \
+src/core/support/cpu_posix.c \
+src/core/support/cpu_windows.c \
+src/core/support/env_linux.c \
+src/core/support/env_posix.c \
+src/core/support/env_win32.c \
+src/core/support/file.c \
+src/core/support/file_posix.c \
+src/core/support/file_win32.c \
+src/core/support/histogram.c \
+src/core/support/host_port.c \
+src/core/support/log.c \
+src/core/support/log_android.c \
+src/core/support/log_linux.c \
+src/core/support/log_posix.c \
+src/core/support/log_win32.c \
+src/core/support/murmur_hash.c \
+src/core/support/slice.c \
+src/core/support/slice_buffer.c \
+src/core/support/stack_lockfree.c \
+src/core/support/string.c \
+src/core/support/string_posix.c \
+src/core/support/string_win32.c \
+src/core/support/subprocess_posix.c \
+src/core/support/sync.c \
+src/core/support/sync_posix.c \
+src/core/support/sync_win32.c \
+src/core/support/thd.c \
+src/core/support/thd_posix.c \
+src/core/support/thd_win32.c \
+src/core/support/time.c \
+src/core/support/time_posix.c \
+src/core/support/time_win32.c \
+src/core/support/tls_pthread.c
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/jenkins/docker_run_jenkins.sh b/tools/jenkins/docker_run_jenkins.sh
new file mode 100755
index 0000000..eb6c914
--- /dev/null
+++ b/tools/jenkins/docker_run_jenkins.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# 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.
+#
+# This script is invoked by run_jekins.sh when piggy-backing into docker.
+set -e
+
+export CONFIG=$config
+export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5
+export CPPFLAGS=-I/tmp/prebuilt/include
+
+mkdir -p /var/local/git
+git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
+
+cd /var/local/git/grpc
+nvm use 0.12
+rvm use ruby-2.1
+tools/run_tests/prepare_travis.sh
+$arch tools/run_tests/run_tests.py -t -c $config -l $language -x report.xml
diff --git a/tools/jenkins/grpc_jenkins_slave/Dockerfile b/tools/jenkins/grpc_jenkins_slave/Dockerfile
index 16b076c..f37c0b9 100644
--- a/tools/jenkins/grpc_jenkins_slave/Dockerfile
+++ b/tools/jenkins/grpc_jenkins_slave/Dockerfile
@@ -136,5 +136,7 @@
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
+RUN mkdir /var/local/jenkins
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/jenkins/grpc_linuxbrew/Dockerfile b/tools/jenkins/grpc_linuxbrew/Dockerfile
new file mode 100644
index 0000000..848489e
--- /dev/null
+++ b/tools/jenkins/grpc_linuxbrew/Dockerfile
@@ -0,0 +1,62 @@
+# 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.
+
+# A work-in-progress Dockerfile that allows running gRPC homebrew
+# installations inside docker containers
+FROM debian:jessie
+
+# Core dependencies
+RUN apt-get update && apt-get install -y \
+  bzip2 curl git ruby wget
+
+# Install linuxbrew
+ENV PATH /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
+RUN git clone https://github.com/Homebrew/linuxbrew.git /home/linuxbrew/.linuxbrew
+RUN brew doctor || true
+
+# Python dependency
+RUN apt-get update && apt-get install -y python-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python
+
+# NodeJS dependency
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12"
+
+# Ruby dependency
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN /bin/bash -l -c "\curl -sSL https://get.rvm.io | bash -s stable"
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+
+# PHP dependency
+RUN apt-get update && apt-get install -y php5 php5-dev php-pear phpunit unzip
+
+RUN /bin/bash -l -c "echo 'export PATH=/home/linuxbrew/.linuxbrew/bin:\$PATH' >> ~/.bashrc"
+
+CMD ["bash"]
diff --git a/tools/jenkins/run_distribution.sh b/tools/jenkins/run_distribution.sh
new file mode 100755
index 0000000..fd31869
--- /dev/null
+++ b/tools/jenkins/run_distribution.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+# 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.
+#
+# This script is invoked by Jenkins and triggers a test run of
+# linuxbrew installation of a selected language
+set -ex
+
+if [ "$platform" == "linux" ]; then
+
+  if [ "$dist_channel" == "homebrew" ]; then
+
+    sha1=$(sha1sum tools/jenkins/grpc_linuxbrew/Dockerfile | cut -f1 -d\ )
+    DOCKER_IMAGE_NAME=grpc_linuxbrew_$sha1
+
+    docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_linuxbrew
+
+    supported="python nodejs ruby php"
+
+    if [ "$language" == "core" ]; then
+      command="curl -fsSL https://goo.gl/getgrpc | bash -"
+    elif [[ "$supported" =~ "$language" ]]; then
+      command="curl -fsSL https://goo.gl/getgrpc | bash -s $language"
+    else
+      echo "unsupported language $language"
+      exit 1
+    fi
+
+    docker run $DOCKER_IMAGE_NAME bash -l \
+      -c "nvm use 0.12; \
+          npm set unsafe-perm true; \
+          rvm use ruby-2.1; \
+          $command"
+
+  else
+    echo "Unsupported $platform dist_channel $dist_channel"
+    exit 1
+  fi
+
+elif [ "$platform" == "macos" ]; then
+
+  if [ "$dist_channel" == "homebrew" ]; then
+    which brew # TODO: for debug, can be removed later
+    brew list -l
+    dir=/tmp/homebrew-test-$language
+    rm -rf $dir
+    mkdir -p $dir
+    git clone https://github.com/Homebrew/homebrew.git $dir
+    cd $dir
+    # TODO: Uncomment these when the general structure of the script is verified
+    # PATH=$dir/bin:$PATH brew tap homebrew/dupes
+    # PATH=$dir/bin:$PATH brew install zlib
+    # PATH=$dir/bin:$PATH brew install openssl
+    # PATH=$dir/bin:$PATH brew tap grpc/grpc
+    # PATH=$dir/bin:$PATH brew install --without-python google-protobuf
+    # PATH=$dir/bin:$PATH brew install grpc
+    PATH=$dir/bin:$PATH brew list -l
+    brew list -l
+    cd ~/ 
+    rm -rf $dir
+    echo $PATH # TODO: for debug, can be removed later
+    brew list -l # TODO: for debug, can be removed later
+
+  else
+    echo "Unsupported $platform dist_channel $dist_channel"
+    exit 1
+  fi
+
+else
+  echo "unsupported platform $platform"
+  exit 1
+fi
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 534ed30..8cb85cb 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -31,52 +31,60 @@
 # This script is invoked by Jenkins and triggers a test run based on
 # env variable settings.
 #
+# Setting up rvm environment BEFORE we set -ex.
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
 # To prevent cygwin bash complaining about empty lines ending with \r
 # we set the igncr option. The option doesn't exist on Linux, so we fallback
 # to just 'set -ex' there.
 # NOTE: No empty lines should appear in this file before igncr is set!
 set -ex -o igncr || set -ex
 
+# Grabbing the machine's architecture
+arch=`uname -m`
+
+case $platform in
+  i386)
+    arch="i386"
+    platform="linux"
+    ;;
+esac
+
 if [ "$platform" == "linux" ]
 then
   echo "building $language on Linux"
 
+  cd `dirname $0`/../..
+  git_root=`pwd`
+  cd -
+
   # Use image name based on Dockerfile checksum
   DOCKER_IMAGE_NAME=grpc_jenkins_slave_`sha1sum tools/jenkins/grpc_jenkins_slave/Dockerfile | cut -f1 -d\ `
 
   # Make sure docker image has been built. Should be instantaneous if so.
   docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_jenkins_slave
 
-  if [ "$ghprbPullId" != "" ]
-  then
-    # if we are building a pull request, grab corresponding refs.
-    FETCH_PULL_REQUEST_CMD="&& git fetch $GIT_URL refs/pull/$ghprbPullId/merge refs/pull/$ghprbPullId/head"
-  fi
+  # Create a local branch so the child Docker script won't complain
+  git branch jenkins-docker
 
   # Make sure the CID file is gone.
   rm -f docker.cid
 
   # Run tests inside docker
-  docker run --cidfile=docker.cid $DOCKER_IMAGE_NAME bash -c -l "git clone --recursive $GIT_URL /var/local/git/grpc \
-    && cd /var/local/git/grpc \
-    $FETCH_PULL_REQUEST_CMD \
-    && git checkout -f $GIT_COMMIT \
-    && git submodule update \
-    && nvm use 0.12 \
-    && rvm use ruby-2.1 \
-    && CONFIG=$config tools/run_tests/prepare_travis.sh \
-    && CPPFLAGS=-I/tmp/prebuilt/include tools/run_tests/run_tests.py -t -c $config -l $language" || DOCKER_FAILED="true"
+  docker run \
+    -e "config=$config" \
+    -e "language=$language" \
+    -e "arch=$arch" \
+    -i \
+    -v "$git_root:/var/local/jenkins/grpc" \
+    --cidfile=docker.cid \
+    $DOCKER_IMAGE_NAME \
+    bash -l /var/local/jenkins/grpc/tools/jenkins/docker_run_jenkins.sh || DOCKER_FAILED="true"
 
   DOCKER_CID=`cat docker.cid`
-  if [ "$DOCKER_FAILED" == "" ]
-  then
-    echo "Docker finished successfully, deleting the container $DOCKER_CID"
-    docker rm $DOCKER_CID
-  else
-    echo "Docker exited with failure, keeping container $DOCKER_CID."
-    echo "You can SSH to the worker and use 'docker commit CID YOUR_IMAGE_NAME' and 'docker run -i -t YOUR_IMAGE_NAME bash' to debug the problem."
-    exit 1
-  fi
+  docker kill $DOCKER_CID
+  docker cp $DOCKER_CID:/var/local/git/grpc/report.xml $git_root
+  sleep 4
+  docker rm $DOCKER_CID || true
 
 elif [ "$platform" == "windows" ]
 then
@@ -89,7 +97,12 @@
   /cygdrive/c/nuget/nuget.exe restore vsprojects/grpc.sln
   /cygdrive/c/nuget/nuget.exe restore src/csharp/Grpc.sln
 
-  python tools/run_tests/run_tests.py -t -l $language
+  python tools/run_tests/run_tests.py -t -l $language -x report.xml || true
+elif [ "$platform" == "macos" ]
+then
+  echo "building $language on MacOS"
+
+  ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
 else
   echo "Unknown platform $platform"
   exit 1
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index d9b7644..ae0fb42 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -34,9 +34,32 @@
 cd $(dirname $0)/../..
 
 root=`pwd`
-rm -rf python2.7_virtual_environment
-virtualenv -p /usr/bin/python2.7 python2.7_virtual_environment
-source python2.7_virtual_environment/bin/activate
-pip install -r src/python/requirements.txt
-CFLAGS="-I$root/include -std=c89 -Werror" LDFLAGS=-L$root/libs/$CONFIG pip install src/python/src
-pip install src/python/interop
+
+make_virtualenv() {
+  virtualenv_name="python"$1"_virtual_environment"
+  if [ ! -d $virtualenv_name ]
+  then
+    # Build the entire virtual environment
+    virtualenv -p `which "python"$1` $virtualenv_name
+    source $virtualenv_name/bin/activate
+    pip install -r src/python/requirements.txt
+    CFLAGS="-I$root/include -std=c89" LDFLAGS=-L$root/libs/$CONFIG GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install src/python/src
+    pip install src/python/interop
+  else
+    source $virtualenv_name/bin/activate
+    # Uninstall and re-install the packages we care about. Don't use
+    # --force-reinstall or --ignore-installed to avoid propagating this
+    # unnecessarily to dependencies. Don't use --no-deps to avoid missing
+    # dependency upgrades.
+    (yes | pip uninstall grpcio) || true
+    (yes | pip uninstall interop) || true
+    (CFLAGS="-I$root/include -std=c89" LDFLAGS=-L$root/libs/$CONFIG GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install src/python/src) || (
+      # Fall back to rebuilding the entire environment
+      rm -rf $virtualenv_name
+      make_virtualenv $1
+    )
+    pip install src/python/interop
+  fi
+}
+
+make_virtualenv $1
diff --git a/tools/run_tests/build_ruby.sh b/tools/run_tests/build_ruby.sh
index de96413..b6c4e32 100755
--- a/tools/run_tests/build_ruby.sh
+++ b/tools/run_tests/build_ruby.sh
@@ -31,7 +31,7 @@
 
 set -ex
 
-export CONFIG=${CONFIG:-opt}
+export GRPC_CONFIG=${CONFIG:-opt}
 
 # change to grpc's ruby directory
 cd $(dirname $0)/../../src/ruby
diff --git a/tools/run_tests/check_sources_and_headers.py b/tools/run_tests/check_sources_and_headers.py
new file mode 100755
index 0000000..605bded
--- /dev/null
+++ b/tools/run_tests/check_sources_and_headers.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python2.7
+
+import json
+import os
+import re
+import sys
+
+root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
+with open(os.path.join(root, 'tools', 'run_tests', 'sources_and_headers.json')) as f:
+	js = json.loads(f.read())
+
+re_inc1 = re.compile(r'^#\s*include\s*"([^"]*)"')
+assert re_inc1.match('#include "foo"').group(1) == 'foo'
+re_inc2 = re.compile(r'^#\s*include\s*<((grpc|grpc\+\+)/[^"]*)>')
+assert re_inc2.match('#include <grpc++/foo>').group(1) == 'grpc++/foo'
+
+def get_target(name):
+	for target in js:
+		if target['name'] == name:
+			return target
+	assert False, 'no target %s' % name
+
+def target_has_header(target, name):
+#	print target['name'], name
+	if name in target['headers']:
+		return True
+	for dep in target['deps']:
+		if target_has_header(get_target(dep), name):
+			return True
+	if name == 'src/core/profiling/stap_probes.h':
+		return True
+	return False
+
+errors = 0
+for target in js:
+	for fn in target['src']:
+		with open(os.path.join(root, fn)) as f:
+			src = f.read().splitlines()
+		for line in src:
+			m = re_inc1.match(line)
+			if m:
+				if not target_has_header(target, m.group(1)):
+					print (
+						'target %s (%s) does not name header %s as a dependency' % (
+							target['name'], fn, m.group(1)))
+					errors += 1
+			m = re_inc2.match(line)
+			if m:
+				if not target_has_header(target, 'include/' + m.group(1)):
+					print (
+						'target %s (%s) does not name header %s as a dependency' % (
+							target['name'], fn, m.group(1)))
+					errors += 1
+
+assert errors == 0
\ No newline at end of file
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index 058a30d..46137f0 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -34,10 +34,12 @@
 import os
 import platform
 import signal
+import string
 import subprocess
 import sys
 import tempfile
 import time
+import xml.etree.cElementTree as ET
 
 
 _DEFAULT_MAX_JOBS = 16 * multiprocessing.cpu_count()
@@ -79,6 +81,7 @@
 
 _TAG_COLOR = {
     'FAILED': 'red',
+    'WARNING': 'yellow',
     'TIMEOUT': 'red',
     'PASSED': 'green',
     'START': 'gray',
@@ -93,7 +96,7 @@
     return
   message.old_tag = tag
   message.old_msg = msg
-  if platform.system() == 'Windows':
+  if platform.system() == 'Windows' or not sys.stdout.isatty():
     if explanatory_text:
       print explanatory_text
     print '%s: %s' % (tag, msg)
@@ -159,7 +162,7 @@
 class Job(object):
   """Manages one job."""
 
-  def __init__(self, spec, bin_hash, newline_on_success, travis):
+  def __init__(self, spec, bin_hash, newline_on_success, travis, xml_report):
     self._spec = spec
     self._bin_hash = bin_hash
     self._tempfile = tempfile.TemporaryFile()
@@ -176,30 +179,42 @@
     self._state = _RUNNING
     self._newline_on_success = newline_on_success
     self._travis = travis
+    self._xml_test = ET.SubElement(xml_report, 'testcase',
+                                   name=self._spec.shortname) if xml_report is not None else None
     message('START', spec.shortname, do_newline=self._travis)
 
   def state(self, update_cache):
     """Poll current state of the job. Prints messages at completion."""
     if self._state == _RUNNING and self._process.poll() is not None:
       elapsed = time.time() - self._start
+      self._tempfile.seek(0)
+      stdout = self._tempfile.read()
+      filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))
+      if self._xml_test is not None:
+        self._xml_test.set('time', str(elapsed))
+        ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout
       if self._process.returncode != 0:
         self._state = _FAILURE
-        self._tempfile.seek(0)
-        stdout = self._tempfile.read()
         message('FAILED', '%s [ret=%d, pid=%d]' % (
             self._spec.shortname, self._process.returncode, self._process.pid),
             stdout, do_newline=True)
+        if self._xml_test is not None:
+          ET.SubElement(self._xml_test, 'failure', message='Failure').text
       else:
         self._state = _SUCCESS
         message('PASSED', '%s [time=%.1fsec]' % (self._spec.shortname, elapsed),
                 do_newline=self._newline_on_success or self._travis)
         if self._bin_hash:
           update_cache.finished(self._spec.identity(), self._bin_hash)
-    elif self._state == _RUNNING and time.time() - self._start > 300:
+    elif self._state == _RUNNING and time.time() - self._start > 600:
       self._tempfile.seek(0)
       stdout = self._tempfile.read()
+      filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))
       message('TIMEOUT', self._spec.shortname, stdout, do_newline=True)
       self.kill()
+      if self._xml_test is not None:
+        ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout
+        ET.SubElement(self._xml_test, 'error', message='Timeout')
     return self._state
 
   def kill(self):
@@ -212,7 +227,7 @@
   """Manages one run of jobs."""
 
   def __init__(self, check_cancelled, maxjobs, newline_on_success, travis,
-               stop_on_failure, cache):
+               stop_on_failure, cache, xml_report):
     self._running = set()
     self._check_cancelled = check_cancelled
     self._cancelled = False
@@ -224,6 +239,7 @@
     self._cache = cache
     self._stop_on_failure = stop_on_failure
     self._hashes = {}
+    self._xml_report = xml_report
 
   def start(self, spec):
     """Start a job. Return True on success, False on failure."""
@@ -250,7 +266,8 @@
         self._running.add(Job(spec,
                               bin_hash,
                               self._newline_on_success,
-                              self._travis))
+                              self._travis,
+                              self._xml_report))
       except:
         message('FAILED', spec.shortname)
         self._cancelled = True
@@ -324,11 +341,13 @@
         travis=False,
         infinite_runs=False,
         stop_on_failure=False,
-        cache=None):
+        cache=None,
+        xml_report=None):
   js = Jobset(check_cancelled,
               maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS,
               newline_on_success, travis, stop_on_failure,
-              cache if cache is not None else NoCache())
+              cache if cache is not None else NoCache(),
+              xml_report)
   for cmdline in cmdlines:
     if not js.start(cmdline):
       break
diff --git a/tools/run_tests/python_tests.json b/tools/run_tests/python_tests.json
index 6c969d7..3d75d8d 100755
--- a/tools/run_tests/python_tests.json
+++ b/tools/run_tests/python_tests.json
@@ -1,56 +1,122 @@
 [
   {
-    "module": "grpc._adapter._c_test"
+    "module": "grpc._adapter._c_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._low_test"
+    "module": "grpc._adapter._low_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._intermediary_low_test"
+    "module": "grpc._adapter._intermediary_low_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._links_test"
+    "module": "grpc._adapter._links_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._lonely_rear_link_test"
+    "module": "grpc._adapter._lonely_rear_link_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._blocking_invocation_inline_service_test"
+    "module": "grpc._adapter._blocking_invocation_inline_service_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._event_invocation_synchronous_event_service_test"
+    "module": "grpc._adapter._event_invocation_synchronous_event_service_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc._adapter._future_invocation_asynchronous_event_service_test"
+    "module": "grpc._adapter._future_invocation_asynchronous_event_service_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.early_adopter.implementations_test"
+    "module": "grpc._links._lonely_invocation_link_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.framework.base.implementations_test"
+    "module": "grpc._links._transmission_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.framework.face.blocking_invocation_inline_service_test"
+    "module": "grpc.early_adopter.implementations_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.framework.face.event_invocation_synchronous_event_service_test"
+    "module": "grpc.framework.base.implementations_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.framework.face.future_invocation_asynchronous_event_service_test"
+    "module": "grpc.framework.face.blocking_invocation_inline_service_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.framework.foundation._later_test"
+    "module": "grpc.framework.face.event_invocation_synchronous_event_service_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "grpc.framework.foundation._logging_pool_test"
+    "module": "grpc.framework.face.future_invocation_asynchronous_event_service_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "interop._insecure_interop_test"
+    "module": "grpc.framework.foundation._later_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "module": "interop._secure_interop_test"
+    "module": "grpc.framework.foundation._logging_pool_test",
+    "pythonVersions": [
+      "2.7"
+    ]
   },
   {
-    "file": "test/compiler/python_plugin_test.py"
+    "module": "interop._insecure_interop_test",
+    "pythonVersions": [
+      "2.7"
+    ]
+  },
+  {
+    "module": "interop._secure_interop_test",
+    "pythonVersions": [
+      "2.7"
+    ]
+  },
+  {
+    "file": "test/compiler/python_plugin_test.py",
+    "pythonVersions": [
+      "2.7"
+    ]
   }
 ]
diff --git a/tools/run_tests/run_csharp.bat b/tools/run_tests/run_csharp.bat
index 17c622c..c861367 100644
--- a/tools/run_tests/run_csharp.bat
+++ b/tools/run_tests/run_csharp.bat
@@ -5,7 +5,10 @@
 @rem enter this directory
 cd /d %~dp0\..\..\src\csharp
 
-packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe -labels "%1/bin/Debug/%1.dll" || goto :error
+@rem set UUID variable to a random GUID, we will use it to put TestResults.xml to a dedicated directory, so that parallel test runs don't collide
+for /F %%i in ('powershell -Command "[guid]::NewGuid().ToString()"') do (set UUID=%%i)
+
+packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe -labels "%1/bin/Debug/%1.dll" -work test-results/%UUID% || goto :error
 
 endlocal
 
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index cab08f9..4959c02 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -36,5 +36,5 @@
 root=`pwd`
 export LD_LIBRARY_PATH=$root/libs/$CONFIG
 export DYLD_LIBRARY_PATH=$root/libs/$CONFIG
-source python2.7_virtual_environment/bin/activate
-python2.7 -B $*
+source "python"$PYVER"_virtual_environment"/bin/activate
+"python"$PYVER -B $*
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 2c9ffe7..1f44fc3 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -42,6 +42,7 @@
 import subprocess
 import sys
 import time
+import xml.etree.cElementTree as ET
 
 import jobset
 import watch_dirs
@@ -50,6 +51,9 @@
 os.chdir(ROOT)
 
 
+_FORCE_ENVIRON_FOR_WRAPPERS = {}
+
+
 # SimpleConfig: just compile with CONFIG=config, and run the binary to test
 class SimpleConfig(object):
 
@@ -97,7 +101,7 @@
   def job_spec(self, cmdline, hash_targets):
     return jobset.JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool] +
                           self.args + cmdline,
-                          shortname='valgrind %s' % binary,
+                          shortname='valgrind %s' % cmdline[0],
                           hash_targets=None)
 
 
@@ -130,7 +134,7 @@
     return sorted(out)
 
   def make_targets(self):
-    return ['buildtests_%s' % self.make_target]
+    return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
 
   def build_steps(self):
     return []
@@ -146,7 +150,7 @@
 
   def test_specs(self, config, travis):
     return [config.job_spec(['tools/run_tests/run_node.sh'], None,
-                            environ={'GRPC_TRACE': 'surface,batch'})]
+                            environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def make_targets(self):
     return ['static_c', 'shared_c']
@@ -165,7 +169,7 @@
 
   def test_specs(self, config, travis):
     return [config.job_spec(['src/php/bin/run_tests.sh'], None,
-                            environ={'GRPC_TRACE': 'surface,batch'})]
+                            environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def make_targets(self):
     return ['static_c', 'shared_c']
@@ -185,27 +189,55 @@
   def __init__(self):
     with open('tools/run_tests/python_tests.json') as f:
       self._tests = json.load(f)
+    self._build_python_versions = set([
+        python_version
+        for test in self._tests
+        for python_version in test['pythonVersions']])
+    self._has_python_versions = []
 
   def test_specs(self, config, travis):
-    modules = [config.job_spec(['tools/run_tests/run_python.sh', '-m',
-                                test['module']],
-                               None,
-                               environ={'GRPC_TRACE': 'surface,batch'},
-                               shortname=test['module'])
-               for test in self._tests if 'module' in test]
-    files = [config.job_spec(['tools/run_tests/run_python.sh',
-                              test['file']],
-                             None,
-                             environ={'GRPC_TRACE': 'surface,batch'},
-                             shortname=test['file'])
-            for test in self._tests if 'file' in test]
-    return files + modules
+    job_specifications = []
+    for test in self._tests:
+      command = None
+      short_name = None
+      if 'module' in test:
+        command = ['tools/run_tests/run_python.sh', '-m', test['module']]
+        short_name = test['module']
+      elif 'file' in test:
+        command = ['tools/run_tests/run_python.sh', test['file']]
+        short_name = test['file']
+      else:
+        raise ValueError('expected input to be a module or file to run '
+                         'unittests from')
+      for python_version in test['pythonVersions']:
+        if python_version in self._has_python_versions:
+          environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
+          environment['PYVER'] = python_version
+          job_specifications.append(config.job_spec(
+              command, None, environ=environment, shortname=short_name))
+        else:
+          jobset.message(
+              'WARNING',
+              'Could not find Python {}; skipping test'.format(python_version),
+              '{}\n'.format(command), do_newline=True)
+    return job_specifications
 
   def make_targets(self):
     return ['static_c', 'grpc_python_plugin', 'shared_c']
 
   def build_steps(self):
-    return [['tools/run_tests/build_python.sh']]
+    commands = []
+    for python_version in self._build_python_versions:
+      try:
+        with open(os.devnull, 'w') as output:
+          subprocess.check_call(['which', 'python' + python_version],
+                                stdout=output, stderr=output)
+        commands.append(['tools/run_tests/build_python.sh', python_version])
+        self._has_python_versions.append(python_version)
+      except:
+        jobset.message('WARNING', 'Missing Python ' + python_version,
+                       do_newline=True)
+    return commands
 
   def supports_multi_config(self):
     return False
@@ -218,7 +250,7 @@
 
   def test_specs(self, config, travis):
     return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
-                            environ={'GRPC_TRACE': 'surface,batch'})]
+                            environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def make_targets(self):
     return ['run_dep_checks']
@@ -251,7 +283,7 @@
       cmd = 'tools/run_tests/run_csharp.sh'
     return [config.job_spec([cmd, assembly],
             None, shortname=assembly,
-            environ={'GRPC_TRACE': 'surface,batch'})
+            environ=_FORCE_ENVIRON_FOR_WRAPPERS)
             for assembly in assemblies ]
 
   def make_targets(self):
@@ -275,7 +307,8 @@
 class Sanity(object):
 
   def test_specs(self, config, travis):
-    return [config.job_spec('tools/run_tests/run_sanity.sh', None)]
+    return [config.job_spec('tools/run_tests/run_sanity.sh', None),
+            config.job_spec('tools/run_tests/check_sources_and_headers.py', None)]
 
   def make_targets(self):
     return ['run_dep_checks']
@@ -385,14 +418,16 @@
                   action='store_const',
                   const=True)
 argp.add_argument('-l', '--language',
-                  choices=sorted(_LANGUAGES.keys()),
+                  choices=['all'] + sorted(_LANGUAGES.keys()),
                   nargs='+',
-                  default=sorted(_LANGUAGES.keys()))
+                  default=['all'])
 argp.add_argument('-S', '--stop_on_failure',
                   default=False,
                   action='store_const',
                   const=True)
 argp.add_argument('-a', '--antagonists', default=0, type=int)
+argp.add_argument('-x', '--xml_report', default=None, type=str,
+        help='Generates a JUnit-compatible XML report')
 args = argp.parse_args()
 
 # grab config
@@ -402,8 +437,14 @@
                       for x in args.config))
 build_configs = set(cfg.build_config for cfg in run_configs)
 
+if args.travis:
+  _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'surface,batch'}
+
 make_targets = []
-languages = set(_LANGUAGES[l] for l in args.language)
+languages = set(_LANGUAGES[l]
+                for l in itertools.chain.from_iterable(
+                      _LANGUAGES.iterkeys() if x == 'all' else [x]
+                      for x in args.language))
 
 if len(build_configs) > 1:
   for language in languages:
@@ -435,8 +476,8 @@
 one_run = set(
     spec
     for config in run_configs
-    for language in args.language
-    for spec in _LANGUAGES[language].test_specs(config, args.travis)
+    for language in languages
+    for spec in language.test_specs(config, args.travis)
     if re.search(args.regex, spec.shortname))
 
 runs_per_test = args.runs_per_test
@@ -483,7 +524,7 @@
         self.parse(json.loads(f.read()))
 
 
-def _build_and_run(check_cancelled, newline_on_success, travis, cache):
+def _build_and_run(check_cancelled, newline_on_success, travis, cache, xml_report=None):
   """Do one pass of building & running tests."""
   # build latest sequentially
   if not jobset.run(build_steps, maxjobs=1,
@@ -504,19 +545,29 @@
       # chance to run.
       massaged_one_run = list(one_run)  # random.shuffle needs an indexable seq.
       random.shuffle(massaged_one_run)  # which it modifies in-place.
+    if infinite_runs:
+      assert len(massaged_one_run) > 0, 'Must have at least one test for a -n inf run'
     runs_sequence = (itertools.repeat(massaged_one_run) if infinite_runs
                      else itertools.repeat(massaged_one_run, runs_per_test))
     all_runs = itertools.chain.from_iterable(runs_sequence)
+
+    root = ET.Element('testsuites') if xml_report else None
+    testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests') if xml_report else None
+
     if not jobset.run(all_runs, check_cancelled,
                       newline_on_success=newline_on_success, travis=travis,
                       infinite_runs=infinite_runs,
                       maxjobs=args.jobs,
                       stop_on_failure=args.stop_on_failure,
-                      cache=cache):
+                      cache=cache if not xml_report else None,
+                      xml_report=testsuite):
       return 2
   finally:
     for antagonist in antagonists:
       antagonist.kill()
+    if xml_report:
+      tree = ET.ElementTree(root)
+      tree.write(xml_report, encoding='UTF-8')
 
   if cache: cache.save()
 
@@ -548,7 +599,8 @@
   result = _build_and_run(check_cancelled=lambda: False,
                           newline_on_success=args.newline_on_success,
                           travis=args.travis,
-                          cache=test_cache)
+                          cache=test_cache,
+                          xml_report=args.xml_report)
   if result == 0:
     jobset.message('SUCCESS', 'All tests passed', do_newline=True)
   else:
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
new file mode 100644
index 0000000..abddaab
--- /dev/null
+++ b/tools/run_tests/sources_and_headers.json
@@ -0,0 +1,11952 @@
+
+
+[
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "alarm_heap_test", 
+    "src": [
+      "test/core/iomgr/alarm_heap_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "alarm_list_test", 
+    "src": [
+      "test/core/iomgr/alarm_list_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "alarm_test", 
+    "src": [
+      "test/core/iomgr/alarm_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "alpn_test", 
+    "src": [
+      "test/core/transport/chttp2/alpn_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "bin_encoder_test", 
+    "src": [
+      "test/core/transport/chttp2/bin_encoder_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_status_conversion_test", 
+    "src": [
+      "test/core/transport/chttp2/status_conversion_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_stream_encoder_test", 
+    "src": [
+      "test/core/transport/chttp2/stream_encoder_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_stream_map_test", 
+    "src": [
+      "test/core/transport/chttp2/stream_map_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "dualstack_socket_test", 
+    "src": [
+      "test/core/end2end/dualstack_socket_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "fd_conservation_posix_test", 
+    "src": [
+      "test/core/iomgr/fd_conservation_posix_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "fd_posix_test", 
+    "src": [
+      "test/core/iomgr/fd_posix_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "fling_client", 
+    "src": [
+      "test/core/fling/client.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "fling_server", 
+    "src": [
+      "test/core/fling/server.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "fling_stream_test", 
+    "src": [
+      "test/core/fling/fling_stream_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "fling_test", 
+    "src": [
+      "test/core/fling/fling_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gen_hpack_tables", 
+    "src": [
+      "tools/codegen/core/gen_hpack_tables.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "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"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_env_test", 
+    "src": [
+      "test/core/support/env_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_file_test", 
+    "src": [
+      "test/core/support/file_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_histogram_test", 
+    "src": [
+      "test/core/support/histogram_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_host_port_test", 
+    "src": [
+      "test/core/support/host_port_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_log_test", 
+    "src": [
+      "test/core/support/log_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_slice_buffer_test", 
+    "src": [
+      "test/core/support/slice_buffer_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_slice_test", 
+    "src": [
+      "test/core/support/slice_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_stack_lockfree_test", 
+    "src": [
+      "test/core/support/stack_lockfree_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_string_test", 
+    "src": [
+      "test/core/support/string_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_sync_test", 
+    "src": [
+      "test/core/support/sync_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_thd_test", 
+    "src": [
+      "test/core/support/thd_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_time_test", 
+    "src": [
+      "test/core/support/time_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_tls_test", 
+    "src": [
+      "test/core/support/tls_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "gpr_useful_test", 
+    "src": [
+      "test/core/support/useful_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_auth_context_test", 
+    "src": [
+      "test/core/security/auth_context_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_base64_test", 
+    "src": [
+      "test/core/security/base64_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_byte_buffer_reader_test", 
+    "src": [
+      "test/core/surface/byte_buffer_reader_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_channel_stack_test", 
+    "src": [
+      "test/core/channel/channel_stack_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_completion_queue_test", 
+    "src": [
+      "test/core/surface/completion_queue_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_create_jwt", 
+    "src": [
+      "test/core/security/create_jwt.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_credentials_test", 
+    "src": [
+      "test/core/security/credentials_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_fetch_oauth2", 
+    "src": [
+      "test/core/security/fetch_oauth2.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_json_token_test", 
+    "src": [
+      "test/core/security/json_token_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_jwt_verifier_test", 
+    "src": [
+      "test/core/security/jwt_verifier_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_print_google_default_creds_token", 
+    "src": [
+      "test/core/security/print_google_default_creds_token.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_security_connector_test", 
+    "src": [
+      "test/core/security/security_connector_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_stream_op_test", 
+    "src": [
+      "test/core/transport/stream_op_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "grpc_verify_jwt", 
+    "src": [
+      "test/core/security/verify_jwt.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "hpack_parser_test", 
+    "src": [
+      "test/core/transport/chttp2/hpack_parser_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "hpack_table_test", 
+    "src": [
+      "test/core/transport/chttp2/hpack_table_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "httpcli_format_request_test", 
+    "src": [
+      "test/core/httpcli/format_request_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "httpcli_parser_test", 
+    "src": [
+      "test/core/httpcli/parser_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "httpcli_test", 
+    "src": [
+      "test/core/httpcli/httpcli_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "json_rewrite", 
+    "src": [
+      "test/core/json/json_rewrite.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "json_rewrite_test", 
+    "src": [
+      "test/core/json/json_rewrite_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "json_test", 
+    "src": [
+      "test/core/json/json_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "lame_client_test", 
+    "src": [
+      "test/core/surface/lame_client_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "low_level_ping_pong_benchmark", 
+    "src": [
+      "test/core/network_benchmarks/low_level_ping_pong.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "message_compress_test", 
+    "src": [
+      "test/core/compression/message_compress_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "multi_init_test", 
+    "src": [
+      "test/core/surface/multi_init_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "multiple_server_queues_test", 
+    "src": [
+      "test/core/end2end/multiple_server_queues_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "murmur_hash_test", 
+    "src": [
+      "test/core/support/murmur_hash_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "no_server_test", 
+    "src": [
+      "test/core/end2end/no_server_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "poll_kick_posix_test", 
+    "src": [
+      "test/core/iomgr/poll_kick_posix_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "resolve_address_test", 
+    "src": [
+      "test/core/iomgr/resolve_address_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "secure_endpoint_test", 
+    "src": [
+      "test/core/security/secure_endpoint_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "sockaddr_utils_test", 
+    "src": [
+      "test/core/iomgr/sockaddr_utils_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "tcp_client_posix_test", 
+    "src": [
+      "test/core/iomgr/tcp_client_posix_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "tcp_posix_test", 
+    "src": [
+      "test/core/iomgr/tcp_posix_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "tcp_server_posix_test", 
+    "src": [
+      "test/core/iomgr/tcp_server_posix_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "time_averaged_stats_test", 
+    "src": [
+      "test/core/iomgr/time_averaged_stats_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "timeout_encoding_test", 
+    "src": [
+      "test/core/transport/chttp2/timeout_encoding_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "timers_test", 
+    "src": [
+      "test/core/profiling/timers_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "transport_metadata_test", 
+    "src": [
+      "test/core/transport/metadata_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "transport_security_test", 
+    "src": [
+      "test/core/tsi/transport_security_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"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "async_end2end_test", 
+    "src": [
+      "test/cpp/end2end/async_end2end_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "async_streaming_ping_pong_test", 
+    "src": [
+      "test/cpp/qps/async_streaming_ping_pong_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "async_unary_ping_pong_test", 
+    "src": [
+      "test/cpp/qps/async_unary_ping_pong_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "auth_property_iterator_test", 
+    "src": [
+      "test/cpp/common/auth_property_iterator_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "channel_arguments_test", 
+    "src": [
+      "test/cpp/client/channel_arguments_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "cli_call_test", 
+    "src": [
+      "test/cpp/util/cli_call_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "client_crash_test", 
+    "src": [
+      "test/cpp/end2end/client_crash_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "client_crash_test_server", 
+    "src": [
+      "test/cpp/end2end/client_crash_test_server.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "credentials_test", 
+    "src": [
+      "test/cpp/client/credentials_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "cxx_byte_buffer_test", 
+    "src": [
+      "test/cpp/util/byte_buffer_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "cxx_slice_test", 
+    "src": [
+      "test/cpp/util/slice_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "cxx_time_test", 
+    "src": [
+      "test/cpp/util/time_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "end2end_test", 
+    "src": [
+      "test/cpp/end2end/end2end_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "fixed_size_thread_pool_test", 
+    "src": [
+      "test/cpp/server/fixed_size_thread_pool_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "generic_end2end_test", 
+    "src": [
+      "test/cpp/end2end/generic_end2end_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "grpc_cli", 
+    "src": [
+      "test/cpp/util/grpc_cli.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc_plugin_support"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "grpc_cpp_plugin", 
+    "src": [
+      "src/compiler/cpp_plugin.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc_plugin_support"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "grpc_csharp_plugin", 
+    "src": [
+      "src/compiler/csharp_plugin.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc_plugin_support"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "grpc_objective_c_plugin", 
+    "src": [
+      "src/compiler/objective_c_plugin.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc_plugin_support"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "grpc_python_plugin", 
+    "src": [
+      "src/compiler/python_plugin.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc_plugin_support"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "grpc_ruby_plugin", 
+    "src": [
+      "src/compiler/ruby_plugin.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "interop_client_helper", 
+      "interop_client_main"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "interop_client", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "interop_server_helper", 
+      "interop_server_main"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "interop_server", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "interop_test", 
+    "src": [
+      "test/cpp/interop/interop_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "mock_test", 
+    "src": [
+      "test/cpp/end2end/mock_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc_test_util", 
+      "pubsub_client_lib"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "pubsub_client", 
+    "src": [
+      "examples/pubsub/main.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "pubsub_client_lib"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "pubsub_publisher_test", 
+    "src": [
+      "examples/pubsub/publisher_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "pubsub_client_lib"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "pubsub_subscriber_test", 
+    "src": [
+      "examples/pubsub/subscriber_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "qps_driver", 
+    "src": [
+      "test/cpp/qps/qps_driver.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "qps_interarrival_test", 
+    "src": [
+      "test/cpp/qps/qps_interarrival_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "qps_openloop_test", 
+    "src": [
+      "test/cpp/qps/qps_openloop_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "qps_test", 
+    "src": [
+      "test/cpp/qps/qps_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [
+      "test/cpp/qps/client.h", 
+      "test/cpp/qps/server.h"
+    ], 
+    "language": "c++", 
+    "name": "qps_worker", 
+    "src": [
+      "test/cpp/qps/client.h", 
+      "test/cpp/qps/server.h", 
+      "test/cpp/qps/worker.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "secure_auth_context_test", 
+    "src": [
+      "test/cpp/common/secure_auth_context_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "server_crash_test", 
+    "src": [
+      "test/cpp/end2end/server_crash_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "server_crash_test_client", 
+    "src": [
+      "test/cpp/end2end/server_crash_test_client.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "status_test", 
+    "src": [
+      "test/cpp/util/status_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "sync_streaming_ping_pong_test", 
+    "src": [
+      "test/cpp/qps/sync_streaming_ping_pong_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "qps"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "sync_unary_ping_pong_test", 
+    "src": [
+      "test/cpp/qps/sync_unary_ping_pong_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "thread_stress_test", 
+    "src": [
+      "test/cpp/end2end/thread_stress_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fake_security", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fake_security_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_bad_hostname_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_census_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_disappearing_server_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_empty_batch_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_invoke_large_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_max_message_length_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_no_op_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_registered_call_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_payload_and_call_creds", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_flags_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_payload_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_server_finishes_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_simple_request_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_compression", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_uds_posix", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_fullstack_with_poll", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_bad_hostname", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_after_accept", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_after_accept_and_writes_closed", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_after_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_before_invoke", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_cancel_in_a_vacuum", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_census_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_disappearing_server", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_early_server_shutdown_finishes_tags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_empty_batch", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_graceful_server_shutdown", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_invoke_large_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_max_concurrent_streams", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_max_message_length", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_no_op", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_ping_pong_streaming", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_registered_call", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_binary_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_response_with_trailing_metadata_and_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_compressed_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_flags", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_large_metadata", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_request_with_payload", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_server_finishes_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_simple_delayed_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_simple_request", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+      "end2end_test_simple_request_with_high_initial_sequence_number", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "src": []
+  }, 
+  {
+    "deps": [
+      "bad_client_test", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "connection_prefix_bad_client_test", 
+    "src": [
+      "test/core/bad_client/tests/connection_prefix.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "bad_client_test", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "initial_settings_frame_bad_client_test", 
+    "src": [
+      "test/core/bad_client/tests/initial_settings_frame.c"
+    ]
+  }, 
+  {
+    "deps": [], 
+    "headers": [
+      "include/grpc/support/alloc.h", 
+      "include/grpc/support/atm.h", 
+      "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", 
+      "include/grpc/support/host_port.h", 
+      "include/grpc/support/log.h", 
+      "include/grpc/support/log_win32.h", 
+      "include/grpc/support/port_platform.h", 
+      "include/grpc/support/slice.h", 
+      "include/grpc/support/slice_buffer.h", 
+      "include/grpc/support/string_util.h", 
+      "include/grpc/support/subprocess.h", 
+      "include/grpc/support/sync.h", 
+      "include/grpc/support/sync_generic.h", 
+      "include/grpc/support/sync_posix.h", 
+      "include/grpc/support/sync_win32.h", 
+      "include/grpc/support/thd.h", 
+      "include/grpc/support/time.h", 
+      "include/grpc/support/tls.h", 
+      "include/grpc/support/tls_gcc.h", 
+      "include/grpc/support/tls_msvc.h", 
+      "include/grpc/support/tls_pthread.h", 
+      "include/grpc/support/useful.h", 
+      "src/core/support/env.h", 
+      "src/core/support/file.h", 
+      "src/core/support/murmur_hash.h", 
+      "src/core/support/stack_lockfree.h", 
+      "src/core/support/string.h", 
+      "src/core/support/string_win32.h", 
+      "src/core/support/thd_internal.h"
+    ], 
+    "language": "c", 
+    "name": "gpr", 
+    "src": [
+      "include/grpc/support/alloc.h", 
+      "include/grpc/support/atm.h", 
+      "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", 
+      "include/grpc/support/host_port.h", 
+      "include/grpc/support/log.h", 
+      "include/grpc/support/log_win32.h", 
+      "include/grpc/support/port_platform.h", 
+      "include/grpc/support/slice.h", 
+      "include/grpc/support/slice_buffer.h", 
+      "include/grpc/support/string_util.h", 
+      "include/grpc/support/subprocess.h", 
+      "include/grpc/support/sync.h", 
+      "include/grpc/support/sync_generic.h", 
+      "include/grpc/support/sync_posix.h", 
+      "include/grpc/support/sync_win32.h", 
+      "include/grpc/support/thd.h", 
+      "include/grpc/support/time.h", 
+      "include/grpc/support/tls.h", 
+      "include/grpc/support/tls_gcc.h", 
+      "include/grpc/support/tls_msvc.h", 
+      "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", 
+      "src/core/support/cpu_posix.c", 
+      "src/core/support/cpu_windows.c", 
+      "src/core/support/env.h", 
+      "src/core/support/env_linux.c", 
+      "src/core/support/env_posix.c", 
+      "src/core/support/env_win32.c", 
+      "src/core/support/file.c", 
+      "src/core/support/file.h", 
+      "src/core/support/file_posix.c", 
+      "src/core/support/file_win32.c", 
+      "src/core/support/histogram.c", 
+      "src/core/support/host_port.c", 
+      "src/core/support/log.c", 
+      "src/core/support/log_android.c", 
+      "src/core/support/log_linux.c", 
+      "src/core/support/log_posix.c", 
+      "src/core/support/log_win32.c", 
+      "src/core/support/murmur_hash.c", 
+      "src/core/support/murmur_hash.h", 
+      "src/core/support/slice.c", 
+      "src/core/support/slice_buffer.c", 
+      "src/core/support/stack_lockfree.c", 
+      "src/core/support/stack_lockfree.h", 
+      "src/core/support/string.c", 
+      "src/core/support/string.h", 
+      "src/core/support/string_posix.c", 
+      "src/core/support/string_win32.c", 
+      "src/core/support/string_win32.h", 
+      "src/core/support/subprocess_posix.c", 
+      "src/core/support/sync.c", 
+      "src/core/support/sync_posix.c", 
+      "src/core/support/sync_win32.c", 
+      "src/core/support/thd.c", 
+      "src/core/support/thd_internal.h", 
+      "src/core/support/thd_posix.c", 
+      "src/core/support/thd_win32.c", 
+      "src/core/support/time.c", 
+      "src/core/support/time_posix.c", 
+      "src/core/support/time_win32.c", 
+      "src/core/support/tls_pthread.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr"
+    ], 
+    "headers": [
+      "test/core/util/test_config.h"
+    ], 
+    "language": "c", 
+    "name": "gpr_test_util", 
+    "src": [
+      "test/core/util/test_config.c", 
+      "test/core/util/test_config.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr"
+    ], 
+    "headers": [
+      "include/grpc/byte_buffer.h", 
+      "include/grpc/byte_buffer_reader.h", 
+      "include/grpc/census.h", 
+      "include/grpc/compression.h", 
+      "include/grpc/grpc.h", 
+      "include/grpc/grpc_security.h", 
+      "include/grpc/status.h", 
+      "src/core/census/context.h", 
+      "src/core/census/grpc_context.h", 
+      "src/core/channel/census_filter.h", 
+      "src/core/channel/channel_args.h", 
+      "src/core/channel/channel_stack.h", 
+      "src/core/channel/client_channel.h", 
+      "src/core/channel/compress_filter.h", 
+      "src/core/channel/connected_channel.h", 
+      "src/core/channel/context.h", 
+      "src/core/channel/http_client_filter.h", 
+      "src/core/channel/http_server_filter.h", 
+      "src/core/channel/noop_filter.h", 
+      "src/core/client_config/client_config.h", 
+      "src/core/client_config/connector.h", 
+      "src/core/client_config/lb_policies/pick_first.h", 
+      "src/core/client_config/lb_policy.h", 
+      "src/core/client_config/resolver.h", 
+      "src/core/client_config/resolver_factory.h", 
+      "src/core/client_config/resolver_registry.h", 
+      "src/core/client_config/resolvers/dns_resolver.h", 
+      "src/core/client_config/resolvers/unix_resolver_posix.h", 
+      "src/core/client_config/subchannel.h", 
+      "src/core/client_config/subchannel_factory.h", 
+      "src/core/client_config/uri_parser.h", 
+      "src/core/compression/message_compress.h", 
+      "src/core/debug/trace.h", 
+      "src/core/httpcli/format_request.h", 
+      "src/core/httpcli/httpcli.h", 
+      "src/core/httpcli/httpcli_security_connector.h", 
+      "src/core/httpcli/parser.h", 
+      "src/core/iomgr/alarm.h", 
+      "src/core/iomgr/alarm_heap.h", 
+      "src/core/iomgr/alarm_internal.h", 
+      "src/core/iomgr/endpoint.h", 
+      "src/core/iomgr/endpoint_pair.h", 
+      "src/core/iomgr/fd_posix.h", 
+      "src/core/iomgr/iocp_windows.h", 
+      "src/core/iomgr/iomgr.h", 
+      "src/core/iomgr/iomgr_internal.h", 
+      "src/core/iomgr/iomgr_posix.h", 
+      "src/core/iomgr/pollset.h", 
+      "src/core/iomgr/pollset_kick_posix.h", 
+      "src/core/iomgr/pollset_posix.h", 
+      "src/core/iomgr/pollset_set.h", 
+      "src/core/iomgr/pollset_set_posix.h", 
+      "src/core/iomgr/pollset_set_windows.h", 
+      "src/core/iomgr/pollset_windows.h", 
+      "src/core/iomgr/resolve_address.h", 
+      "src/core/iomgr/sockaddr.h", 
+      "src/core/iomgr/sockaddr_posix.h", 
+      "src/core/iomgr/sockaddr_utils.h", 
+      "src/core/iomgr/sockaddr_win32.h", 
+      "src/core/iomgr/socket_utils_posix.h", 
+      "src/core/iomgr/socket_windows.h", 
+      "src/core/iomgr/tcp_client.h", 
+      "src/core/iomgr/tcp_posix.h", 
+      "src/core/iomgr/tcp_server.h", 
+      "src/core/iomgr/tcp_windows.h", 
+      "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/wakeup_fd_pipe.h", 
+      "src/core/iomgr/wakeup_fd_posix.h", 
+      "src/core/json/json.h", 
+      "src/core/json/json_common.h", 
+      "src/core/json/json_reader.h", 
+      "src/core/json/json_writer.h", 
+      "src/core/profiling/timers.h", 
+      "src/core/profiling/timers_preciseclock.h", 
+      "src/core/security/auth_filters.h", 
+      "src/core/security/base64.h", 
+      "src/core/security/credentials.h", 
+      "src/core/security/json_token.h", 
+      "src/core/security/jwt_verifier.h", 
+      "src/core/security/secure_endpoint.h", 
+      "src/core/security/secure_transport_setup.h", 
+      "src/core/security/security_connector.h", 
+      "src/core/security/security_context.h", 
+      "src/core/surface/byte_buffer_queue.h", 
+      "src/core/surface/call.h", 
+      "src/core/surface/channel.h", 
+      "src/core/surface/completion_queue.h", 
+      "src/core/surface/event_string.h", 
+      "src/core/surface/init.h", 
+      "src/core/surface/server.h", 
+      "src/core/surface/surface_trace.h", 
+      "src/core/transport/chttp2/alpn.h", 
+      "src/core/transport/chttp2/bin_encoder.h", 
+      "src/core/transport/chttp2/frame.h", 
+      "src/core/transport/chttp2/frame_data.h", 
+      "src/core/transport/chttp2/frame_goaway.h", 
+      "src/core/transport/chttp2/frame_ping.h", 
+      "src/core/transport/chttp2/frame_rst_stream.h", 
+      "src/core/transport/chttp2/frame_settings.h", 
+      "src/core/transport/chttp2/frame_window_update.h", 
+      "src/core/transport/chttp2/hpack_parser.h", 
+      "src/core/transport/chttp2/hpack_table.h", 
+      "src/core/transport/chttp2/http2_errors.h", 
+      "src/core/transport/chttp2/huffsyms.h", 
+      "src/core/transport/chttp2/incoming_metadata.h", 
+      "src/core/transport/chttp2/internal.h", 
+      "src/core/transport/chttp2/status_conversion.h", 
+      "src/core/transport/chttp2/stream_encoder.h", 
+      "src/core/transport/chttp2/stream_map.h", 
+      "src/core/transport/chttp2/timeout_encoding.h", 
+      "src/core/transport/chttp2/varint.h", 
+      "src/core/transport/chttp2_transport.h", 
+      "src/core/transport/connectivity_state.h", 
+      "src/core/transport/metadata.h", 
+      "src/core/transport/stream_op.h", 
+      "src/core/transport/transport.h", 
+      "src/core/transport/transport_impl.h", 
+      "src/core/tsi/fake_transport_security.h", 
+      "src/core/tsi/ssl_transport_security.h", 
+      "src/core/tsi/transport_security.h", 
+      "src/core/tsi/transport_security_interface.h"
+    ], 
+    "language": "c", 
+    "name": "grpc", 
+    "src": [
+      "include/grpc/byte_buffer.h", 
+      "include/grpc/byte_buffer_reader.h", 
+      "include/grpc/census.h", 
+      "include/grpc/compression.h", 
+      "include/grpc/grpc.h", 
+      "include/grpc/grpc_security.h", 
+      "include/grpc/status.h", 
+      "src/core/census/context.c", 
+      "src/core/census/context.h", 
+      "src/core/census/grpc_context.c", 
+      "src/core/census/grpc_context.h", 
+      "src/core/census/initialize.c", 
+      "src/core/channel/census_filter.h", 
+      "src/core/channel/channel_args.c", 
+      "src/core/channel/channel_args.h", 
+      "src/core/channel/channel_stack.c", 
+      "src/core/channel/channel_stack.h", 
+      "src/core/channel/client_channel.c", 
+      "src/core/channel/client_channel.h", 
+      "src/core/channel/compress_filter.c", 
+      "src/core/channel/compress_filter.h", 
+      "src/core/channel/connected_channel.c", 
+      "src/core/channel/connected_channel.h", 
+      "src/core/channel/context.h", 
+      "src/core/channel/http_client_filter.c", 
+      "src/core/channel/http_client_filter.h", 
+      "src/core/channel/http_server_filter.c", 
+      "src/core/channel/http_server_filter.h", 
+      "src/core/channel/noop_filter.c", 
+      "src/core/channel/noop_filter.h", 
+      "src/core/client_config/client_config.c", 
+      "src/core/client_config/client_config.h", 
+      "src/core/client_config/connector.c", 
+      "src/core/client_config/connector.h", 
+      "src/core/client_config/lb_policies/pick_first.c", 
+      "src/core/client_config/lb_policies/pick_first.h", 
+      "src/core/client_config/lb_policy.c", 
+      "src/core/client_config/lb_policy.h", 
+      "src/core/client_config/resolver.c", 
+      "src/core/client_config/resolver.h", 
+      "src/core/client_config/resolver_factory.c", 
+      "src/core/client_config/resolver_factory.h", 
+      "src/core/client_config/resolver_registry.c", 
+      "src/core/client_config/resolver_registry.h", 
+      "src/core/client_config/resolvers/dns_resolver.c", 
+      "src/core/client_config/resolvers/dns_resolver.h", 
+      "src/core/client_config/resolvers/unix_resolver_posix.c", 
+      "src/core/client_config/resolvers/unix_resolver_posix.h", 
+      "src/core/client_config/subchannel.c", 
+      "src/core/client_config/subchannel.h", 
+      "src/core/client_config/subchannel_factory.c", 
+      "src/core/client_config/subchannel_factory.h", 
+      "src/core/client_config/uri_parser.c", 
+      "src/core/client_config/uri_parser.h", 
+      "src/core/compression/algorithm.c", 
+      "src/core/compression/message_compress.c", 
+      "src/core/compression/message_compress.h", 
+      "src/core/debug/trace.c", 
+      "src/core/debug/trace.h", 
+      "src/core/httpcli/format_request.c", 
+      "src/core/httpcli/format_request.h", 
+      "src/core/httpcli/httpcli.c", 
+      "src/core/httpcli/httpcli.h", 
+      "src/core/httpcli/httpcli_security_connector.c", 
+      "src/core/httpcli/httpcli_security_connector.h", 
+      "src/core/httpcli/parser.c", 
+      "src/core/httpcli/parser.h", 
+      "src/core/iomgr/alarm.c", 
+      "src/core/iomgr/alarm.h", 
+      "src/core/iomgr/alarm_heap.c", 
+      "src/core/iomgr/alarm_heap.h", 
+      "src/core/iomgr/alarm_internal.h", 
+      "src/core/iomgr/endpoint.c", 
+      "src/core/iomgr/endpoint.h", 
+      "src/core/iomgr/endpoint_pair.h", 
+      "src/core/iomgr/endpoint_pair_posix.c", 
+      "src/core/iomgr/endpoint_pair_windows.c", 
+      "src/core/iomgr/fd_posix.c", 
+      "src/core/iomgr/fd_posix.h", 
+      "src/core/iomgr/iocp_windows.c", 
+      "src/core/iomgr/iocp_windows.h", 
+      "src/core/iomgr/iomgr.c", 
+      "src/core/iomgr/iomgr.h", 
+      "src/core/iomgr/iomgr_internal.h", 
+      "src/core/iomgr/iomgr_posix.c", 
+      "src/core/iomgr/iomgr_posix.h", 
+      "src/core/iomgr/iomgr_windows.c", 
+      "src/core/iomgr/pollset.h", 
+      "src/core/iomgr/pollset_kick_posix.c", 
+      "src/core/iomgr/pollset_kick_posix.h", 
+      "src/core/iomgr/pollset_multipoller_with_epoll.c", 
+      "src/core/iomgr/pollset_multipoller_with_poll_posix.c", 
+      "src/core/iomgr/pollset_posix.c", 
+      "src/core/iomgr/pollset_posix.h", 
+      "src/core/iomgr/pollset_set.h", 
+      "src/core/iomgr/pollset_set_posix.c", 
+      "src/core/iomgr/pollset_set_posix.h", 
+      "src/core/iomgr/pollset_set_windows.c", 
+      "src/core/iomgr/pollset_set_windows.h", 
+      "src/core/iomgr/pollset_windows.c", 
+      "src/core/iomgr/pollset_windows.h", 
+      "src/core/iomgr/resolve_address.h", 
+      "src/core/iomgr/resolve_address_posix.c", 
+      "src/core/iomgr/resolve_address_windows.c", 
+      "src/core/iomgr/sockaddr.h", 
+      "src/core/iomgr/sockaddr_posix.h", 
+      "src/core/iomgr/sockaddr_utils.c", 
+      "src/core/iomgr/sockaddr_utils.h", 
+      "src/core/iomgr/sockaddr_win32.h", 
+      "src/core/iomgr/socket_utils_common_posix.c", 
+      "src/core/iomgr/socket_utils_linux.c", 
+      "src/core/iomgr/socket_utils_posix.c", 
+      "src/core/iomgr/socket_utils_posix.h", 
+      "src/core/iomgr/socket_windows.c", 
+      "src/core/iomgr/socket_windows.h", 
+      "src/core/iomgr/tcp_client.h", 
+      "src/core/iomgr/tcp_client_posix.c", 
+      "src/core/iomgr/tcp_client_windows.c", 
+      "src/core/iomgr/tcp_posix.c", 
+      "src/core/iomgr/tcp_posix.h", 
+      "src/core/iomgr/tcp_server.h", 
+      "src/core/iomgr/tcp_server_posix.c", 
+      "src/core/iomgr/tcp_server_windows.c", 
+      "src/core/iomgr/tcp_windows.c", 
+      "src/core/iomgr/tcp_windows.h", 
+      "src/core/iomgr/time_averaged_stats.c", 
+      "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/wakeup_fd_eventfd.c", 
+      "src/core/iomgr/wakeup_fd_nospecial.c", 
+      "src/core/iomgr/wakeup_fd_pipe.c", 
+      "src/core/iomgr/wakeup_fd_pipe.h", 
+      "src/core/iomgr/wakeup_fd_posix.c", 
+      "src/core/iomgr/wakeup_fd_posix.h", 
+      "src/core/json/json.c", 
+      "src/core/json/json.h", 
+      "src/core/json/json_common.h", 
+      "src/core/json/json_reader.c", 
+      "src/core/json/json_reader.h", 
+      "src/core/json/json_string.c", 
+      "src/core/json/json_writer.c", 
+      "src/core/json/json_writer.h", 
+      "src/core/profiling/basic_timers.c", 
+      "src/core/profiling/stap_timers.c", 
+      "src/core/profiling/timers.h", 
+      "src/core/profiling/timers_preciseclock.h", 
+      "src/core/security/auth_filters.h", 
+      "src/core/security/base64.c", 
+      "src/core/security/base64.h", 
+      "src/core/security/client_auth_filter.c", 
+      "src/core/security/credentials.c", 
+      "src/core/security/credentials.h", 
+      "src/core/security/credentials_metadata.c", 
+      "src/core/security/credentials_posix.c", 
+      "src/core/security/credentials_win32.c", 
+      "src/core/security/google_default_credentials.c", 
+      "src/core/security/json_token.c", 
+      "src/core/security/json_token.h", 
+      "src/core/security/jwt_verifier.c", 
+      "src/core/security/jwt_verifier.h", 
+      "src/core/security/secure_endpoint.c", 
+      "src/core/security/secure_endpoint.h", 
+      "src/core/security/secure_transport_setup.c", 
+      "src/core/security/secure_transport_setup.h", 
+      "src/core/security/security_connector.c", 
+      "src/core/security/security_connector.h", 
+      "src/core/security/security_context.c", 
+      "src/core/security/security_context.h", 
+      "src/core/security/server_auth_filter.c", 
+      "src/core/security/server_secure_chttp2.c", 
+      "src/core/surface/byte_buffer.c", 
+      "src/core/surface/byte_buffer_queue.c", 
+      "src/core/surface/byte_buffer_queue.h", 
+      "src/core/surface/byte_buffer_reader.c", 
+      "src/core/surface/call.c", 
+      "src/core/surface/call.h", 
+      "src/core/surface/call_details.c", 
+      "src/core/surface/call_log_batch.c", 
+      "src/core/surface/channel.c", 
+      "src/core/surface/channel.h", 
+      "src/core/surface/channel_create.c", 
+      "src/core/surface/completion_queue.c", 
+      "src/core/surface/completion_queue.h", 
+      "src/core/surface/event_string.c", 
+      "src/core/surface/event_string.h", 
+      "src/core/surface/init.c", 
+      "src/core/surface/init.h", 
+      "src/core/surface/init_secure.c", 
+      "src/core/surface/lame_client.c", 
+      "src/core/surface/metadata_array.c", 
+      "src/core/surface/secure_channel_create.c", 
+      "src/core/surface/server.c", 
+      "src/core/surface/server.h", 
+      "src/core/surface/server_chttp2.c", 
+      "src/core/surface/server_create.c", 
+      "src/core/surface/surface_trace.c", 
+      "src/core/surface/surface_trace.h", 
+      "src/core/surface/version.c", 
+      "src/core/transport/chttp2/alpn.c", 
+      "src/core/transport/chttp2/alpn.h", 
+      "src/core/transport/chttp2/bin_encoder.c", 
+      "src/core/transport/chttp2/bin_encoder.h", 
+      "src/core/transport/chttp2/frame.h", 
+      "src/core/transport/chttp2/frame_data.c", 
+      "src/core/transport/chttp2/frame_data.h", 
+      "src/core/transport/chttp2/frame_goaway.c", 
+      "src/core/transport/chttp2/frame_goaway.h", 
+      "src/core/transport/chttp2/frame_ping.c", 
+      "src/core/transport/chttp2/frame_ping.h", 
+      "src/core/transport/chttp2/frame_rst_stream.c", 
+      "src/core/transport/chttp2/frame_rst_stream.h", 
+      "src/core/transport/chttp2/frame_settings.c", 
+      "src/core/transport/chttp2/frame_settings.h", 
+      "src/core/transport/chttp2/frame_window_update.c", 
+      "src/core/transport/chttp2/frame_window_update.h", 
+      "src/core/transport/chttp2/hpack_parser.c", 
+      "src/core/transport/chttp2/hpack_parser.h", 
+      "src/core/transport/chttp2/hpack_table.c", 
+      "src/core/transport/chttp2/hpack_table.h", 
+      "src/core/transport/chttp2/http2_errors.h", 
+      "src/core/transport/chttp2/huffsyms.c", 
+      "src/core/transport/chttp2/huffsyms.h", 
+      "src/core/transport/chttp2/incoming_metadata.c", 
+      "src/core/transport/chttp2/incoming_metadata.h", 
+      "src/core/transport/chttp2/internal.h", 
+      "src/core/transport/chttp2/parsing.c", 
+      "src/core/transport/chttp2/status_conversion.c", 
+      "src/core/transport/chttp2/status_conversion.h", 
+      "src/core/transport/chttp2/stream_encoder.c", 
+      "src/core/transport/chttp2/stream_encoder.h", 
+      "src/core/transport/chttp2/stream_lists.c", 
+      "src/core/transport/chttp2/stream_map.c", 
+      "src/core/transport/chttp2/stream_map.h", 
+      "src/core/transport/chttp2/timeout_encoding.c", 
+      "src/core/transport/chttp2/timeout_encoding.h", 
+      "src/core/transport/chttp2/varint.c", 
+      "src/core/transport/chttp2/varint.h", 
+      "src/core/transport/chttp2/writing.c", 
+      "src/core/transport/chttp2_transport.c", 
+      "src/core/transport/chttp2_transport.h", 
+      "src/core/transport/connectivity_state.c", 
+      "src/core/transport/connectivity_state.h", 
+      "src/core/transport/metadata.c", 
+      "src/core/transport/metadata.h", 
+      "src/core/transport/stream_op.c", 
+      "src/core/transport/stream_op.h", 
+      "src/core/transport/transport.c", 
+      "src/core/transport/transport.h", 
+      "src/core/transport/transport_impl.h", 
+      "src/core/transport/transport_op_string.c", 
+      "src/core/tsi/fake_transport_security.c", 
+      "src/core/tsi/fake_transport_security.h", 
+      "src/core/tsi/ssl_transport_security.c", 
+      "src/core/tsi/ssl_transport_security.h", 
+      "src/core/tsi/transport_security.c", 
+      "src/core/tsi/transport_security.h", 
+      "src/core/tsi/transport_security_interface.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc"
+    ], 
+    "headers": [
+      "test/core/end2end/cq_verifier.h", 
+      "test/core/end2end/data/ssl_test_data.h", 
+      "test/core/iomgr/endpoint_tests.h", 
+      "test/core/security/oauth2_utils.h", 
+      "test/core/util/grpc_profiler.h", 
+      "test/core/util/parse_hexstring.h", 
+      "test/core/util/port.h", 
+      "test/core/util/slice_splitter.h"
+    ], 
+    "language": "c", 
+    "name": "grpc_test_util", 
+    "src": [
+      "test/core/end2end/cq_verifier.c", 
+      "test/core/end2end/cq_verifier.h", 
+      "test/core/end2end/data/server1_cert.c", 
+      "test/core/end2end/data/server1_key.c", 
+      "test/core/end2end/data/ssl_test_data.h", 
+      "test/core/end2end/data/test_root_cert.c", 
+      "test/core/iomgr/endpoint_tests.c", 
+      "test/core/iomgr/endpoint_tests.h", 
+      "test/core/security/oauth2_utils.c", 
+      "test/core/security/oauth2_utils.h", 
+      "test/core/util/grpc_profiler.c", 
+      "test/core/util/grpc_profiler.h", 
+      "test/core/util/parse_hexstring.c", 
+      "test/core/util/parse_hexstring.h", 
+      "test/core/util/port.h", 
+      "test/core/util/port_posix.c", 
+      "test/core/util/port_windows.c", 
+      "test/core/util/slice_splitter.c", 
+      "test/core/util/slice_splitter.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc"
+    ], 
+    "headers": [
+      "test/core/end2end/cq_verifier.h", 
+      "test/core/iomgr/endpoint_tests.h", 
+      "test/core/security/oauth2_utils.h", 
+      "test/core/util/grpc_profiler.h", 
+      "test/core/util/parse_hexstring.h", 
+      "test/core/util/port.h", 
+      "test/core/util/slice_splitter.h"
+    ], 
+    "language": "c", 
+    "name": "grpc_test_util_unsecure", 
+    "src": [
+      "test/core/end2end/cq_verifier.c", 
+      "test/core/end2end/cq_verifier.h", 
+      "test/core/iomgr/endpoint_tests.c", 
+      "test/core/iomgr/endpoint_tests.h", 
+      "test/core/security/oauth2_utils.c", 
+      "test/core/security/oauth2_utils.h", 
+      "test/core/util/grpc_profiler.c", 
+      "test/core/util/grpc_profiler.h", 
+      "test/core/util/parse_hexstring.c", 
+      "test/core/util/parse_hexstring.h", 
+      "test/core/util/port.h", 
+      "test/core/util/port_posix.c", 
+      "test/core/util/port_windows.c", 
+      "test/core/util/slice_splitter.c", 
+      "test/core/util/slice_splitter.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr"
+    ], 
+    "headers": [
+      "include/grpc/byte_buffer.h", 
+      "include/grpc/byte_buffer_reader.h", 
+      "include/grpc/census.h", 
+      "include/grpc/compression.h", 
+      "include/grpc/grpc.h", 
+      "include/grpc/status.h", 
+      "src/core/census/context.h", 
+      "src/core/census/grpc_context.h", 
+      "src/core/channel/census_filter.h", 
+      "src/core/channel/channel_args.h", 
+      "src/core/channel/channel_stack.h", 
+      "src/core/channel/client_channel.h", 
+      "src/core/channel/compress_filter.h", 
+      "src/core/channel/connected_channel.h", 
+      "src/core/channel/context.h", 
+      "src/core/channel/http_client_filter.h", 
+      "src/core/channel/http_server_filter.h", 
+      "src/core/channel/noop_filter.h", 
+      "src/core/client_config/client_config.h", 
+      "src/core/client_config/connector.h", 
+      "src/core/client_config/lb_policies/pick_first.h", 
+      "src/core/client_config/lb_policy.h", 
+      "src/core/client_config/resolver.h", 
+      "src/core/client_config/resolver_factory.h", 
+      "src/core/client_config/resolver_registry.h", 
+      "src/core/client_config/resolvers/dns_resolver.h", 
+      "src/core/client_config/resolvers/unix_resolver_posix.h", 
+      "src/core/client_config/subchannel.h", 
+      "src/core/client_config/subchannel_factory.h", 
+      "src/core/client_config/uri_parser.h", 
+      "src/core/compression/message_compress.h", 
+      "src/core/debug/trace.h", 
+      "src/core/iomgr/alarm.h", 
+      "src/core/iomgr/alarm_heap.h", 
+      "src/core/iomgr/alarm_internal.h", 
+      "src/core/iomgr/endpoint.h", 
+      "src/core/iomgr/endpoint_pair.h", 
+      "src/core/iomgr/fd_posix.h", 
+      "src/core/iomgr/iocp_windows.h", 
+      "src/core/iomgr/iomgr.h", 
+      "src/core/iomgr/iomgr_internal.h", 
+      "src/core/iomgr/iomgr_posix.h", 
+      "src/core/iomgr/pollset.h", 
+      "src/core/iomgr/pollset_kick_posix.h", 
+      "src/core/iomgr/pollset_posix.h", 
+      "src/core/iomgr/pollset_set.h", 
+      "src/core/iomgr/pollset_set_posix.h", 
+      "src/core/iomgr/pollset_set_windows.h", 
+      "src/core/iomgr/pollset_windows.h", 
+      "src/core/iomgr/resolve_address.h", 
+      "src/core/iomgr/sockaddr.h", 
+      "src/core/iomgr/sockaddr_posix.h", 
+      "src/core/iomgr/sockaddr_utils.h", 
+      "src/core/iomgr/sockaddr_win32.h", 
+      "src/core/iomgr/socket_utils_posix.h", 
+      "src/core/iomgr/socket_windows.h", 
+      "src/core/iomgr/tcp_client.h", 
+      "src/core/iomgr/tcp_posix.h", 
+      "src/core/iomgr/tcp_server.h", 
+      "src/core/iomgr/tcp_windows.h", 
+      "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/wakeup_fd_pipe.h", 
+      "src/core/iomgr/wakeup_fd_posix.h", 
+      "src/core/json/json.h", 
+      "src/core/json/json_common.h", 
+      "src/core/json/json_reader.h", 
+      "src/core/json/json_writer.h", 
+      "src/core/profiling/timers.h", 
+      "src/core/profiling/timers_preciseclock.h", 
+      "src/core/surface/byte_buffer_queue.h", 
+      "src/core/surface/call.h", 
+      "src/core/surface/channel.h", 
+      "src/core/surface/completion_queue.h", 
+      "src/core/surface/event_string.h", 
+      "src/core/surface/init.h", 
+      "src/core/surface/server.h", 
+      "src/core/surface/surface_trace.h", 
+      "src/core/transport/chttp2/alpn.h", 
+      "src/core/transport/chttp2/bin_encoder.h", 
+      "src/core/transport/chttp2/frame.h", 
+      "src/core/transport/chttp2/frame_data.h", 
+      "src/core/transport/chttp2/frame_goaway.h", 
+      "src/core/transport/chttp2/frame_ping.h", 
+      "src/core/transport/chttp2/frame_rst_stream.h", 
+      "src/core/transport/chttp2/frame_settings.h", 
+      "src/core/transport/chttp2/frame_window_update.h", 
+      "src/core/transport/chttp2/hpack_parser.h", 
+      "src/core/transport/chttp2/hpack_table.h", 
+      "src/core/transport/chttp2/http2_errors.h", 
+      "src/core/transport/chttp2/huffsyms.h", 
+      "src/core/transport/chttp2/incoming_metadata.h", 
+      "src/core/transport/chttp2/internal.h", 
+      "src/core/transport/chttp2/status_conversion.h", 
+      "src/core/transport/chttp2/stream_encoder.h", 
+      "src/core/transport/chttp2/stream_map.h", 
+      "src/core/transport/chttp2/timeout_encoding.h", 
+      "src/core/transport/chttp2/varint.h", 
+      "src/core/transport/chttp2_transport.h", 
+      "src/core/transport/connectivity_state.h", 
+      "src/core/transport/metadata.h", 
+      "src/core/transport/stream_op.h", 
+      "src/core/transport/transport.h", 
+      "src/core/transport/transport_impl.h"
+    ], 
+    "language": "c", 
+    "name": "grpc_unsecure", 
+    "src": [
+      "include/grpc/byte_buffer.h", 
+      "include/grpc/byte_buffer_reader.h", 
+      "include/grpc/census.h", 
+      "include/grpc/compression.h", 
+      "include/grpc/grpc.h", 
+      "include/grpc/status.h", 
+      "src/core/census/context.c", 
+      "src/core/census/context.h", 
+      "src/core/census/grpc_context.c", 
+      "src/core/census/grpc_context.h", 
+      "src/core/census/initialize.c", 
+      "src/core/channel/census_filter.h", 
+      "src/core/channel/channel_args.c", 
+      "src/core/channel/channel_args.h", 
+      "src/core/channel/channel_stack.c", 
+      "src/core/channel/channel_stack.h", 
+      "src/core/channel/client_channel.c", 
+      "src/core/channel/client_channel.h", 
+      "src/core/channel/compress_filter.c", 
+      "src/core/channel/compress_filter.h", 
+      "src/core/channel/connected_channel.c", 
+      "src/core/channel/connected_channel.h", 
+      "src/core/channel/context.h", 
+      "src/core/channel/http_client_filter.c", 
+      "src/core/channel/http_client_filter.h", 
+      "src/core/channel/http_server_filter.c", 
+      "src/core/channel/http_server_filter.h", 
+      "src/core/channel/noop_filter.c", 
+      "src/core/channel/noop_filter.h", 
+      "src/core/client_config/client_config.c", 
+      "src/core/client_config/client_config.h", 
+      "src/core/client_config/connector.c", 
+      "src/core/client_config/connector.h", 
+      "src/core/client_config/lb_policies/pick_first.c", 
+      "src/core/client_config/lb_policies/pick_first.h", 
+      "src/core/client_config/lb_policy.c", 
+      "src/core/client_config/lb_policy.h", 
+      "src/core/client_config/resolver.c", 
+      "src/core/client_config/resolver.h", 
+      "src/core/client_config/resolver_factory.c", 
+      "src/core/client_config/resolver_factory.h", 
+      "src/core/client_config/resolver_registry.c", 
+      "src/core/client_config/resolver_registry.h", 
+      "src/core/client_config/resolvers/dns_resolver.c", 
+      "src/core/client_config/resolvers/dns_resolver.h", 
+      "src/core/client_config/resolvers/unix_resolver_posix.c", 
+      "src/core/client_config/resolvers/unix_resolver_posix.h", 
+      "src/core/client_config/subchannel.c", 
+      "src/core/client_config/subchannel.h", 
+      "src/core/client_config/subchannel_factory.c", 
+      "src/core/client_config/subchannel_factory.h", 
+      "src/core/client_config/uri_parser.c", 
+      "src/core/client_config/uri_parser.h", 
+      "src/core/compression/algorithm.c", 
+      "src/core/compression/message_compress.c", 
+      "src/core/compression/message_compress.h", 
+      "src/core/debug/trace.c", 
+      "src/core/debug/trace.h", 
+      "src/core/iomgr/alarm.c", 
+      "src/core/iomgr/alarm.h", 
+      "src/core/iomgr/alarm_heap.c", 
+      "src/core/iomgr/alarm_heap.h", 
+      "src/core/iomgr/alarm_internal.h", 
+      "src/core/iomgr/endpoint.c", 
+      "src/core/iomgr/endpoint.h", 
+      "src/core/iomgr/endpoint_pair.h", 
+      "src/core/iomgr/endpoint_pair_posix.c", 
+      "src/core/iomgr/endpoint_pair_windows.c", 
+      "src/core/iomgr/fd_posix.c", 
+      "src/core/iomgr/fd_posix.h", 
+      "src/core/iomgr/iocp_windows.c", 
+      "src/core/iomgr/iocp_windows.h", 
+      "src/core/iomgr/iomgr.c", 
+      "src/core/iomgr/iomgr.h", 
+      "src/core/iomgr/iomgr_internal.h", 
+      "src/core/iomgr/iomgr_posix.c", 
+      "src/core/iomgr/iomgr_posix.h", 
+      "src/core/iomgr/iomgr_windows.c", 
+      "src/core/iomgr/pollset.h", 
+      "src/core/iomgr/pollset_kick_posix.c", 
+      "src/core/iomgr/pollset_kick_posix.h", 
+      "src/core/iomgr/pollset_multipoller_with_epoll.c", 
+      "src/core/iomgr/pollset_multipoller_with_poll_posix.c", 
+      "src/core/iomgr/pollset_posix.c", 
+      "src/core/iomgr/pollset_posix.h", 
+      "src/core/iomgr/pollset_set.h", 
+      "src/core/iomgr/pollset_set_posix.c", 
+      "src/core/iomgr/pollset_set_posix.h", 
+      "src/core/iomgr/pollset_set_windows.c", 
+      "src/core/iomgr/pollset_set_windows.h", 
+      "src/core/iomgr/pollset_windows.c", 
+      "src/core/iomgr/pollset_windows.h", 
+      "src/core/iomgr/resolve_address.h", 
+      "src/core/iomgr/resolve_address_posix.c", 
+      "src/core/iomgr/resolve_address_windows.c", 
+      "src/core/iomgr/sockaddr.h", 
+      "src/core/iomgr/sockaddr_posix.h", 
+      "src/core/iomgr/sockaddr_utils.c", 
+      "src/core/iomgr/sockaddr_utils.h", 
+      "src/core/iomgr/sockaddr_win32.h", 
+      "src/core/iomgr/socket_utils_common_posix.c", 
+      "src/core/iomgr/socket_utils_linux.c", 
+      "src/core/iomgr/socket_utils_posix.c", 
+      "src/core/iomgr/socket_utils_posix.h", 
+      "src/core/iomgr/socket_windows.c", 
+      "src/core/iomgr/socket_windows.h", 
+      "src/core/iomgr/tcp_client.h", 
+      "src/core/iomgr/tcp_client_posix.c", 
+      "src/core/iomgr/tcp_client_windows.c", 
+      "src/core/iomgr/tcp_posix.c", 
+      "src/core/iomgr/tcp_posix.h", 
+      "src/core/iomgr/tcp_server.h", 
+      "src/core/iomgr/tcp_server_posix.c", 
+      "src/core/iomgr/tcp_server_windows.c", 
+      "src/core/iomgr/tcp_windows.c", 
+      "src/core/iomgr/tcp_windows.h", 
+      "src/core/iomgr/time_averaged_stats.c", 
+      "src/core/iomgr/time_averaged_stats.h", 
+      "src/core/iomgr/wakeup_fd_eventfd.c", 
+      "src/core/iomgr/wakeup_fd_nospecial.c", 
+      "src/core/iomgr/wakeup_fd_pipe.c", 
+      "src/core/iomgr/wakeup_fd_pipe.h", 
+      "src/core/iomgr/wakeup_fd_posix.c", 
+      "src/core/iomgr/wakeup_fd_posix.h", 
+      "src/core/json/json.c", 
+      "src/core/json/json.h", 
+      "src/core/json/json_common.h", 
+      "src/core/json/json_reader.c", 
+      "src/core/json/json_reader.h", 
+      "src/core/json/json_string.c", 
+      "src/core/json/json_writer.c", 
+      "src/core/json/json_writer.h", 
+      "src/core/profiling/basic_timers.c", 
+      "src/core/profiling/stap_timers.c", 
+      "src/core/profiling/timers.h", 
+      "src/core/profiling/timers_preciseclock.h", 
+      "src/core/surface/byte_buffer.c", 
+      "src/core/surface/byte_buffer_queue.c", 
+      "src/core/surface/byte_buffer_queue.h", 
+      "src/core/surface/byte_buffer_reader.c", 
+      "src/core/surface/call.c", 
+      "src/core/surface/call.h", 
+      "src/core/surface/call_details.c", 
+      "src/core/surface/call_log_batch.c", 
+      "src/core/surface/channel.c", 
+      "src/core/surface/channel.h", 
+      "src/core/surface/channel_create.c", 
+      "src/core/surface/completion_queue.c", 
+      "src/core/surface/completion_queue.h", 
+      "src/core/surface/event_string.c", 
+      "src/core/surface/event_string.h", 
+      "src/core/surface/init.c", 
+      "src/core/surface/init.h", 
+      "src/core/surface/init_unsecure.c", 
+      "src/core/surface/lame_client.c", 
+      "src/core/surface/metadata_array.c", 
+      "src/core/surface/server.c", 
+      "src/core/surface/server.h", 
+      "src/core/surface/server_chttp2.c", 
+      "src/core/surface/server_create.c", 
+      "src/core/surface/surface_trace.c", 
+      "src/core/surface/surface_trace.h", 
+      "src/core/surface/version.c", 
+      "src/core/transport/chttp2/alpn.c", 
+      "src/core/transport/chttp2/alpn.h", 
+      "src/core/transport/chttp2/bin_encoder.c", 
+      "src/core/transport/chttp2/bin_encoder.h", 
+      "src/core/transport/chttp2/frame.h", 
+      "src/core/transport/chttp2/frame_data.c", 
+      "src/core/transport/chttp2/frame_data.h", 
+      "src/core/transport/chttp2/frame_goaway.c", 
+      "src/core/transport/chttp2/frame_goaway.h", 
+      "src/core/transport/chttp2/frame_ping.c", 
+      "src/core/transport/chttp2/frame_ping.h", 
+      "src/core/transport/chttp2/frame_rst_stream.c", 
+      "src/core/transport/chttp2/frame_rst_stream.h", 
+      "src/core/transport/chttp2/frame_settings.c", 
+      "src/core/transport/chttp2/frame_settings.h", 
+      "src/core/transport/chttp2/frame_window_update.c", 
+      "src/core/transport/chttp2/frame_window_update.h", 
+      "src/core/transport/chttp2/hpack_parser.c", 
+      "src/core/transport/chttp2/hpack_parser.h", 
+      "src/core/transport/chttp2/hpack_table.c", 
+      "src/core/transport/chttp2/hpack_table.h", 
+      "src/core/transport/chttp2/http2_errors.h", 
+      "src/core/transport/chttp2/huffsyms.c", 
+      "src/core/transport/chttp2/huffsyms.h", 
+      "src/core/transport/chttp2/incoming_metadata.c", 
+      "src/core/transport/chttp2/incoming_metadata.h", 
+      "src/core/transport/chttp2/internal.h", 
+      "src/core/transport/chttp2/parsing.c", 
+      "src/core/transport/chttp2/status_conversion.c", 
+      "src/core/transport/chttp2/status_conversion.h", 
+      "src/core/transport/chttp2/stream_encoder.c", 
+      "src/core/transport/chttp2/stream_encoder.h", 
+      "src/core/transport/chttp2/stream_lists.c", 
+      "src/core/transport/chttp2/stream_map.c", 
+      "src/core/transport/chttp2/stream_map.h", 
+      "src/core/transport/chttp2/timeout_encoding.c", 
+      "src/core/transport/chttp2/timeout_encoding.h", 
+      "src/core/transport/chttp2/varint.c", 
+      "src/core/transport/chttp2/varint.h", 
+      "src/core/transport/chttp2/writing.c", 
+      "src/core/transport/chttp2_transport.c", 
+      "src/core/transport/chttp2_transport.h", 
+      "src/core/transport/connectivity_state.c", 
+      "src/core/transport/connectivity_state.h", 
+      "src/core/transport/metadata.c", 
+      "src/core/transport/metadata.h", 
+      "src/core/transport/stream_op.c", 
+      "src/core/transport/stream_op.h", 
+      "src/core/transport/transport.c", 
+      "src/core/transport/transport.h", 
+      "src/core/transport/transport_impl.h", 
+      "src/core/transport/transport_op_string.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [
+      "include/grpc++/async_generic_service.h", 
+      "include/grpc++/async_unary_call.h", 
+      "include/grpc++/auth_context.h", 
+      "include/grpc++/auth_property_iterator.h", 
+      "include/grpc++/byte_buffer.h", 
+      "include/grpc++/channel_arguments.h", 
+      "include/grpc++/channel_interface.h", 
+      "include/grpc++/client_context.h", 
+      "include/grpc++/completion_queue.h", 
+      "include/grpc++/config.h", 
+      "include/grpc++/config_protobuf.h", 
+      "include/grpc++/create_channel.h", 
+      "include/grpc++/credentials.h", 
+      "include/grpc++/fixed_size_thread_pool.h", 
+      "include/grpc++/generic_stub.h", 
+      "include/grpc++/impl/call.h", 
+      "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/internal_stub.h", 
+      "include/grpc++/impl/proto_utils.h", 
+      "include/grpc++/impl/rpc_method.h", 
+      "include/grpc++/impl/rpc_service_method.h", 
+      "include/grpc++/impl/serialization_traits.h", 
+      "include/grpc++/impl/service_type.h", 
+      "include/grpc++/impl/sync.h", 
+      "include/grpc++/impl/sync_cxx11.h", 
+      "include/grpc++/impl/sync_no_cxx11.h", 
+      "include/grpc++/impl/thd.h", 
+      "include/grpc++/impl/thd_cxx11.h", 
+      "include/grpc++/impl/thd_no_cxx11.h", 
+      "include/grpc++/server.h", 
+      "include/grpc++/server_builder.h", 
+      "include/grpc++/server_context.h", 
+      "include/grpc++/server_credentials.h", 
+      "include/grpc++/slice.h", 
+      "include/grpc++/status.h", 
+      "include/grpc++/status_code_enum.h", 
+      "include/grpc++/stream.h", 
+      "include/grpc++/thread_pool_interface.h", 
+      "include/grpc++/time.h", 
+      "src/cpp/client/channel.h", 
+      "src/cpp/client/secure_credentials.h", 
+      "src/cpp/common/create_auth_context.h", 
+      "src/cpp/common/secure_auth_context.h", 
+      "src/cpp/server/secure_server_credentials.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++", 
+    "src": [
+      "include/grpc++/async_generic_service.h", 
+      "include/grpc++/async_unary_call.h", 
+      "include/grpc++/auth_context.h", 
+      "include/grpc++/auth_property_iterator.h", 
+      "include/grpc++/byte_buffer.h", 
+      "include/grpc++/channel_arguments.h", 
+      "include/grpc++/channel_interface.h", 
+      "include/grpc++/client_context.h", 
+      "include/grpc++/completion_queue.h", 
+      "include/grpc++/config.h", 
+      "include/grpc++/config_protobuf.h", 
+      "include/grpc++/create_channel.h", 
+      "include/grpc++/credentials.h", 
+      "include/grpc++/fixed_size_thread_pool.h", 
+      "include/grpc++/generic_stub.h", 
+      "include/grpc++/impl/call.h", 
+      "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/internal_stub.h", 
+      "include/grpc++/impl/proto_utils.h", 
+      "include/grpc++/impl/rpc_method.h", 
+      "include/grpc++/impl/rpc_service_method.h", 
+      "include/grpc++/impl/serialization_traits.h", 
+      "include/grpc++/impl/service_type.h", 
+      "include/grpc++/impl/sync.h", 
+      "include/grpc++/impl/sync_cxx11.h", 
+      "include/grpc++/impl/sync_no_cxx11.h", 
+      "include/grpc++/impl/thd.h", 
+      "include/grpc++/impl/thd_cxx11.h", 
+      "include/grpc++/impl/thd_no_cxx11.h", 
+      "include/grpc++/server.h", 
+      "include/grpc++/server_builder.h", 
+      "include/grpc++/server_context.h", 
+      "include/grpc++/server_credentials.h", 
+      "include/grpc++/slice.h", 
+      "include/grpc++/status.h", 
+      "include/grpc++/status_code_enum.h", 
+      "include/grpc++/stream.h", 
+      "include/grpc++/thread_pool_interface.h", 
+      "include/grpc++/time.h", 
+      "src/cpp/client/channel.cc", 
+      "src/cpp/client/channel.h", 
+      "src/cpp/client/channel_arguments.cc", 
+      "src/cpp/client/client_context.cc", 
+      "src/cpp/client/create_channel.cc", 
+      "src/cpp/client/credentials.cc", 
+      "src/cpp/client/generic_stub.cc", 
+      "src/cpp/client/insecure_credentials.cc", 
+      "src/cpp/client/internal_stub.cc", 
+      "src/cpp/client/secure_channel_arguments.cc", 
+      "src/cpp/client/secure_credentials.cc", 
+      "src/cpp/client/secure_credentials.h", 
+      "src/cpp/common/auth_property_iterator.cc", 
+      "src/cpp/common/call.cc", 
+      "src/cpp/common/completion_queue.cc", 
+      "src/cpp/common/create_auth_context.h", 
+      "src/cpp/common/rpc_method.cc", 
+      "src/cpp/common/secure_auth_context.cc", 
+      "src/cpp/common/secure_auth_context.h", 
+      "src/cpp/common/secure_create_auth_context.cc", 
+      "src/cpp/proto/proto_utils.cc", 
+      "src/cpp/server/async_generic_service.cc", 
+      "src/cpp/server/create_default_thread_pool.cc", 
+      "src/cpp/server/fixed_size_thread_pool.cc", 
+      "src/cpp/server/insecure_server_credentials.cc", 
+      "src/cpp/server/secure_server_credentials.cc", 
+      "src/cpp/server/secure_server_credentials.h", 
+      "src/cpp/server/server.cc", 
+      "src/cpp/server/server_builder.cc", 
+      "src/cpp/server/server_context.cc", 
+      "src/cpp/server/server_credentials.cc", 
+      "src/cpp/util/byte_buffer.cc", 
+      "src/cpp/util/slice.cc", 
+      "src/cpp/util/status.cc", 
+      "src/cpp/util/time.cc"
+    ]
+  }, 
+  {
+    "deps": [], 
+    "headers": [
+      "test/cpp/util/test_config.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++_test_config", 
+    "src": [
+      "test/cpp/util/test_config.cc", 
+      "test/cpp/util/test_config.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/cpp/util/cli_call.h", 
+      "test/cpp/util/create_test_channel.h", 
+      "test/cpp/util/echo.grpc.pb.h", 
+      "test/cpp/util/echo.pb.h", 
+      "test/cpp/util/echo_duplicate.grpc.pb.h", 
+      "test/cpp/util/echo_duplicate.pb.h", 
+      "test/cpp/util/fake_credentials.h", 
+      "test/cpp/util/messages.grpc.pb.h", 
+      "test/cpp/util/messages.pb.h", 
+      "test/cpp/util/subprocess.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++_test_util", 
+    "src": [
+      "test/cpp/util/cli_call.cc", 
+      "test/cpp/util/cli_call.h", 
+      "test/cpp/util/create_test_channel.cc", 
+      "test/cpp/util/create_test_channel.h", 
+      "test/cpp/util/fake_credentials.cc", 
+      "test/cpp/util/fake_credentials.h", 
+      "test/cpp/util/subprocess.cc", 
+      "test/cpp/util/subprocess.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "include/grpc++/async_generic_service.h", 
+      "include/grpc++/async_unary_call.h", 
+      "include/grpc++/auth_context.h", 
+      "include/grpc++/auth_property_iterator.h", 
+      "include/grpc++/byte_buffer.h", 
+      "include/grpc++/channel_arguments.h", 
+      "include/grpc++/channel_interface.h", 
+      "include/grpc++/client_context.h", 
+      "include/grpc++/completion_queue.h", 
+      "include/grpc++/config.h", 
+      "include/grpc++/config_protobuf.h", 
+      "include/grpc++/create_channel.h", 
+      "include/grpc++/credentials.h", 
+      "include/grpc++/fixed_size_thread_pool.h", 
+      "include/grpc++/generic_stub.h", 
+      "include/grpc++/impl/call.h", 
+      "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/internal_stub.h", 
+      "include/grpc++/impl/proto_utils.h", 
+      "include/grpc++/impl/rpc_method.h", 
+      "include/grpc++/impl/rpc_service_method.h", 
+      "include/grpc++/impl/serialization_traits.h", 
+      "include/grpc++/impl/service_type.h", 
+      "include/grpc++/impl/sync.h", 
+      "include/grpc++/impl/sync_cxx11.h", 
+      "include/grpc++/impl/sync_no_cxx11.h", 
+      "include/grpc++/impl/thd.h", 
+      "include/grpc++/impl/thd_cxx11.h", 
+      "include/grpc++/impl/thd_no_cxx11.h", 
+      "include/grpc++/server.h", 
+      "include/grpc++/server_builder.h", 
+      "include/grpc++/server_context.h", 
+      "include/grpc++/server_credentials.h", 
+      "include/grpc++/slice.h", 
+      "include/grpc++/status.h", 
+      "include/grpc++/status_code_enum.h", 
+      "include/grpc++/stream.h", 
+      "include/grpc++/thread_pool_interface.h", 
+      "include/grpc++/time.h", 
+      "src/cpp/client/channel.h", 
+      "src/cpp/common/create_auth_context.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++_unsecure", 
+    "src": [
+      "include/grpc++/async_generic_service.h", 
+      "include/grpc++/async_unary_call.h", 
+      "include/grpc++/auth_context.h", 
+      "include/grpc++/auth_property_iterator.h", 
+      "include/grpc++/byte_buffer.h", 
+      "include/grpc++/channel_arguments.h", 
+      "include/grpc++/channel_interface.h", 
+      "include/grpc++/client_context.h", 
+      "include/grpc++/completion_queue.h", 
+      "include/grpc++/config.h", 
+      "include/grpc++/config_protobuf.h", 
+      "include/grpc++/create_channel.h", 
+      "include/grpc++/credentials.h", 
+      "include/grpc++/fixed_size_thread_pool.h", 
+      "include/grpc++/generic_stub.h", 
+      "include/grpc++/impl/call.h", 
+      "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/internal_stub.h", 
+      "include/grpc++/impl/proto_utils.h", 
+      "include/grpc++/impl/rpc_method.h", 
+      "include/grpc++/impl/rpc_service_method.h", 
+      "include/grpc++/impl/serialization_traits.h", 
+      "include/grpc++/impl/service_type.h", 
+      "include/grpc++/impl/sync.h", 
+      "include/grpc++/impl/sync_cxx11.h", 
+      "include/grpc++/impl/sync_no_cxx11.h", 
+      "include/grpc++/impl/thd.h", 
+      "include/grpc++/impl/thd_cxx11.h", 
+      "include/grpc++/impl/thd_no_cxx11.h", 
+      "include/grpc++/server.h", 
+      "include/grpc++/server_builder.h", 
+      "include/grpc++/server_context.h", 
+      "include/grpc++/server_credentials.h", 
+      "include/grpc++/slice.h", 
+      "include/grpc++/status.h", 
+      "include/grpc++/status_code_enum.h", 
+      "include/grpc++/stream.h", 
+      "include/grpc++/thread_pool_interface.h", 
+      "include/grpc++/time.h", 
+      "src/cpp/client/channel.cc", 
+      "src/cpp/client/channel.h", 
+      "src/cpp/client/channel_arguments.cc", 
+      "src/cpp/client/client_context.cc", 
+      "src/cpp/client/create_channel.cc", 
+      "src/cpp/client/credentials.cc", 
+      "src/cpp/client/generic_stub.cc", 
+      "src/cpp/client/insecure_credentials.cc", 
+      "src/cpp/client/internal_stub.cc", 
+      "src/cpp/common/call.cc", 
+      "src/cpp/common/completion_queue.cc", 
+      "src/cpp/common/create_auth_context.h", 
+      "src/cpp/common/insecure_create_auth_context.cc", 
+      "src/cpp/common/rpc_method.cc", 
+      "src/cpp/proto/proto_utils.cc", 
+      "src/cpp/server/async_generic_service.cc", 
+      "src/cpp/server/create_default_thread_pool.cc", 
+      "src/cpp/server/fixed_size_thread_pool.cc", 
+      "src/cpp/server/insecure_server_credentials.cc", 
+      "src/cpp/server/server.cc", 
+      "src/cpp/server/server_builder.cc", 
+      "src/cpp/server/server_context.cc", 
+      "src/cpp/server/server_credentials.cc", 
+      "src/cpp/util/byte_buffer.cc", 
+      "src/cpp/util/slice.cc", 
+      "src/cpp/util/status.cc", 
+      "src/cpp/util/time.cc"
+    ]
+  }, 
+  {
+    "deps": [], 
+    "headers": [
+      "include/grpc++/config.h", 
+      "include/grpc++/config_protobuf.h", 
+      "src/compiler/config.h", 
+      "src/compiler/cpp_generator.h", 
+      "src/compiler/cpp_generator_helpers.h", 
+      "src/compiler/csharp_generator.h", 
+      "src/compiler/csharp_generator_helpers.h", 
+      "src/compiler/generator_helpers.h", 
+      "src/compiler/objective_c_generator.h", 
+      "src/compiler/objective_c_generator_helpers.h", 
+      "src/compiler/python_generator.h", 
+      "src/compiler/ruby_generator.h", 
+      "src/compiler/ruby_generator_helpers-inl.h", 
+      "src/compiler/ruby_generator_map-inl.h", 
+      "src/compiler/ruby_generator_string-inl.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc_plugin_support", 
+    "src": [
+      "include/grpc++/config.h", 
+      "include/grpc++/config_protobuf.h", 
+      "src/compiler/config.h", 
+      "src/compiler/cpp_generator.cc", 
+      "src/compiler/cpp_generator.h", 
+      "src/compiler/cpp_generator_helpers.h", 
+      "src/compiler/csharp_generator.cc", 
+      "src/compiler/csharp_generator.h", 
+      "src/compiler/csharp_generator_helpers.h", 
+      "src/compiler/generator_helpers.h", 
+      "src/compiler/objective_c_generator.cc", 
+      "src/compiler/objective_c_generator.h", 
+      "src/compiler/objective_c_generator_helpers.h", 
+      "src/compiler/python_generator.cc", 
+      "src/compiler/python_generator.h", 
+      "src/compiler/ruby_generator.cc", 
+      "src/compiler/ruby_generator.h", 
+      "src/compiler/ruby_generator_helpers-inl.h", 
+      "src/compiler/ruby_generator_map-inl.h", 
+      "src/compiler/ruby_generator_string-inl.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/cpp/interop/client_helper.h"
+    ], 
+    "language": "c++", 
+    "name": "interop_client_helper", 
+    "src": [
+      "test/cpp/interop/client_helper.cc", 
+      "test/cpp/interop/client_helper.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "interop_client_helper"
+    ], 
+    "headers": [
+      "test/cpp/interop/interop_client.h", 
+      "test/proto/empty.grpc.pb.h", 
+      "test/proto/empty.pb.h", 
+      "test/proto/messages.grpc.pb.h", 
+      "test/proto/messages.pb.h", 
+      "test/proto/test.grpc.pb.h", 
+      "test/proto/test.pb.h"
+    ], 
+    "language": "c++", 
+    "name": "interop_client_main", 
+    "src": [
+      "test/cpp/interop/client.cc", 
+      "test/cpp/interop/interop_client.cc", 
+      "test/cpp/interop/interop_client.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/cpp/interop/server_helper.h"
+    ], 
+    "language": "c++", 
+    "name": "interop_server_helper", 
+    "src": [
+      "test/cpp/interop/server_helper.cc", 
+      "test/cpp/interop/server_helper.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "interop_server_helper"
+    ], 
+    "headers": [
+      "test/proto/empty.grpc.pb.h", 
+      "test/proto/empty.pb.h", 
+      "test/proto/messages.grpc.pb.h", 
+      "test/proto/messages.pb.h", 
+      "test/proto/test.grpc.pb.h", 
+      "test/proto/test.pb.h"
+    ], 
+    "language": "c++", 
+    "name": "interop_server_main", 
+    "src": [
+      "test/cpp/interop/server.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc", 
+      "grpc++"
+    ], 
+    "headers": [
+      "examples/pubsub/empty.grpc.pb.h", 
+      "examples/pubsub/empty.pb.h", 
+      "examples/pubsub/label.grpc.pb.h", 
+      "examples/pubsub/label.pb.h", 
+      "examples/pubsub/publisher.h", 
+      "examples/pubsub/pubsub.grpc.pb.h", 
+      "examples/pubsub/pubsub.pb.h", 
+      "examples/pubsub/subscriber.h"
+    ], 
+    "language": "c++", 
+    "name": "pubsub_client_lib", 
+    "src": [
+      "examples/pubsub/publisher.cc", 
+      "examples/pubsub/publisher.h", 
+      "examples/pubsub/subscriber.cc", 
+      "examples/pubsub/subscriber.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/cpp/qps/client.h", 
+      "test/cpp/qps/driver.h", 
+      "test/cpp/qps/histogram.h", 
+      "test/cpp/qps/interarrival.h", 
+      "test/cpp/qps/perf_db.grpc.pb.h", 
+      "test/cpp/qps/perf_db.pb.h", 
+      "test/cpp/qps/perf_db_client.h", 
+      "test/cpp/qps/qps_worker.h", 
+      "test/cpp/qps/qpstest.grpc.pb.h", 
+      "test/cpp/qps/qpstest.pb.h", 
+      "test/cpp/qps/report.h", 
+      "test/cpp/qps/server.h", 
+      "test/cpp/qps/stats.h", 
+      "test/cpp/qps/timer.h", 
+      "test/cpp/util/benchmark_config.h"
+    ], 
+    "language": "c++", 
+    "name": "qps", 
+    "src": [
+      "test/cpp/qps/client.h", 
+      "test/cpp/qps/client_async.cc", 
+      "test/cpp/qps/client_sync.cc", 
+      "test/cpp/qps/driver.cc", 
+      "test/cpp/qps/driver.h", 
+      "test/cpp/qps/histogram.h", 
+      "test/cpp/qps/interarrival.h", 
+      "test/cpp/qps/perf_db_client.cc", 
+      "test/cpp/qps/perf_db_client.h", 
+      "test/cpp/qps/qps_worker.cc", 
+      "test/cpp/qps/qps_worker.h", 
+      "test/cpp/qps/report.cc", 
+      "test/cpp/qps/report.h", 
+      "test/cpp/qps/server.h", 
+      "test/cpp/qps/server_async.cc", 
+      "test/cpp/qps/server_sync.cc", 
+      "test/cpp/qps/stats.h", 
+      "test/cpp/qps/timer.cc", 
+      "test/cpp/qps/timer.h", 
+      "test/cpp/util/benchmark_config.cc", 
+      "test/cpp/util/benchmark_config.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "language": "csharp", 
+    "name": "grpc_csharp_ext", 
+    "src": [
+      "src/csharp/ext/grpc_csharp_ext.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_fake_security", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_fake_security.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_fullstack", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_fullstack.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_fullstack_compression", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_fullstack_compression.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_fullstack_uds_posix", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_fullstack_with_poll", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_fullstack_with_poll.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_simple_ssl_fullstack", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_simple_ssl_fullstack_with_poll", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_socket_pair", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_socket_pair.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_socket_pair_one_byte_at_a_time", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_fixture_chttp2_socket_pair_with_grpc_trace", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_bad_hostname", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/bad_hostname.c", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_cancel_after_accept", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_after_accept.c", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_cancel_after_accept_and_writes_closed", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_after_accept_and_writes_closed.c", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_cancel_after_invoke", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_after_invoke.c", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_cancel_before_invoke", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_before_invoke.c", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_cancel_in_a_vacuum", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_in_a_vacuum.c", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_census_simple_request", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/census_simple_request.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_disappearing_server", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/disappearing_server.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_early_server_shutdown_finishes_inflight_calls", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_early_server_shutdown_finishes_tags", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/early_server_shutdown_finishes_tags.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_empty_batch", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/empty_batch.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_graceful_server_shutdown", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/graceful_server_shutdown.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_invoke_large_request", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/invoke_large_request.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_max_concurrent_streams", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/max_concurrent_streams.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_max_message_length", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/max_message_length.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_no_op", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/no_op.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_ping_pong_streaming", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/ping_pong_streaming.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_registered_call", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/registered_call.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_response_with_binary_metadata_and_payload", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_response_with_metadata_and_payload", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_response_with_metadata_and_payload.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_response_with_payload", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_response_with_payload.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "end2end_certs", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_response_with_payload_and_call_creds", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_response_with_payload_and_call_creds.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_response_with_trailing_metadata_and_payload", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_with_compressed_payload", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_with_compressed_payload.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_with_flags", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_with_flags.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_with_large_metadata", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_with_large_metadata.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_request_with_payload", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/request_with_payload.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_server_finishes_request", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/server_finishes_request.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_simple_delayed_request", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/simple_delayed_request.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_simple_request", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/simple_request.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h"
+    ], 
+    "language": "c", 
+    "name": "end2end_test_simple_request_with_high_initial_sequence_number", 
+    "src": [
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/tests/cancel_test_helpers.h", 
+      "test/core/end2end/tests/simple_request_with_high_initial_sequence_number.c"
+    ]
+  }, 
+  {
+    "deps": [], 
+    "headers": [], 
+    "language": "c", 
+    "name": "end2end_certs", 
+    "src": [
+      "test/core/end2end/data/server1_cert.c", 
+      "test/core/end2end/data/server1_key.c", 
+      "test/core/end2end/data/test_root_cert.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [
+      "test/core/bad_client/bad_client.h"
+    ], 
+    "language": "c", 
+    "name": "bad_client_test", 
+    "src": [
+      "test/core/bad_client/bad_client.c", 
+      "test/core/bad_client/bad_client.h"
+    ]
+  }
+]
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 77b3345..98ef004 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -84,6 +84,14 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "fd_conservation_posix_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "fd_posix_test", 
     "platforms": [
       "posix"
@@ -189,6 +197,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "gpr_stack_lockfree_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "gpr_string_test", 
     "platforms": [
       "windows", 
@@ -306,6 +323,24 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "grpc_jwt_verifier_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "grpc_security_connector_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "grpc_stream_op_test", 
     "platforms": [
       "windows", 
@@ -404,6 +439,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "multiple_server_queues_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "murmur_hash_test", 
     "platforms": [
       "windows", 
@@ -490,15 +534,6 @@
   {
     "flaky": false, 
     "language": "c", 
-    "name": "time_test", 
-    "platforms": [
-      "windows", 
-      "posix"
-    ]
-  }, 
-  {
-    "flaky": false, 
-    "language": "c", 
     "name": "timeout_encoding_test", 
     "platforms": [
       "windows", 
@@ -534,6 +569,15 @@
   }, 
   {
     "flaky": false, 
+    "language": "c", 
+    "name": "uri_parser_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
     "language": "c++", 
     "name": "async_end2end_test", 
     "platforms": [
@@ -562,6 +606,15 @@
   {
     "flaky": false, 
     "language": "c++", 
+    "name": "auth_property_iterator_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
     "name": "channel_arguments_test", 
     "platforms": [
       "windows", 
@@ -598,6 +651,24 @@
   {
     "flaky": false, 
     "language": "c++", 
+    "name": "cxx_byte_buffer_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
+    "name": "cxx_slice_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
     "name": "cxx_time_test", 
     "platforms": [
       "windows", 
@@ -616,6 +687,15 @@
   {
     "flaky": false, 
     "language": "c++", 
+    "name": "fixed_size_thread_pool_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
     "name": "generic_end2end_test", 
     "platforms": [
       "windows", 
@@ -643,6 +723,15 @@
   {
     "flaky": false, 
     "language": "c++", 
+    "name": "qps_openloop_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
     "name": "qps_test", 
     "platforms": [
       "windows", 
@@ -652,7 +741,7 @@
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "qps_test_openloop", 
+    "name": "secure_auth_context_test", 
     "platforms": [
       "windows", 
       "posix"
@@ -697,15 +786,6 @@
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "thread_pool_test", 
-    "platforms": [
-      "windows", 
-      "posix"
-    ]
-  }, 
-  {
-    "flaky": false, 
-    "language": "c++", 
     "name": "thread_stress_test", 
     "platforms": [
       "windows", 
@@ -722,7 +802,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fake_security_cancel_after_accept_test", 
     "platforms": [
@@ -821,7 +901,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fake_security_invoke_large_request_test", 
     "platforms": [
@@ -922,6 +1002,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fake_security_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fake_security_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -992,7 +1081,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fullstack_cancel_after_accept_test", 
     "platforms": [
@@ -1091,7 +1180,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fullstack_invoke_large_request_test", 
     "platforms": [
@@ -1192,6 +1281,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -1255,13 +1353,292 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_compression_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_message_length_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_registered_call_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_flags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_server_finishes_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_uds_posix_bad_hostname_test", 
     "platforms": [
       "posix"
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fullstack_uds_posix_cancel_after_accept_test", 
     "platforms": [
@@ -1349,7 +1726,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fullstack_uds_posix_invoke_large_request_test", 
     "platforms": [
@@ -1439,6 +1816,14 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_compressed_payload_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_uds_posix_request_with_flags_test", 
     "platforms": [
       "posix"
@@ -1501,7 +1886,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fullstack_with_poll_cancel_after_accept_test", 
     "platforms": [
@@ -1589,7 +1974,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_fullstack_with_poll_invoke_large_request_test", 
     "platforms": [
@@ -1679,6 +2064,14 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_compressed_payload_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_with_poll_request_with_flags_test", 
     "platforms": [
       "posix"
@@ -1742,7 +2135,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_test", 
     "platforms": [
@@ -1841,7 +2234,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_simple_ssl_fullstack_invoke_large_request_test", 
     "platforms": [
@@ -1942,6 +2335,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_simple_ssl_fullstack_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -2011,7 +2413,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test", 
     "platforms": [
@@ -2099,7 +2501,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test", 
     "platforms": [
@@ -2189,6 +2591,14 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test", 
     "platforms": [
       "posix"
@@ -2252,7 +2662,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test", 
     "platforms": [
@@ -2351,7 +2761,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test", 
     "platforms": [
@@ -2452,6 +2862,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -2522,7 +2941,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_socket_pair_cancel_after_accept_test", 
     "platforms": [
@@ -2621,7 +3040,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_socket_pair_invoke_large_request_test", 
     "platforms": [
@@ -2722,6 +3141,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_socket_pair_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_socket_pair_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -2792,7 +3220,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test", 
     "platforms": [
@@ -2891,7 +3319,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test", 
     "platforms": [
@@ -2992,6 +3420,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -3062,7 +3499,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test", 
     "platforms": [
@@ -3161,7 +3598,7 @@
     ]
   }, 
   {
-    "flaky": true, 
+    "flaky": false, 
     "language": "c", 
     "name": "chttp2_socket_pair_with_grpc_trace_invoke_large_request_test", 
     "platforms": [
@@ -3262,6 +3699,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_socket_pair_with_grpc_trace_request_with_flags_test", 
     "platforms": [
       "windows", 
@@ -3523,6 +3969,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_request_with_flags_unsecure_test", 
     "platforms": [
       "windows", 
@@ -3586,6 +4041,276 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_compression_bad_hostname_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_after_invoke_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_before_invoke_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_census_simple_request_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_disappearing_server_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_empty_batch_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": true, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_invoke_large_request_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_concurrent_streams_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_max_message_length_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_no_op_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_ping_pong_streaming_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_registered_call_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_flags_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_large_metadata_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_request_with_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_server_finishes_request_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_delayed_request_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_uds_posix_bad_hostname_unsecure_test", 
     "platforms": [
       "posix"
@@ -3762,6 +4487,14 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_uds_posix_request_with_flags_unsecure_test", 
     "platforms": [
       "posix"
@@ -3994,6 +4727,14 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_fullstack_with_poll_request_with_flags_unsecure_test", 
     "platforms": [
       "posix"
@@ -4248,6 +4989,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_socket_pair_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_socket_pair_request_with_flags_unsecure_test", 
     "platforms": [
       "windows", 
@@ -4509,6 +5259,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test", 
     "platforms": [
       "windows", 
@@ -4770,6 +5529,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test", 
     "platforms": [
       "windows", 
diff --git a/vsprojects/Grpc.mak b/vsprojects/Grpc.mak
index f7c4988..30ae286 100644
--- a/vsprojects/Grpc.mak
+++ b/vsprojects/Grpc.mak
@@ -51,13 +51,19 @@
 
 all: buildtests
 
+tools:
+
+tools_c:
+
+tools_cxx:
+
 $(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\end2end_fixture_chttp2_fake_security.lib Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack.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_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_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\end2end_fixture_chttp2_fake_security.lib Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack.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_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_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_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 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 time_test.exe timeout_encoding_test.exe timers_test.exe transport_metadata_test.exe transport_security_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_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_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_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_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_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_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_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_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_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_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_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_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_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_disappearing_server_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_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_delayed_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_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_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_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_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_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_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_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_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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_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_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_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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_disappearing_server_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_delayed_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 tests built.
 
 buildtests_cxx: interop_client.exe interop_server.exe 
@@ -135,8 +141,8 @@
 	$(OUT_DIR)\fling_server.exe
 gen_hpack_tables.exe: build_libs $(OUT_DIR)
 	echo Building gen_hpack_tables
-	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\src\core\transport\chttp2\gen_hpack_tables.c 
-	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gen_hpack_tables.exe" Debug\grpc_test_util.lib Debug\gpr.lib Debug\grpc.lib $(LIBS) $(OUT_DIR)\gen_hpack_tables.obj 
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\tools\codegen\core\gen_hpack_tables.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gen_hpack_tables.exe" Debug\gpr.lib Debug\grpc.lib $(LIBS) $(OUT_DIR)\gen_hpack_tables.obj 
 gen_hpack_tables: gen_hpack_tables.exe
 	echo Running gen_hpack_tables
 	$(OUT_DIR)\gen_hpack_tables.exe
@@ -203,6 +209,13 @@
 gpr_slice_test: gpr_slice_test.exe
 	echo Running gpr_slice_test
 	$(OUT_DIR)\gpr_slice_test.exe
+gpr_stack_lockfree_test.exe: build_libs $(OUT_DIR)
+	echo Building gpr_stack_lockfree_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\stack_lockfree_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_stack_lockfree_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stack_lockfree_test.obj 
+gpr_stack_lockfree_test: gpr_stack_lockfree_test.exe
+	echo Running gpr_stack_lockfree_test
+	$(OUT_DIR)\gpr_stack_lockfree_test.exe
 gpr_string_test.exe: build_libs $(OUT_DIR)
 	echo Building gpr_string_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\string_test.c 
@@ -308,6 +321,13 @@
 grpc_json_token_test: grpc_json_token_test.exe
 	echo Running grpc_json_token_test
 	$(OUT_DIR)\grpc_json_token_test.exe
+grpc_jwt_verifier_test.exe: build_libs $(OUT_DIR)
+	echo Building grpc_jwt_verifier_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\security\jwt_verifier_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_jwt_verifier_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\jwt_verifier_test.obj 
+grpc_jwt_verifier_test: grpc_jwt_verifier_test.exe
+	echo Running grpc_jwt_verifier_test
+	$(OUT_DIR)\grpc_jwt_verifier_test.exe
 grpc_print_google_default_creds_token.exe: build_libs $(OUT_DIR)
 	echo Building grpc_print_google_default_creds_token
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\security\print_google_default_creds_token.c 
@@ -315,6 +335,13 @@
 grpc_print_google_default_creds_token: grpc_print_google_default_creds_token.exe
 	echo Running grpc_print_google_default_creds_token
 	$(OUT_DIR)\grpc_print_google_default_creds_token.exe
+grpc_security_connector_test.exe: build_libs $(OUT_DIR)
+	echo Building grpc_security_connector_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\security\security_connector_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_security_connector_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\security_connector_test.obj 
+grpc_security_connector_test: grpc_security_connector_test.exe
+	echo Running grpc_security_connector_test
+	$(OUT_DIR)\grpc_security_connector_test.exe
 grpc_stream_op_test.exe: build_libs $(OUT_DIR)
 	echo Building grpc_stream_op_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\transport\stream_op_test.c 
@@ -322,6 +349,13 @@
 grpc_stream_op_test: grpc_stream_op_test.exe
 	echo Running grpc_stream_op_test
 	$(OUT_DIR)\grpc_stream_op_test.exe
+grpc_verify_jwt.exe: build_libs $(OUT_DIR)
+	echo Building grpc_verify_jwt
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\security\verify_jwt.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_verify_jwt.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\verify_jwt.obj 
+grpc_verify_jwt: grpc_verify_jwt.exe
+	echo Running grpc_verify_jwt
+	$(OUT_DIR)\grpc_verify_jwt.exe
 hpack_parser_test.exe: build_libs $(OUT_DIR)
 	echo Building hpack_parser_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\transport\chttp2\hpack_parser_test.c 
@@ -399,6 +433,13 @@
 multi_init_test: multi_init_test.exe
 	echo Running multi_init_test
 	$(OUT_DIR)\multi_init_test.exe
+multiple_server_queues_test.exe: build_libs $(OUT_DIR)
+	echo Building multiple_server_queues_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\multiple_server_queues_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\multiple_server_queues_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multiple_server_queues_test.obj 
+multiple_server_queues_test: multiple_server_queues_test.exe
+	echo Running multiple_server_queues_test
+	$(OUT_DIR)\multiple_server_queues_test.exe
 murmur_hash_test.exe: build_libs $(OUT_DIR)
 	echo Building murmur_hash_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\murmur_hash_test.c 
@@ -441,13 +482,6 @@
 time_averaged_stats_test: time_averaged_stats_test.exe
 	echo Running time_averaged_stats_test
 	$(OUT_DIR)\time_averaged_stats_test.exe
-time_test.exe: build_libs $(OUT_DIR)
-	echo Building time_test
-	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\time_test.c 
-	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\time_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_test.obj 
-time_test: time_test.exe
-	echo Running time_test
-	$(OUT_DIR)\time_test.exe
 timeout_encoding_test.exe: build_libs $(OUT_DIR)
 	echo Building timeout_encoding_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\transport\chttp2\timeout_encoding_test.c 
@@ -476,6 +510,13 @@
 transport_security_test: transport_security_test.exe
 	echo Running transport_security_test
 	$(OUT_DIR)\transport_security_test.exe
+uri_parser_test.exe: build_libs $(OUT_DIR)
+	echo Building uri_parser_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\client_config\uri_parser_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\uri_parser_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\uri_parser_test.obj 
+uri_parser_test: uri_parser_test.exe
+	echo Running uri_parser_test
+	$(OUT_DIR)\uri_parser_test.exe
 interop_client.exe: build_libs $(OUT_DIR)
 	echo Building interop_client
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -651,6 +692,13 @@
 chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test: chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test.exe
+chttp2_fake_security_request_with_compressed_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fake_security_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fake_security_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_fake_security.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fake_security_request_with_compressed_payload_test: chttp2_fake_security_request_with_compressed_payload_test.exe
+	echo Running chttp2_fake_security_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_fake_security_request_with_compressed_payload_test.exe
 chttp2_fake_security_request_with_flags_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_fake_security_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -861,6 +909,13 @@
 chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test: chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe
+chttp2_fullstack_request_with_compressed_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_request_with_compressed_payload_test: chttp2_fullstack_request_with_compressed_payload_test.exe
+	echo Running chttp2_fullstack_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_fullstack_request_with_compressed_payload_test.exe
 chttp2_fullstack_request_with_flags_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_fullstack_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -910,6 +965,223 @@
 chttp2_fullstack_simple_request_with_high_initial_sequence_number_test: chttp2_fullstack_simple_request_with_high_initial_sequence_number_test.exe
 	echo Running chttp2_fullstack_simple_request_with_high_initial_sequence_number_test
 	$(OUT_DIR)\chttp2_fullstack_simple_request_with_high_initial_sequence_number_test.exe
+chttp2_fullstack_compression_bad_hostname_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_bad_hostname_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_bad_hostname_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_bad_hostname.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_bad_hostname_test: chttp2_fullstack_compression_bad_hostname_test.exe
+	echo Running chttp2_fullstack_compression_bad_hostname_test
+	$(OUT_DIR)\chttp2_fullstack_compression_bad_hostname_test.exe
+chttp2_fullstack_compression_cancel_after_accept_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_after_accept_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_after_accept.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_after_accept_test: chttp2_fullstack_compression_cancel_after_accept_test.exe
+	echo Running chttp2_fullstack_compression_cancel_after_accept_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_test.exe
+chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_after_accept_and_writes_closed.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test: chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test.exe
+	echo Running chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test.exe
+chttp2_fullstack_compression_cancel_after_invoke_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_after_invoke_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_invoke_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_after_invoke.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_after_invoke_test: chttp2_fullstack_compression_cancel_after_invoke_test.exe
+	echo Running chttp2_fullstack_compression_cancel_after_invoke_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_invoke_test.exe
+chttp2_fullstack_compression_cancel_before_invoke_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_before_invoke_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_before_invoke_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_before_invoke.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_before_invoke_test: chttp2_fullstack_compression_cancel_before_invoke_test.exe
+	echo Running chttp2_fullstack_compression_cancel_before_invoke_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_before_invoke_test.exe
+chttp2_fullstack_compression_cancel_in_a_vacuum_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_in_a_vacuum_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_in_a_vacuum_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_in_a_vacuum.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_in_a_vacuum_test: chttp2_fullstack_compression_cancel_in_a_vacuum_test.exe
+	echo Running chttp2_fullstack_compression_cancel_in_a_vacuum_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_in_a_vacuum_test.exe
+chttp2_fullstack_compression_census_simple_request_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_census_simple_request_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_census_simple_request_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_census_simple_request.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_census_simple_request_test: chttp2_fullstack_compression_census_simple_request_test.exe
+	echo Running chttp2_fullstack_compression_census_simple_request_test
+	$(OUT_DIR)\chttp2_fullstack_compression_census_simple_request_test.exe
+chttp2_fullstack_compression_disappearing_server_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_disappearing_server_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_disappearing_server_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_disappearing_server.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_disappearing_server_test: chttp2_fullstack_compression_disappearing_server_test.exe
+	echo Running chttp2_fullstack_compression_disappearing_server_test
+	$(OUT_DIR)\chttp2_fullstack_compression_disappearing_server_test.exe
+chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_early_server_shutdown_finishes_inflight_calls.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test: chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test.exe
+	echo Running chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test
+	$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test.exe
+chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_early_server_shutdown_finishes_tags.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test: chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test.exe
+	echo Running chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test
+	$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test.exe
+chttp2_fullstack_compression_empty_batch_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_empty_batch_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_empty_batch_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_empty_batch.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_empty_batch_test: chttp2_fullstack_compression_empty_batch_test.exe
+	echo Running chttp2_fullstack_compression_empty_batch_test
+	$(OUT_DIR)\chttp2_fullstack_compression_empty_batch_test.exe
+chttp2_fullstack_compression_graceful_server_shutdown_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_graceful_server_shutdown_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_graceful_server_shutdown_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_graceful_server_shutdown.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_graceful_server_shutdown_test: chttp2_fullstack_compression_graceful_server_shutdown_test.exe
+	echo Running chttp2_fullstack_compression_graceful_server_shutdown_test
+	$(OUT_DIR)\chttp2_fullstack_compression_graceful_server_shutdown_test.exe
+chttp2_fullstack_compression_invoke_large_request_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_invoke_large_request_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_invoke_large_request_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_invoke_large_request.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_invoke_large_request_test: chttp2_fullstack_compression_invoke_large_request_test.exe
+	echo Running chttp2_fullstack_compression_invoke_large_request_test
+	$(OUT_DIR)\chttp2_fullstack_compression_invoke_large_request_test.exe
+chttp2_fullstack_compression_max_concurrent_streams_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_max_concurrent_streams_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_max_concurrent_streams_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_max_concurrent_streams.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_max_concurrent_streams_test: chttp2_fullstack_compression_max_concurrent_streams_test.exe
+	echo Running chttp2_fullstack_compression_max_concurrent_streams_test
+	$(OUT_DIR)\chttp2_fullstack_compression_max_concurrent_streams_test.exe
+chttp2_fullstack_compression_max_message_length_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_max_message_length_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_max_message_length_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_max_message_length.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_max_message_length_test: chttp2_fullstack_compression_max_message_length_test.exe
+	echo Running chttp2_fullstack_compression_max_message_length_test
+	$(OUT_DIR)\chttp2_fullstack_compression_max_message_length_test.exe
+chttp2_fullstack_compression_no_op_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_no_op_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_no_op_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_no_op.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_no_op_test: chttp2_fullstack_compression_no_op_test.exe
+	echo Running chttp2_fullstack_compression_no_op_test
+	$(OUT_DIR)\chttp2_fullstack_compression_no_op_test.exe
+chttp2_fullstack_compression_ping_pong_streaming_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_ping_pong_streaming_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_ping_pong_streaming_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_ping_pong_streaming.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_ping_pong_streaming_test: chttp2_fullstack_compression_ping_pong_streaming_test.exe
+	echo Running chttp2_fullstack_compression_ping_pong_streaming_test
+	$(OUT_DIR)\chttp2_fullstack_compression_ping_pong_streaming_test.exe
+chttp2_fullstack_compression_registered_call_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_registered_call_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_registered_call_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_registered_call.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_registered_call_test: chttp2_fullstack_compression_registered_call_test.exe
+	echo Running chttp2_fullstack_compression_registered_call_test
+	$(OUT_DIR)\chttp2_fullstack_compression_registered_call_test.exe
+chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_binary_metadata_and_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test: chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test.exe
+chttp2_fullstack_compression_request_response_with_metadata_and_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_metadata_and_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_metadata_and_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_metadata_and_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_metadata_and_payload_test: chttp2_fullstack_compression_request_response_with_metadata_and_payload_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_metadata_and_payload_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_metadata_and_payload_test.exe
+chttp2_fullstack_compression_request_response_with_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_payload_test: chttp2_fullstack_compression_request_response_with_payload_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_payload_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_payload_test.exe
+chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_payload_and_call_creds.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test: chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test.exe
+chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_trailing_metadata_and_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test: chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test.exe
+chttp2_fullstack_compression_request_with_compressed_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_compressed_payload_test: chttp2_fullstack_compression_request_with_compressed_payload_test.exe
+	echo Running chttp2_fullstack_compression_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_compressed_payload_test.exe
+chttp2_fullstack_compression_request_with_flags_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_flags_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_flags_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_flags.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_flags_test: chttp2_fullstack_compression_request_with_flags_test.exe
+	echo Running chttp2_fullstack_compression_request_with_flags_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_flags_test.exe
+chttp2_fullstack_compression_request_with_large_metadata_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_large_metadata_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_large_metadata_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_large_metadata.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_large_metadata_test: chttp2_fullstack_compression_request_with_large_metadata_test.exe
+	echo Running chttp2_fullstack_compression_request_with_large_metadata_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_large_metadata_test.exe
+chttp2_fullstack_compression_request_with_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_payload_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_payload_test: chttp2_fullstack_compression_request_with_payload_test.exe
+	echo Running chttp2_fullstack_compression_request_with_payload_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_payload_test.exe
+chttp2_fullstack_compression_server_finishes_request_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_server_finishes_request_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_server_finishes_request_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_server_finishes_request.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_server_finishes_request_test: chttp2_fullstack_compression_server_finishes_request_test.exe
+	echo Running chttp2_fullstack_compression_server_finishes_request_test
+	$(OUT_DIR)\chttp2_fullstack_compression_server_finishes_request_test.exe
+chttp2_fullstack_compression_simple_delayed_request_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_simple_delayed_request_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_simple_delayed_request_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_simple_delayed_request.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_simple_delayed_request_test: chttp2_fullstack_compression_simple_delayed_request_test.exe
+	echo Running chttp2_fullstack_compression_simple_delayed_request_test
+	$(OUT_DIR)\chttp2_fullstack_compression_simple_delayed_request_test.exe
+chttp2_fullstack_compression_simple_request_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_simple_request_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_simple_request_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_simple_request.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_simple_request_test: chttp2_fullstack_compression_simple_request_test.exe
+	echo Running chttp2_fullstack_compression_simple_request_test
+	$(OUT_DIR)\chttp2_fullstack_compression_simple_request_test.exe
+chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_simple_request_with_high_initial_sequence_number.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test: chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test.exe
+	echo Running chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test
+	$(OUT_DIR)\chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test.exe
 chttp2_simple_ssl_fullstack_bad_hostname_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_simple_ssl_fullstack_bad_hostname_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -1071,6 +1343,13 @@
 chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test: chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test.exe
+chttp2_simple_ssl_fullstack_request_with_compressed_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_simple_ssl_fullstack_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_simple_ssl_fullstack_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_simple_ssl_fullstack.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_simple_ssl_fullstack_request_with_compressed_payload_test: chttp2_simple_ssl_fullstack_request_with_compressed_payload_test.exe
+	echo Running chttp2_simple_ssl_fullstack_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_simple_ssl_fullstack_request_with_compressed_payload_test.exe
 chttp2_simple_ssl_fullstack_request_with_flags_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_simple_ssl_fullstack_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -1281,6 +1560,13 @@
 chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test: chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\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: build_libs $(OUT_DIR)
+	echo Building chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test: chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test.exe
+	echo Running chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test.exe
 chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -1491,6 +1777,13 @@
 chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test: chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test.exe
+chttp2_socket_pair_request_with_compressed_payload_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_socket_pair_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_socket_pair_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_socket_pair.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_socket_pair_request_with_compressed_payload_test: chttp2_socket_pair_request_with_compressed_payload_test.exe
+	echo Running chttp2_socket_pair_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_socket_pair_request_with_compressed_payload_test.exe
 chttp2_socket_pair_request_with_flags_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -1701,6 +1994,13 @@
 chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test: chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\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: build_libs $(OUT_DIR)
+	echo Building chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_socket_pair_one_byte_at_a_time.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test: chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test.exe
+	echo Running chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test
+	$(OUT_DIR)\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: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -1911,6 +2211,13 @@
 chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test: chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test.exe
 	echo Running chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test
 	$(OUT_DIR)\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: build_libs $(OUT_DIR)
+	echo Building chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test.exe" Debug\end2end_fixture_chttp2_socket_pair_with_grpc_trace.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\end2end_certs.lib Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test: chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test.exe
+	echo Running chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test
+	$(OUT_DIR)\chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test.exe
 chttp2_socket_pair_with_grpc_trace_request_with_flags_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_with_grpc_trace_request_with_flags_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -2114,6 +2421,13 @@
 chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test: chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
 	echo Running chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test
 	$(OUT_DIR)\chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
+chttp2_fullstack_request_with_compressed_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_request_with_compressed_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_request_with_compressed_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_request_with_compressed_payload_unsecure_test: chttp2_fullstack_request_with_compressed_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_request_with_compressed_payload_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_request_with_compressed_payload_unsecure_test.exe
 chttp2_fullstack_request_with_flags_unsecure_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_fullstack_request_with_flags_unsecure_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -2163,6 +2477,216 @@
 chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test: chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test.exe
 	echo Running chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test
 	$(OUT_DIR)\chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test.exe
+chttp2_fullstack_compression_bad_hostname_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_bad_hostname_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_bad_hostname_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_bad_hostname.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_bad_hostname_unsecure_test: chttp2_fullstack_compression_bad_hostname_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_bad_hostname_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_bad_hostname_unsecure_test.exe
+chttp2_fullstack_compression_cancel_after_accept_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_after_accept_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_after_accept.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_after_accept_unsecure_test: chttp2_fullstack_compression_cancel_after_accept_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_cancel_after_accept_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_unsecure_test.exe
+chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_after_accept_and_writes_closed.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test: chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test.exe
+chttp2_fullstack_compression_cancel_after_invoke_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_after_invoke_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_invoke_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_after_invoke.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_after_invoke_unsecure_test: chttp2_fullstack_compression_cancel_after_invoke_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_cancel_after_invoke_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_after_invoke_unsecure_test.exe
+chttp2_fullstack_compression_cancel_before_invoke_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_before_invoke_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_before_invoke_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_before_invoke.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_before_invoke_unsecure_test: chttp2_fullstack_compression_cancel_before_invoke_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_cancel_before_invoke_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_before_invoke_unsecure_test.exe
+chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_cancel_in_a_vacuum.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test: chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test.exe
+chttp2_fullstack_compression_census_simple_request_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_census_simple_request_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_census_simple_request_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_census_simple_request.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_census_simple_request_unsecure_test: chttp2_fullstack_compression_census_simple_request_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_census_simple_request_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_census_simple_request_unsecure_test.exe
+chttp2_fullstack_compression_disappearing_server_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_disappearing_server_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_disappearing_server_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_disappearing_server.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_disappearing_server_unsecure_test: chttp2_fullstack_compression_disappearing_server_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_disappearing_server_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_disappearing_server_unsecure_test.exe
+chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_early_server_shutdown_finishes_inflight_calls.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test: chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe
+chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_early_server_shutdown_finishes_tags.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test: chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test.exe
+chttp2_fullstack_compression_empty_batch_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_empty_batch_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_empty_batch_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_empty_batch.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_empty_batch_unsecure_test: chttp2_fullstack_compression_empty_batch_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_empty_batch_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_empty_batch_unsecure_test.exe
+chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_graceful_server_shutdown.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test: chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test.exe
+chttp2_fullstack_compression_invoke_large_request_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_invoke_large_request_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_invoke_large_request_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_invoke_large_request.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_invoke_large_request_unsecure_test: chttp2_fullstack_compression_invoke_large_request_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_invoke_large_request_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_invoke_large_request_unsecure_test.exe
+chttp2_fullstack_compression_max_concurrent_streams_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_max_concurrent_streams_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_max_concurrent_streams_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_max_concurrent_streams.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_max_concurrent_streams_unsecure_test: chttp2_fullstack_compression_max_concurrent_streams_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_max_concurrent_streams_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_max_concurrent_streams_unsecure_test.exe
+chttp2_fullstack_compression_max_message_length_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_max_message_length_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_max_message_length_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_max_message_length.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_max_message_length_unsecure_test: chttp2_fullstack_compression_max_message_length_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_max_message_length_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_max_message_length_unsecure_test.exe
+chttp2_fullstack_compression_no_op_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_no_op_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_no_op_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_no_op.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_no_op_unsecure_test: chttp2_fullstack_compression_no_op_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_no_op_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_no_op_unsecure_test.exe
+chttp2_fullstack_compression_ping_pong_streaming_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_ping_pong_streaming_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_ping_pong_streaming_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_ping_pong_streaming.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_ping_pong_streaming_unsecure_test: chttp2_fullstack_compression_ping_pong_streaming_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_ping_pong_streaming_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_ping_pong_streaming_unsecure_test.exe
+chttp2_fullstack_compression_registered_call_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_registered_call_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_registered_call_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_registered_call.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_registered_call_unsecure_test: chttp2_fullstack_compression_registered_call_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_registered_call_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_registered_call_unsecure_test.exe
+chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_binary_metadata_and_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test: chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test
+	$(OUT_DIR)\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: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_metadata_and_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test: chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test.exe
+chttp2_fullstack_compression_request_response_with_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_payload_unsecure_test: chttp2_fullstack_compression_request_response_with_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_payload_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_payload_unsecure_test.exe
+chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_response_with_trailing_metadata_and_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test: chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
+chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test: chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test.exe
+chttp2_fullstack_compression_request_with_flags_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_flags_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_flags_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_flags.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_flags_unsecure_test: chttp2_fullstack_compression_request_with_flags_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_with_flags_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_flags_unsecure_test.exe
+chttp2_fullstack_compression_request_with_large_metadata_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_large_metadata_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_large_metadata_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_large_metadata.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_large_metadata_unsecure_test: chttp2_fullstack_compression_request_with_large_metadata_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_with_large_metadata_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_large_metadata_unsecure_test.exe
+chttp2_fullstack_compression_request_with_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_request_with_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_request_with_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_request_with_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_request_with_payload_unsecure_test: chttp2_fullstack_compression_request_with_payload_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_request_with_payload_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_request_with_payload_unsecure_test.exe
+chttp2_fullstack_compression_server_finishes_request_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_server_finishes_request_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_server_finishes_request_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_server_finishes_request.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_server_finishes_request_unsecure_test: chttp2_fullstack_compression_server_finishes_request_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_server_finishes_request_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_server_finishes_request_unsecure_test.exe
+chttp2_fullstack_compression_simple_delayed_request_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_simple_delayed_request_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_simple_delayed_request_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_simple_delayed_request.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_simple_delayed_request_unsecure_test: chttp2_fullstack_compression_simple_delayed_request_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_simple_delayed_request_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_simple_delayed_request_unsecure_test.exe
+chttp2_fullstack_compression_simple_request_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_simple_request_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_simple_request_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_simple_request.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_simple_request_unsecure_test: chttp2_fullstack_compression_simple_request_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_simple_request_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_simple_request_unsecure_test.exe
+chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test.exe" Debug\end2end_fixture_chttp2_fullstack_compression.lib Debug\end2end_test_simple_request_with_high_initial_sequence_number.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test: chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test.exe
+	echo Running chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test
+	$(OUT_DIR)\chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test.exe
 chttp2_socket_pair_bad_hostname_unsecure_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_bad_hostname_unsecure_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -2317,6 +2841,13 @@
 chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test: chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
 	echo Running chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test
 	$(OUT_DIR)\chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
+chttp2_socket_pair_request_with_compressed_payload_unsecure_test.exe: build_libs $(OUT_DIR)
+	echo Building chttp2_socket_pair_request_with_compressed_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_socket_pair_request_with_compressed_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_socket_pair.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_socket_pair_request_with_compressed_payload_unsecure_test: chttp2_socket_pair_request_with_compressed_payload_unsecure_test.exe
+	echo Running chttp2_socket_pair_request_with_compressed_payload_unsecure_test
+	$(OUT_DIR)\chttp2_socket_pair_request_with_compressed_payload_unsecure_test.exe
 chttp2_socket_pair_request_with_flags_unsecure_test.exe: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_request_with_flags_unsecure_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -2520,6 +3051,13 @@
 chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test: chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
 	echo Running chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test
 	$(OUT_DIR)\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: build_libs $(OUT_DIR)
+	echo Building chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_socket_pair_one_byte_at_a_time.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test: chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test.exe
+	echo Running chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test
+	$(OUT_DIR)\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: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -2723,6 +3261,13 @@
 chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test: chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test.exe
 	echo Running chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test
 	$(OUT_DIR)\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: build_libs $(OUT_DIR)
+	echo Building chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test.exe" Debug\end2end_fixture_chttp2_socket_pair_with_grpc_trace.lib Debug\end2end_test_request_with_compressed_payload.lib Debug\grpc_test_util_unsecure.lib Debug\grpc_unsecure.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dummy.obj 
+chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test: chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test.exe
+	echo Running chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test
+	$(OUT_DIR)\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: build_libs $(OUT_DIR)
 	echo Building chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\vsprojects\dummy.c 
@@ -2806,6 +3351,10 @@
 	echo Building end2end_fixture_chttp2_fullstack
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\fixtures\chttp2_fullstack.c 
 	$(LIBTOOL) /OUT:"Debug\end2end_fixture_chttp2_fullstack.lib" $(OUT_DIR)\chttp2_fullstack.obj 
+Debug\end2end_fixture_chttp2_fullstack_compression.lib: $(OUT_DIR)
+	echo Building end2end_fixture_chttp2_fullstack_compression
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\fixtures\chttp2_fullstack_compression.c 
+	$(LIBTOOL) /OUT:"Debug\end2end_fixture_chttp2_fullstack_compression.lib" $(OUT_DIR)\chttp2_fullstack_compression.obj 
 Debug\end2end_fixture_chttp2_simple_ssl_fullstack.lib: $(OUT_DIR)
 	echo Building end2end_fixture_chttp2_simple_ssl_fullstack
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\fixtures\chttp2_simple_ssl_fullstack.c 
@@ -2918,6 +3467,10 @@
 	echo Building end2end_test_request_response_with_trailing_metadata_and_payload
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\tests\request_response_with_trailing_metadata_and_payload.c 
 	$(LIBTOOL) /OUT:"Debug\end2end_test_request_response_with_trailing_metadata_and_payload.lib" $(OUT_DIR)\request_response_with_trailing_metadata_and_payload.obj 
+Debug\end2end_test_request_with_compressed_payload.lib: $(OUT_DIR)
+	echo Building end2end_test_request_with_compressed_payload
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\tests\request_with_compressed_payload.c 
+	$(LIBTOOL) /OUT:"Debug\end2end_test_request_with_compressed_payload.lib" $(OUT_DIR)\request_with_compressed_payload.obj 
 Debug\end2end_test_request_with_flags.lib: $(OUT_DIR)
 	echo Building end2end_test_request_with_flags
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\end2end\tests\request_with_flags.c 
diff --git a/vsprojects/README.md b/vsprojects/README.md
index 14178da..dade9e5 100644
--- a/vsprojects/README.md
+++ b/vsprojects/README.md
@@ -12,7 +12,7 @@
 ```
 > REM Run from this directory.
 > REM No need to do this if you have NuGet visual studio extension.
-> nuget restore
+> nuget restore grpc.sln
 ```
 
 After that, you can build the solution using one of these options:
diff --git a/vsprojects/gpr/gpr.vcxproj b/vsprojects/gpr/gpr.vcxproj
index 3e6bb20..32a08a2 100644
--- a/vsprojects/gpr/gpr.vcxproj
+++ b/vsprojects/gpr/gpr.vcxproj
@@ -179,6 +179,7 @@
     <ClInclude Include="..\..\src\core\support\env.h" />
     <ClInclude Include="..\..\src\core\support\file.h" />
     <ClInclude Include="..\..\src\core\support\murmur_hash.h" />
+    <ClInclude Include="..\..\src\core\support\stack_lockfree.h" />
     <ClInclude Include="..\..\src\core\support\string.h" />
     <ClInclude Include="..\..\src\core\support\string_win32.h" />
     <ClInclude Include="..\..\src\core\support\thd_internal.h" />
@@ -230,6 +231,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\slice_buffer.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\stack_lockfree.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\string.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\string_posix.c">
diff --git a/vsprojects/gpr/gpr.vcxproj.filters b/vsprojects/gpr/gpr.vcxproj.filters
index a270902..ace549f 100644
--- a/vsprojects/gpr/gpr.vcxproj.filters
+++ b/vsprojects/gpr/gpr.vcxproj.filters
@@ -70,6 +70,9 @@
     <ClCompile Include="..\..\src\core\support\slice_buffer.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\stack_lockfree.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\string.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -209,6 +212,9 @@
     <ClInclude Include="..\..\src\core\support\murmur_hash.h">
       <Filter>src\core\support</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\support\stack_lockfree.h">
+      <Filter>src\core\support</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\support\string.h">
       <Filter>src\core\support</Filter>
     </ClInclude>
diff --git a/vsprojects/grpc++/grpc++.vcxproj b/vsprojects/grpc++/grpc++.vcxproj
index d233f9e..2d13bf0 100644
--- a/vsprojects/grpc++/grpc++.vcxproj
+++ b/vsprojects/grpc++/grpc++.vcxproj
@@ -148,21 +148,27 @@
   <ItemGroup>
     <ClInclude Include="..\..\include\grpc++\async_generic_service.h" />
     <ClInclude Include="..\..\include\grpc++\async_unary_call.h" />
+    <ClInclude Include="..\..\include\grpc++\auth_context.h" />
+    <ClInclude Include="..\..\include\grpc++\auth_property_iterator.h" />
     <ClInclude Include="..\..\include\grpc++\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc++\channel_arguments.h" />
     <ClInclude Include="..\..\include\grpc++\channel_interface.h" />
     <ClInclude Include="..\..\include\grpc++\client_context.h" />
     <ClInclude Include="..\..\include\grpc++\completion_queue.h" />
     <ClInclude Include="..\..\include\grpc++\config.h" />
+    <ClInclude Include="..\..\include\grpc++\config_protobuf.h" />
     <ClInclude Include="..\..\include\grpc++\create_channel.h" />
     <ClInclude Include="..\..\include\grpc++\credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h" />
     <ClInclude Include="..\..\include\grpc++\generic_stub.h" />
     <ClInclude Include="..\..\include\grpc++\impl\call.h" />
     <ClInclude Include="..\..\include\grpc++\impl\client_unary_call.h" />
     <ClInclude Include="..\..\include\grpc++\impl\grpc_library.h" />
     <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\proto_utils.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\serialization_traits.h" />
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h" />
     <ClInclude Include="..\..\include\grpc++\impl\sync.h" />
     <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h" />
@@ -183,14 +189,22 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\cpp\client\secure_credentials.h" />
+    <ClInclude Include="..\..\src\cpp\common\secure_auth_context.h" />
     <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="..\..\src\cpp\client\channel.h" />
-    <ClInclude Include="..\..\src\cpp\proto\proto_utils.h" />
-    <ClInclude Include="..\..\src\cpp\server\thread_pool.h" />
+    <ClInclude Include="..\..\src\cpp\common\create_auth_context.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\src\cpp\client\secure_channel_arguments.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\secure_credentials.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\auth_property_iterator.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\secure_auth_context.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\secure_create_auth_context.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\secure_server_credentials.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\channel.cc">
@@ -199,8 +213,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\client_context.cc">
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\client\client_unary_call.cc">
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\create_channel.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\credentials.cc">
@@ -223,6 +235,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\server.cc">
@@ -233,8 +247,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\server_credentials.cc">
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\slice.cc">
diff --git a/vsprojects/grpc++/grpc++.vcxproj.filters b/vsprojects/grpc++/grpc++.vcxproj.filters
index dd375c7..c5d8db5 100644
--- a/vsprojects/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/grpc++/grpc++.vcxproj.filters
@@ -1,9 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
+    <ClCompile Include="..\..\src\cpp\client\secure_channel_arguments.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\secure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\auth_property_iterator.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\secure_auth_context.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\secure_create_auth_context.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\secure_server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -16,9 +28,6 @@
     <ClCompile Include="..\..\src\cpp\client\client_context.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\client\client_unary_call.cc">
-      <Filter>src\cpp\client</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\create_channel.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
@@ -52,6 +61,9 @@
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -67,9 +79,6 @@
     <ClCompile Include="..\..\src\cpp\server\server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
-      <Filter>src\cpp\server</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
@@ -90,6 +99,12 @@
     <ClInclude Include="..\..\include\grpc++\async_unary_call.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\auth_context.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\auth_property_iterator.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\byte_buffer.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -108,12 +123,18 @@
     <ClInclude Include="..\..\include\grpc++\config.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\config_protobuf.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\create_channel.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
     <ClInclude Include="..\..\include\grpc++\credentials.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\generic_stub.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -129,12 +150,18 @@
     <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\proto_utils.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\serialization_traits.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -191,17 +218,17 @@
     <ClInclude Include="..\..\src\cpp\client\secure_credentials.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\cpp\common\secure_auth_context.h">
+      <Filter>src\cpp\common</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\cpp\client\channel.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\cpp\proto\proto_utils.h">
-      <Filter>src\cpp\proto</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\cpp\server\thread_pool.h">
-      <Filter>src\cpp\server</Filter>
+    <ClInclude Include="..\..\src\cpp\common\create_auth_context.h">
+      <Filter>src\cpp\common</Filter>
     </ClInclude>
   </ItemGroup>
 
diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj
index 9b2ef91..f03715b 100644
--- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -148,21 +148,27 @@
   <ItemGroup>
     <ClInclude Include="..\..\include\grpc++\async_generic_service.h" />
     <ClInclude Include="..\..\include\grpc++\async_unary_call.h" />
+    <ClInclude Include="..\..\include\grpc++\auth_context.h" />
+    <ClInclude Include="..\..\include\grpc++\auth_property_iterator.h" />
     <ClInclude Include="..\..\include\grpc++\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc++\channel_arguments.h" />
     <ClInclude Include="..\..\include\grpc++\channel_interface.h" />
     <ClInclude Include="..\..\include\grpc++\client_context.h" />
     <ClInclude Include="..\..\include\grpc++\completion_queue.h" />
     <ClInclude Include="..\..\include\grpc++\config.h" />
+    <ClInclude Include="..\..\include\grpc++\config_protobuf.h" />
     <ClInclude Include="..\..\include\grpc++\create_channel.h" />
     <ClInclude Include="..\..\include\grpc++\credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h" />
     <ClInclude Include="..\..\include\grpc++\generic_stub.h" />
     <ClInclude Include="..\..\include\grpc++\impl\call.h" />
     <ClInclude Include="..\..\include\grpc++\impl\client_unary_call.h" />
     <ClInclude Include="..\..\include\grpc++\impl\grpc_library.h" />
     <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\proto_utils.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\serialization_traits.h" />
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h" />
     <ClInclude Include="..\..\include\grpc++\impl\sync.h" />
     <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h" />
@@ -183,18 +189,17 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\cpp\client\channel.h" />
-    <ClInclude Include="..\..\src\cpp\proto\proto_utils.h" />
-    <ClInclude Include="..\..\src\cpp\server\thread_pool.h" />
+    <ClInclude Include="..\..\src\cpp\common\create_auth_context.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\src\cpp\common\insecure_create_auth_context.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\channel.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\channel_arguments.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\client_context.cc">
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\client\client_unary_call.cc">
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\create_channel.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\credentials.cc">
@@ -217,6 +222,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\server.cc">
@@ -227,8 +234,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\server_credentials.cc">
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\slice.cc">
diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index d616e33..8f7f3bc 100644
--- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
+    <ClCompile Include="..\..\src\cpp\common\insecure_create_auth_context.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\channel.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
@@ -10,9 +13,6 @@
     <ClCompile Include="..\..\src\cpp\client\client_context.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\client\client_unary_call.cc">
-      <Filter>src\cpp\client</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\create_channel.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
@@ -46,6 +46,9 @@
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -61,9 +64,6 @@
     <ClCompile Include="..\..\src\cpp\server\server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
-      <Filter>src\cpp\server</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
@@ -84,6 +84,12 @@
     <ClInclude Include="..\..\include\grpc++\async_unary_call.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\auth_context.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\auth_property_iterator.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\byte_buffer.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -102,12 +108,18 @@
     <ClInclude Include="..\..\include\grpc++\config.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\config_protobuf.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\create_channel.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
     <ClInclude Include="..\..\include\grpc++\credentials.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\generic_stub.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -123,12 +135,18 @@
     <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\proto_utils.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\serialization_traits.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -185,11 +203,8 @@
     <ClInclude Include="..\..\src\cpp\client\channel.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\cpp\proto\proto_utils.h">
-      <Filter>src\cpp\proto</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\cpp\server\thread_pool.h">
-      <Filter>src\cpp\server</Filter>
+    <ClInclude Include="..\..\src\cpp\common\create_auth_context.h">
+      <Filter>src\cpp\common</Filter>
     </ClInclude>
   </ItemGroup>
 
diff --git a/vsprojects/grpc/grpc.vcxproj b/vsprojects/grpc/grpc.vcxproj
index 61f1f71..6f929a7 100644
--- a/vsprojects/grpc/grpc.vcxproj
+++ b/vsprojects/grpc/grpc.vcxproj
@@ -164,6 +164,7 @@
     <ClInclude Include="..\..\src\core\security\base64.h" />
     <ClInclude Include="..\..\src\core\security\credentials.h" />
     <ClInclude Include="..\..\src\core\security\json_token.h" />
+    <ClInclude Include="..\..\src\core\security\jwt_verifier.h" />
     <ClInclude Include="..\..\src\core\security\secure_endpoint.h" />
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
     <ClInclude Include="..\..\src\core\security\security_connector.h" />
@@ -176,14 +177,25 @@
     <ClInclude Include="..\..\src\core\channel\census_filter.h" />
     <ClInclude Include="..\..\src\core\channel\channel_args.h" />
     <ClInclude Include="..\..\src\core\channel\channel_stack.h" />
-    <ClInclude Include="..\..\src\core\channel\child_channel.h" />
     <ClInclude Include="..\..\src\core\channel\client_channel.h" />
-    <ClInclude Include="..\..\src\core\channel\client_setup.h" />
+    <ClInclude Include="..\..\src\core\channel\compress_filter.h" />
     <ClInclude Include="..\..\src\core\channel\connected_channel.h" />
     <ClInclude Include="..\..\src\core\channel\context.h" />
     <ClInclude Include="..\..\src\core\channel\http_client_filter.h" />
     <ClInclude Include="..\..\src\core\channel\http_server_filter.h" />
     <ClInclude Include="..\..\src\core\channel\noop_filter.h" />
+    <ClInclude Include="..\..\src\core\client_config\client_config.h" />
+    <ClInclude Include="..\..\src\core\client_config\connector.h" />
+    <ClInclude Include="..\..\src\core\client_config\lb_policies\pick_first.h" />
+    <ClInclude Include="..\..\src\core\client_config\lb_policy.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolver.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolver_factory.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolver_registry.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolvers\dns_resolver.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.h" />
+    <ClInclude Include="..\..\src\core\client_config\subchannel.h" />
+    <ClInclude Include="..\..\src\core\client_config\subchannel_factory.h" />
+    <ClInclude Include="..\..\src\core\client_config\uri_parser.h" />
     <ClInclude Include="..\..\src\core\compression\message_compress.h" />
     <ClInclude Include="..\..\src\core\debug\trace.h" />
     <ClInclude Include="..\..\src\core\iomgr\alarm.h" />
@@ -197,10 +209,11 @@
     <ClInclude Include="..\..\src\core\iomgr\iomgr_internal.h" />
     <ClInclude Include="..\..\src\core\iomgr\iomgr_posix.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset.h" />
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset_kick_posix.h" />
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset_posix.h" />
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set.h" />
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_posix.h" />
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\resolve_address.h" />
     <ClInclude Include="..\..\src\core\iomgr\sockaddr.h" />
@@ -225,7 +238,6 @@
     <ClInclude Include="..\..\src\core\surface\byte_buffer_queue.h" />
     <ClInclude Include="..\..\src\core\surface\call.h" />
     <ClInclude Include="..\..\src\core\surface\channel.h" />
-    <ClInclude Include="..\..\src\core\surface\client.h" />
     <ClInclude Include="..\..\src\core\surface\completion_queue.h" />
     <ClInclude Include="..\..\src\core\surface\event_string.h" />
     <ClInclude Include="..\..\src\core\surface\init.h" />
@@ -244,12 +256,15 @@
     <ClInclude Include="..\..\src\core\transport\chttp2\hpack_table.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\http2_errors.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\huffsyms.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\incoming_metadata.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\internal.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\status_conversion.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\stream_encoder.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\stream_map.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\timeout_encoding.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\varint.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2_transport.h" />
+    <ClInclude Include="..\..\src\core\transport\connectivity_state.h" />
     <ClInclude Include="..\..\src\core\transport\metadata.h" />
     <ClInclude Include="..\..\src\core\transport\stream_op.h" />
     <ClInclude Include="..\..\src\core\transport\transport.h" />
@@ -281,6 +296,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\json_token.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\security\jwt_verifier.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\security\secure_endpoint.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
@@ -309,11 +326,9 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\channel_stack.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\child_channel.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\client_setup.c">
+    <ClCompile Include="..\..\src\core\channel\compress_filter.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\connected_channel.c">
     </ClCompile>
@@ -323,6 +338,30 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\noop_filter.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\client_config.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\connector.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policies\pick_first.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policy.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_factory.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_registry.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\dns_resolver.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel_factory.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\uri_parser.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\compression\algorithm.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\compression\message_compress.c">
@@ -349,7 +388,7 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\iomgr_windows.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
+    <ClCompile Include="..\..\src\core\iomgr\pollset_kick_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
     </ClCompile>
@@ -357,6 +396,10 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_posix.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
@@ -423,8 +466,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\client.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\completion_queue.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\event_string.c">
@@ -443,6 +484,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\bin_encoder.c">
@@ -465,18 +508,28 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\huffsyms.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\incoming_metadata.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\parsing.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\status_conversion.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_encoder.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\stream_lists.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_map.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\timeout_encoding.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\varint.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\writing.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2_transport.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\connectivity_state.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\metadata.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\stream_op.c">
diff --git a/vsprojects/grpc/grpc.vcxproj.filters b/vsprojects/grpc/grpc.vcxproj.filters
index 4566296..0c38822 100644
--- a/vsprojects/grpc/grpc.vcxproj.filters
+++ b/vsprojects/grpc/grpc.vcxproj.filters
@@ -37,6 +37,9 @@
     <ClCompile Include="..\..\src\core\security\json_token.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\security\jwt_verifier.c">
+      <Filter>src\core\security</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\security\secure_endpoint.c">
       <Filter>src\core\security</Filter>
     </ClCompile>
@@ -79,13 +82,10 @@
     <ClCompile Include="..\..\src\core\channel\channel_stack.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\child_channel.c">
-      <Filter>src\core\channel</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\channel\client_channel.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\client_setup.c">
+    <ClCompile Include="..\..\src\core\channel\compress_filter.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\connected_channel.c">
@@ -100,6 +100,42 @@
     <ClCompile Include="..\..\src\core\channel\noop_filter.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\client_config.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\connector.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policies\pick_first.c">
+      <Filter>src\core\client_config\lb_policies</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policy.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_factory.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_registry.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\dns_resolver.c">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.c">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel_factory.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\uri_parser.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\compression\algorithm.c">
       <Filter>src\core\compression</Filter>
     </ClCompile>
@@ -139,7 +175,7 @@
     <ClCompile Include="..\..\src\core\iomgr\iomgr_windows.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
+    <ClCompile Include="..\..\src\core\iomgr\pollset_kick_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
@@ -151,6 +187,12 @@
     <ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_posix.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_windows.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
@@ -250,9 +292,6 @@
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\client.c">
-      <Filter>src\core\surface</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\completion_queue.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -280,6 +319,9 @@
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
@@ -313,12 +355,21 @@
     <ClCompile Include="..\..\src\core\transport\chttp2\huffsyms.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\incoming_metadata.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\parsing.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\status_conversion.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_encoder.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\stream_lists.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_map.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
@@ -328,9 +379,15 @@
     <ClCompile Include="..\..\src\core\transport\chttp2\varint.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\writing.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2_transport.c">
       <Filter>src\core\transport</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\connectivity_state.c">
+      <Filter>src\core\transport</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\metadata.c">
       <Filter>src\core\transport</Filter>
     </ClCompile>
@@ -398,6 +455,9 @@
     <ClInclude Include="..\..\src\core\security\json_token.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\security\jwt_verifier.h">
+      <Filter>src\core\security</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\security\secure_endpoint.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
@@ -434,13 +494,10 @@
     <ClInclude Include="..\..\src\core\channel\channel_stack.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\channel\child_channel.h">
-      <Filter>src\core\channel</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\channel\client_channel.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\channel\client_setup.h">
+    <ClInclude Include="..\..\src\core\channel\compress_filter.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\channel\connected_channel.h">
@@ -458,6 +515,42 @@
     <ClInclude Include="..\..\src\core\channel\noop_filter.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\client_config.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\connector.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\lb_policies\pick_first.h">
+      <Filter>src\core\client_config\lb_policies</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\lb_policy.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolver.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolver_factory.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolver_registry.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolvers\dns_resolver.h">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.h">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\subchannel.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\subchannel_factory.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\uri_parser.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\compression\message_compress.h">
       <Filter>src\core\compression</Filter>
     </ClInclude>
@@ -497,16 +590,19 @@
     <ClInclude Include="..\..\src\core\iomgr\pollset.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick.h">
-      <Filter>src\core\iomgr</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\iomgr\pollset_kick_posix.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick_windows.h">
+    <ClInclude Include="..\..\src\core\iomgr\pollset_posix.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\iomgr\pollset_posix.h">
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set.h">
+      <Filter>src\core\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_posix.h">
+      <Filter>src\core\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_windows.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\iomgr\pollset_windows.h">
@@ -581,9 +677,6 @@
     <ClInclude Include="..\..\src\core\surface\channel.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\surface\client.h">
-      <Filter>src\core\surface</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\surface\completion_queue.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
@@ -638,6 +731,12 @@
     <ClInclude Include="..\..\src\core\transport\chttp2\huffsyms.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\incoming_metadata.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\internal.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\chttp2\status_conversion.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
@@ -656,6 +755,9 @@
     <ClInclude Include="..\..\src\core\transport\chttp2_transport.h">
       <Filter>src\core\transport</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\connectivity_state.h">
+      <Filter>src\core\transport</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\metadata.h">
       <Filter>src\core\transport</Filter>
     </ClInclude>
@@ -692,6 +794,15 @@
     <Filter Include="src\core\channel">
       <UniqueIdentifier>{d897b6c3-c555-234e-a589-b4f008063615}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\client_config">
+      <UniqueIdentifier>{e71e6928-b1e3-0616-0961-1505370458ab}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\client_config\lb_policies">
+      <UniqueIdentifier>{a3eca4d5-f760-61a6-7251-556b828c8b44}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\client_config\resolvers">
+      <UniqueIdentifier>{6d97b8d9-2c15-927a-892a-709d073c02ab}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\compression">
       <UniqueIdentifier>{263cb913-dfe6-42a4-096b-cac231f76305}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/grpc_plugin_support/grpc_plugin_support.vcxproj b/vsprojects/grpc_plugin_support/grpc_plugin_support.vcxproj
index c0188e5..4f0e4a6 100644
--- a/vsprojects/grpc_plugin_support/grpc_plugin_support.vcxproj
+++ b/vsprojects/grpc_plugin_support/grpc_plugin_support.vcxproj
@@ -146,6 +146,8 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\include\grpc++\config.h" />
+    <ClInclude Include="..\..\include\grpc++\config_protobuf.h" />
     <ClInclude Include="..\..\src\compiler\config.h" />
     <ClInclude Include="..\..\src\compiler\cpp_generator.h" />
     <ClInclude Include="..\..\src\compiler\cpp_generator_helpers.h" />
diff --git a/vsprojects/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/grpc_test_util/grpc_test_util.vcxproj
index e5288f4..3f16c22 100644
--- a/vsprojects/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/grpc_test_util/grpc_test_util.vcxproj
@@ -146,6 +146,16 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\test\core\end2end\data\ssl_test_data.h" />
+    <ClInclude Include="..\..\test\core\end2end\cq_verifier.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\data\server1_cert.c">
     </ClCompile>
     <ClCompile Include="..\..\test\core\end2end\data\server1_key.c">
@@ -156,6 +166,8 @@
     </ClCompile>
     <ClCompile Include="..\..\test\core\iomgr\endpoint_tests.c">
     </ClCompile>
+    <ClCompile Include="..\..\test\core\security\oauth2_utils.c">
+    </ClCompile>
     <ClCompile Include="..\..\test\core\util\grpc_profiler.c">
     </ClCompile>
     <ClCompile Include="..\..\test\core\util\parse_hexstring.c">
diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
index 79aa9ca..753f342 100644
--- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
@@ -158,14 +158,25 @@
     <ClInclude Include="..\..\src\core\channel\census_filter.h" />
     <ClInclude Include="..\..\src\core\channel\channel_args.h" />
     <ClInclude Include="..\..\src\core\channel\channel_stack.h" />
-    <ClInclude Include="..\..\src\core\channel\child_channel.h" />
     <ClInclude Include="..\..\src\core\channel\client_channel.h" />
-    <ClInclude Include="..\..\src\core\channel\client_setup.h" />
+    <ClInclude Include="..\..\src\core\channel\compress_filter.h" />
     <ClInclude Include="..\..\src\core\channel\connected_channel.h" />
     <ClInclude Include="..\..\src\core\channel\context.h" />
     <ClInclude Include="..\..\src\core\channel\http_client_filter.h" />
     <ClInclude Include="..\..\src\core\channel\http_server_filter.h" />
     <ClInclude Include="..\..\src\core\channel\noop_filter.h" />
+    <ClInclude Include="..\..\src\core\client_config\client_config.h" />
+    <ClInclude Include="..\..\src\core\client_config\connector.h" />
+    <ClInclude Include="..\..\src\core\client_config\lb_policies\pick_first.h" />
+    <ClInclude Include="..\..\src\core\client_config\lb_policy.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolver.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolver_factory.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolver_registry.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolvers\dns_resolver.h" />
+    <ClInclude Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.h" />
+    <ClInclude Include="..\..\src\core\client_config\subchannel.h" />
+    <ClInclude Include="..\..\src\core\client_config\subchannel_factory.h" />
+    <ClInclude Include="..\..\src\core\client_config\uri_parser.h" />
     <ClInclude Include="..\..\src\core\compression\message_compress.h" />
     <ClInclude Include="..\..\src\core\debug\trace.h" />
     <ClInclude Include="..\..\src\core\iomgr\alarm.h" />
@@ -179,10 +190,11 @@
     <ClInclude Include="..\..\src\core\iomgr\iomgr_internal.h" />
     <ClInclude Include="..\..\src\core\iomgr\iomgr_posix.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset.h" />
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset_kick_posix.h" />
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset_posix.h" />
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set.h" />
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_posix.h" />
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\pollset_windows.h" />
     <ClInclude Include="..\..\src\core\iomgr\resolve_address.h" />
     <ClInclude Include="..\..\src\core\iomgr\sockaddr.h" />
@@ -207,7 +219,6 @@
     <ClInclude Include="..\..\src\core\surface\byte_buffer_queue.h" />
     <ClInclude Include="..\..\src\core\surface\call.h" />
     <ClInclude Include="..\..\src\core\surface\channel.h" />
-    <ClInclude Include="..\..\src\core\surface\client.h" />
     <ClInclude Include="..\..\src\core\surface\completion_queue.h" />
     <ClInclude Include="..\..\src\core\surface\event_string.h" />
     <ClInclude Include="..\..\src\core\surface\init.h" />
@@ -226,12 +237,15 @@
     <ClInclude Include="..\..\src\core\transport\chttp2\hpack_table.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\http2_errors.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\huffsyms.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\incoming_metadata.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\internal.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\status_conversion.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\stream_encoder.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\stream_map.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\timeout_encoding.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\varint.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2_transport.h" />
+    <ClInclude Include="..\..\src\core\transport\connectivity_state.h" />
     <ClInclude Include="..\..\src\core\transport\metadata.h" />
     <ClInclude Include="..\..\src\core\transport\stream_op.h" />
     <ClInclude Include="..\..\src\core\transport\transport.h" />
@@ -247,11 +261,9 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\channel_stack.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\child_channel.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\client_setup.c">
+    <ClCompile Include="..\..\src\core\channel\compress_filter.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\connected_channel.c">
     </ClCompile>
@@ -261,6 +273,30 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\noop_filter.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\client_config.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\connector.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policies\pick_first.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policy.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_factory.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_registry.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\dns_resolver.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel_factory.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\uri_parser.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\compression\algorithm.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\compression\message_compress.c">
@@ -287,7 +323,7 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\iomgr_windows.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
+    <ClCompile Include="..\..\src\core\iomgr\pollset_kick_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
     </ClCompile>
@@ -295,6 +331,10 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_posix.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
@@ -361,8 +401,6 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
     </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\client.c">
-    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\completion_queue.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\event_string.c">
@@ -381,6 +419,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\bin_encoder.c">
@@ -403,18 +443,28 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\huffsyms.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\incoming_metadata.c">
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\parsing.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\status_conversion.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_encoder.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\stream_lists.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_map.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\timeout_encoding.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\varint.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\writing.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2_transport.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\connectivity_state.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\metadata.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\stream_op.c">
diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
index a1939d1..1b312cc 100644
--- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -13,13 +13,10 @@
     <ClCompile Include="..\..\src\core\channel\channel_stack.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\child_channel.c">
-      <Filter>src\core\channel</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\channel\client_channel.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\channel\client_setup.c">
+    <ClCompile Include="..\..\src\core\channel\compress_filter.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\connected_channel.c">
@@ -34,6 +31,42 @@
     <ClCompile Include="..\..\src\core\channel\noop_filter.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\client_config.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\connector.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policies\pick_first.c">
+      <Filter>src\core\client_config\lb_policies</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\lb_policy.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_factory.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolver_registry.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\dns_resolver.c">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.c">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\subchannel_factory.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\client_config\uri_parser.c">
+      <Filter>src\core\client_config</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\compression\algorithm.c">
       <Filter>src\core\compression</Filter>
     </ClCompile>
@@ -73,7 +106,7 @@
     <ClCompile Include="..\..\src\core\iomgr\iomgr_windows.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
+    <ClCompile Include="..\..\src\core\iomgr\pollset_kick_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
@@ -85,6 +118,12 @@
     <ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_posix.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\pollset_set_windows.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
@@ -184,9 +223,6 @@
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\client.c">
-      <Filter>src\core\surface</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\completion_queue.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -214,6 +250,9 @@
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
@@ -247,12 +286,21 @@
     <ClCompile Include="..\..\src\core\transport\chttp2\huffsyms.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\incoming_metadata.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\parsing.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\status_conversion.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_encoder.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\stream_lists.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\stream_map.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
@@ -262,9 +310,15 @@
     <ClCompile Include="..\..\src\core\transport\chttp2\varint.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\chttp2\writing.c">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2_transport.c">
       <Filter>src\core\transport</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\transport\connectivity_state.c">
+      <Filter>src\core\transport</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\metadata.c">
       <Filter>src\core\transport</Filter>
     </ClCompile>
@@ -317,13 +371,10 @@
     <ClInclude Include="..\..\src\core\channel\channel_stack.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\channel\child_channel.h">
-      <Filter>src\core\channel</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\channel\client_channel.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\channel\client_setup.h">
+    <ClInclude Include="..\..\src\core\channel\compress_filter.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\channel\connected_channel.h">
@@ -341,6 +392,42 @@
     <ClInclude Include="..\..\src\core\channel\noop_filter.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\client_config.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\connector.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\lb_policies\pick_first.h">
+      <Filter>src\core\client_config\lb_policies</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\lb_policy.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolver.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolver_factory.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolver_registry.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolvers\dns_resolver.h">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\resolvers\unix_resolver_posix.h">
+      <Filter>src\core\client_config\resolvers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\subchannel.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\subchannel_factory.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\client_config\uri_parser.h">
+      <Filter>src\core\client_config</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\compression\message_compress.h">
       <Filter>src\core\compression</Filter>
     </ClInclude>
@@ -380,16 +467,19 @@
     <ClInclude Include="..\..\src\core\iomgr\pollset.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick.h">
-      <Filter>src\core\iomgr</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\iomgr\pollset_kick_posix.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\iomgr\pollset_kick_windows.h">
+    <ClInclude Include="..\..\src\core\iomgr\pollset_posix.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\iomgr\pollset_posix.h">
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set.h">
+      <Filter>src\core\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_posix.h">
+      <Filter>src\core\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\iomgr\pollset_set_windows.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
     <ClInclude Include="..\..\src\core\iomgr\pollset_windows.h">
@@ -464,9 +554,6 @@
     <ClInclude Include="..\..\src\core\surface\channel.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\core\surface\client.h">
-      <Filter>src\core\surface</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\surface\completion_queue.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
@@ -521,6 +608,12 @@
     <ClInclude Include="..\..\src\core\transport\chttp2\huffsyms.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\incoming_metadata.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\internal.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\chttp2\status_conversion.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
@@ -539,6 +632,9 @@
     <ClInclude Include="..\..\src\core\transport\chttp2_transport.h">
       <Filter>src\core\transport</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\connectivity_state.h">
+      <Filter>src\core\transport</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\metadata.h">
       <Filter>src\core\transport</Filter>
     </ClInclude>
@@ -575,6 +671,15 @@
     <Filter Include="src\core\channel">
       <UniqueIdentifier>{cc102c4b-66ff-cf4c-2288-d76327e1a183}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\client_config">
+      <UniqueIdentifier>{02bd7340-02ee-4337-ffa5-0b6ecc7cf60c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\client_config\lb_policies">
+      <UniqueIdentifier>{308af086-46c7-fa66-9021-19b1c3d4a6bd}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\client_config\resolvers">
+      <UniqueIdentifier>{dd617c24-6f07-fdff-80d5-c8610d6f815e}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\compression">
       <UniqueIdentifier>{2e3aca1d-223d-10a1-b282-7f9fc68ee6f5}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec b/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec
index 211d747..d2ac440 100644
--- a/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec
+++ b/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec
@@ -2,14 +2,14 @@
 <package>
   <metadata>
     <id>grpc.native.csharp_ext</id>
-    <version>0.9.1</version>
+    <version>0.10.0</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>http://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
     <description>Native extension needed by gRPC C# library. This is not the package you are looking for, it is only meant to be used as a dependency.</description>
-    <releaseNotes>Release of gRPC C core 0.9.1 libraries.</releaseNotes>
+    <releaseNotes>Release of gRPC C core 0.10.0 libraries.</releaseNotes>
     <copyright>Copyright 2015</copyright>
     <title>gRPC C# Native Extension</title>
     <summary>Native library required by gRPC C#</summary>